diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 1325b60aa..000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - root: true, - parser: "@typescript-eslint/parser", - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - plugins: ["@typescript-eslint"], - parserOptions: { - ecmaVersion: "latest", // For target ESNext - sourceType: "module", // Allows the use of imports - }, - env: { - node: true, - mocha: true, - es6: true, - }, - rules: { - "max-len": ["error", 1000], - }, -}; diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..aafe063c9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,17 @@ +# Ignore dist builds +packages/*/dist +packages/*/build + +# Ignore schemas +packages/common/validation/schemas + +# Ignore node_modules +node_modules +packages/*/node_modules + +# Ignore image assets +*.png + +# Ignore test assets +*.tar.xz +*.sh \ No newline at end of file diff --git a/packages/admin-ui/.prettierrc b/.prettierrc similarity index 75% rename from packages/admin-ui/.prettierrc rename to .prettierrc index 307e1bf0b..8c5ed36f5 100644 --- a/packages/admin-ui/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ { - "printWidth": 80, + "printWidth": 120, "tabWidth": 2, "useTabs": false, "semi": true, @@ -9,5 +9,6 @@ "trailingComma": "none", "bracketSpacing": true, "jsxBracketSameLine": false, - "arrowParens": "avoid" + "arrowParens": "always", + "endOfLine": "auto" } diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..e2abd4029 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,49 @@ +import { FlatCompat } from "@eslint/eslintrc"; +import { parse } from "@typescript-eslint/parser"; +import path from "path"; +import { fileURLToPath } from "url"; +import js from "@eslint/js"; + +// mimic CommonJS variables -- not needed if using CommonJS +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, + resolvePluginsRelativeTo: __dirname, // optional + recommendedConfig: js.configs.recommended, // optional unless using "eslint:recommended" + allConfig: js.configs.all // optional unless using "eslint:all" +}); + +export default [ + { + // Basic settings + languageOptions: { + parser: parse, + parserOptions: { + project: "./tsconfig.json", // Adjust path if necessary + tsconfigRootDir: __dirname, + sourceType: "module" + } + }, + ignores: [ + "packages/common/validation/schemas", + "node_modules", + "packages/*/dist", + "packages/*/node_modules", + "packages/*/build" + ] + }, + + // Optionally, add compatibility with old configs + ...compat.config({ + plugins: ["@typescript-eslint", "prettier"], + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], + rules: { + "prettier/prettier": "error", + "no-unused-expressions": "off", // Disable standard no-unused-expressions rule + "@typescript-eslint/no-unused-expressions": "off", // Disable TypeScript-specific rule + "@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }] + } + }) +]; diff --git a/package.json b/package.json index 8a2143bec..dbd8cf884 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@dappnode/dappnode", + "name": "root", "type": "module", "version": "1.0.0", "private": true, @@ -16,26 +16,35 @@ "test": "yarn workspaces foreach --all -pt run test", "test:int": "yarn workspaces foreach --all -pt run test:int", "dev": "yarn workspaces foreach --all -pi -j unlimited run dev", - "lint": "yarn workspaces foreach --all -pt run lint", + "lint": "eslint 'packages/**/src/**/*.{js,ts,tsx}' 'packages/**/test/**/*.{js,ts,tsx}' --ignore-pattern 'packages/common/src/validation/schemas/**/*.{js,ts,tsx}'", + "lint:fix": "eslint 'packages/**/src/**/*.{js,ts,tsx}' 'packages/**/test/**/*.{js,ts,tsx}' --fix --ignore-pattern 'packages/common/src/validation/schemas/**/*.{js,ts,tsx}'", + "format": "prettier --write 'packages/**/src/**/*.{js,ts,tsx,json,md}' 'packages/**/test/**/*.{js,ts,tsx,json,md}'", "mock-standalone:build": "yarn workspace @dappnode/admin-ui run mock-standalone:build", "mock-standalone": "yarn workspace @dappnode/admin-ui run mock-standalone", "generate": "yarn workspace @dappnode/common run generate" }, "devDependencies": { + "@eslint/eslintrc": "^3.1.0", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", "@types/node": "^22.2.0", - "@typescript-eslint/eslint-plugin": "^5.61.0", - "@typescript-eslint/parser": "^5.61.0", + "@typescript-eslint/eslint-plugin": "^8.3.0", + "@typescript-eslint/parser": "^8.3.0", "chai": "^4.3.10", "depcheck": "^1.4.7", - "eslint": "^8.44.0", + "eslint": "^9.9.1", + "eslint-config-prettier": "^9.1.0", "eslint-config-react-app": "^7.0.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-promise": "^7.1.0", "mocha": "^10.2.0", "nodemon": "^3.0.2", + "prettier": "^3.3.3", "rimraf": "^3.0.2", "tsx": "^4.17.0", "typescript": "^5.5.4" }, - "packageManager": "yarn@4.4.0" + "packageManager": "yarn@4.4.1" } diff --git a/packages/admin-ui/.eslintignore b/packages/admin-ui/.eslintignore deleted file mode 100644 index b6033a923..000000000 --- a/packages/admin-ui/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -*.min.js -*.config.js -environment*.js -socket.io.js -build -node_modules -abi.js -coverage \ No newline at end of file diff --git a/packages/admin-ui/.eslintrc.cjs b/packages/admin-ui/.eslintrc.cjs deleted file mode 100644 index 7f9ad7aa2..000000000 --- a/packages/admin-ui/.eslintrc.cjs +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: ["react-app"], - rules: { - "no-console": ["warn", { allow: ["warn", "error"] }] - } -}; diff --git a/packages/admin-ui/.prettierignore b/packages/admin-ui/.prettierignore deleted file mode 100644 index 57824b968..000000000 --- a/packages/admin-ui/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -# Ignore image assets -*.png -*.gif \ No newline at end of file diff --git a/packages/admin-ui/package.json b/packages/admin-ui/package.json index 6078810b4..6c741c8c7 100644 --- a/packages/admin-ui/package.json +++ b/packages/admin-ui/package.json @@ -7,8 +7,6 @@ "start": "VITE_APP_API_TEST=true vite", "build": "tsc -b && vite build", "analyze": "npx source-map-explorer build/static/js/main.*", - "lint": "eslint --ext ts,tsx,js,jsx --fix src", - "prettier": "prettier --write 'src/**/*.*'", "mock": "VITE_APP_API_URL=http://localhost:5000 yarn start", "server-mock": "PORT=5000 nodemon server-mock/index.ts", "server-mock:check-types": "tsc --noEmit --project tsconfig.server-mock.json", diff --git a/packages/admin-ui/src/App.tsx b/packages/admin-ui/src/App.tsx index 647329dcf..74582923c 100644 --- a/packages/admin-ui/src/App.tsx +++ b/packages/admin-ui/src/App.tsx @@ -37,6 +37,7 @@ const useLocalStorage = ( // Assert that either the item or initialValue is of type T return (item as T) || initialValue; } catch (error) { + console.error(error); return initialValue; } }); @@ -55,12 +56,14 @@ function MainApp({ username }: { username: string }) { const [screenWidth, setScreenWidth] = useState(window.innerWidth); const [theme, setTheme] = useLocalStorage("theme", "light"); - const [stakersModuleStatus, setStakersModuleStatus] = useLocalStorage< - UiModuleStatus - >("stakersModuleStatus", "enabled"); - const [rollupsModuleStatus, setRollupsModuleStatus] = useLocalStorage< - UiModuleStatus - >("rollupsModuleStatus", "disabled"); + const [stakersModuleStatus, setStakersModuleStatus] = useLocalStorage( + "stakersModuleStatus", + "enabled" + ); + const [rollupsModuleStatus, setRollupsModuleStatus] = useLocalStorage( + "rollupsModuleStatus", + "disabled" + ); useEffect(() => { const handleResize = () => setScreenWidth(window.innerWidth); @@ -78,16 +81,11 @@ function MainApp({ username }: { username: string }) { theme, stakersModuleStatus, rollupsModuleStatus, - toggleTheme: () => - setTheme((curr: Theme) => (curr === "light" ? "dark" : "light")), + toggleTheme: () => setTheme((curr: Theme) => (curr === "light" ? "dark" : "light")), toggleStakersModuleStatus: () => - setStakersModuleStatus((curr: UiModuleStatus) => - curr === "enabled" ? "disabled" : "enabled" - ), + setStakersModuleStatus((curr: UiModuleStatus) => (curr === "enabled" ? "disabled" : "enabled")), toggleRollupsModuleStatus: () => - setRollupsModuleStatus((curr: UiModuleStatus) => - curr === "enabled" ? "disabled" : "enabled" - ) + setRollupsModuleStatus((curr: UiModuleStatus) => (curr === "enabled" ? "disabled" : "enabled")) }; return ( @@ -161,10 +159,7 @@ export default function App() { // Start API and Socket.io once user has logged in useEffect(() => { - if (isLoggedIn) - startApi(onFetchLoginStatus).catch(e => - console.error("Error on startApi", e) - ); + if (isLoggedIn) startApi(onFetchLoginStatus).catch((e) => console.error("Error on startApi", e)); }, [isLoggedIn, onFetchLoginStatus]); // Keep retrying if there is a loggin error, probably due a network error diff --git a/packages/admin-ui/src/__mock-backend__/autoUpdate.ts b/packages/admin-ui/src/__mock-backend__/autoUpdate.ts index 78f30907f..76906b8d8 100644 --- a/packages/admin-ui/src/__mock-backend__/autoUpdate.ts +++ b/packages/admin-ui/src/__mock-backend__/autoUpdate.ts @@ -1,15 +1,11 @@ import { AutoUpdateDataView, Routes } from "@dappnode/types"; import { pause } from "./utils/pause"; -export const autoUpdate: Pick< - Routes, - "autoUpdateDataGet" | "autoUpdateSettingsEdit" -> = { +export const autoUpdate: Pick = { autoUpdateDataGet: async () => autoUpdateData, autoUpdateSettingsEdit: async ({ id, enabled }) => { await pause(500); - if (autoUpdateData.settings[id]) - autoUpdateData.settings[id].enabled = enabled; + if (autoUpdateData.settings[id]) autoUpdateData.settings[id].enabled = enabled; for (const dnp of autoUpdateData.dnpsToShow) { if (dnp.id === id) dnp.enabled = enabled; @@ -79,8 +75,7 @@ const autoUpdateData: AutoUpdateDataView = { enabled: true, feedback: { inQueue: true, - errorMessage: - "More lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum" + errorMessage: "More lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum" } } ] diff --git a/packages/admin-ui/src/__mock-backend__/data/directory.ts b/packages/admin-ui/src/__mock-backend__/data/directory.ts index 000b77f02..fb87c8f0c 100644 --- a/packages/admin-ui/src/__mock-backend__/data/directory.ts +++ b/packages/admin-ui/src/__mock-backend__/data/directory.ts @@ -7,8 +7,7 @@ function getDirectoryDnp(dnp: MockDnp, index: number): DirectoryItemOk { index, status: "ok", name: dnp.manifest.name, - description: - dnp.manifest.shortDescription || dnp.manifest.description || "", + description: dnp.manifest.shortDescription || dnp.manifest.description || "", avatarUrl: dnp.avatar || "", isFeatured: false, isInstalled: Boolean(dnp.installedData), diff --git a/packages/admin-ui/src/__mock-backend__/data/dnpInstalled.ts b/packages/admin-ui/src/__mock-backend__/data/dnpInstalled.ts index 0a8ce588d..5bbedecc6 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnpInstalled.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnpInstalled.ts @@ -12,10 +12,7 @@ import { mockDnps } from "./dnps"; function getInstalledDnp(dnp: MockDnp): InstalledPackageDetailData { const dnpName = dnp.manifest.name; - function getContainer( - serviceName: string, - container: Partial - ): PackageContainer { + function getContainer(serviceName: string, container: Partial): PackageContainer { return { ...sampleContainer, containerId: `0000000000000${dnpName}`, @@ -48,17 +45,13 @@ function getInstalledDnp(dnp: MockDnp): InstalledPackageDetailData { userSettings: { environment: dnp.userSettings?.environment }, setupWizard: dnp.setupWizard && { ...dnp.setupWizard, - fields: dnp.setupWizard.fields.filter( - f => f.target?.type === "environment" - ) + fields: dnp.setupWizard.fields.filter((f) => f.target?.type === "environment") }, containers: dnp.installedContainers - ? Object.entries(dnp.installedContainers).map( - ([serviceName, container]) => ({ - ...getContainer(serviceName, container), - ...container - }) - ) + ? Object.entries(dnp.installedContainers).map(([serviceName, container]) => ({ + ...getContainer(serviceName, container), + ...container + })) : [getContainer(dnpName, {})], ...dnp.installedData @@ -75,21 +68,10 @@ const getContainerName = ({ isCore: boolean; }): string => // Note: _PREFIX variables already end with the character "-" - [ - isCore ? "DAppNodeCore-" : "DAppNodePackage-", - getContainerDomain({ dnpName, serviceName }) - ].join(""); + [isCore ? "DAppNodeCore-" : "DAppNodePackage-", getContainerDomain({ dnpName, serviceName })].join(""); -const getContainerDomain = ({ - dnpName, - serviceName -}: { - serviceName?: string; - dnpName: string; -}): string => { - return !serviceName || serviceName === dnpName - ? dnpName - : `${serviceName}.${dnpName}`; +const getContainerDomain = ({ dnpName, serviceName }: { serviceName?: string; dnpName: string }): string => { + return !serviceName || serviceName === dnpName ? dnpName : `${serviceName}.${dnpName}`; }; const getImageTag = ({ diff --git a/packages/admin-ui/src/__mock-backend__/data/dnpRequest.ts b/packages/admin-ui/src/__mock-backend__/data/dnpRequest.ts index 602ccc20e..723b7bd80 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnpRequest.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnpRequest.ts @@ -20,8 +20,7 @@ function getRequestDnp(dnp: MockDnp): RequestedDnp { const dnpName = dep.manifest.name; if (dep.userSettings) settings[dnpName] = dep.userSettings; if (dep.setupWizard) setupWizard[dnpName] = dep.setupWizard; - if (dep.specialPermissions) - specialPermissions[dnpName] = dep.specialPermissions; + if (dep.specialPermissions) specialPermissions[dnpName] = dep.specialPermissions; compatibleDnps[dnpName] = { from: dep.installedData?.version, to: dep.manifest.version diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/bitcoin.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/bitcoin.ts index 57087426a..2565c4625 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/bitcoin.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/bitcoin.ts @@ -18,8 +18,7 @@ export const bitcoin: MockDnp = { featuredBackground: "linear-gradient(to right, #4b3317, #cb6e00)", featuredColor: "white" }, - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: [ "Abel Boldú (@vdo)", "Eduardo Antuña (https://github.com/eduadiez)", @@ -29,8 +28,7 @@ export const bitcoin: MockDnp = { onRemove: "Make sure you have change the endpoint in your bitcoin miner" }, keywords: ["bitcoin", "btc"], - // @ts-ignore - homepage: { + links: { homepage: "https://github.com/dappnode/DAppNodePackage-bitcoin#readme" }, repository: { diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/geth.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/geth.ts index 051681de0..7d5839902 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/geth.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/geth.ts @@ -1,8 +1,7 @@ import { MockDnp } from "./types"; export const geth: MockDnp = { - avatar: - "https://github.com/dappnode/DAppNodePackage-geth/blob/master/geth-avatar.png", + avatar: "https://github.com/dappnode/DAppNodePackage-geth/blob/master/geth-avatar.png", manifest: { name: "geth.dnp.dappnode.eth", @@ -10,16 +9,14 @@ export const geth: MockDnp = { upstreamVersion: "v1.10.21", upstreamRepo: "ethereum/go-ethereum", upstreamArg: "UPSTREAM_VERSION", - shortDescription: - "Geth is the official Go implementation of the Ethereum protocol.", + shortDescription: "Geth is the official Go implementation of the Ethereum protocol.", description: "Ethereum is a global, open-source platform for decentralized applications where you can write code that controls digital value, runs exactly as programmed, and is accessible anywhere in the world.", type: "service", architectures: ["linux/amd64", "linux/arm64"], chain: "ethereum", dockerTimeout: "20min", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: [ "Mariano Conti (nanexcool) (hhttps://github.com/nanexcool)", "Eduardo Antuña (https://github.com/eduadiez)", diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/https-portal.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/https-portal.ts index e7e84c936..ace573f1a 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/https-portal.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/https-portal.ts @@ -10,8 +10,7 @@ export const httpsPortal: MockDnp = { version: "0.1.0", description: "HTTPs Portal", type: "service", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", links: { WebApplication: "http://https.dappnode/", homepage: "https://github.com/dappnode/DNP_HTTPS#readme" diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/lightningNetwork.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/lightningNetwork.ts index c5dbd8f7d..9745266ec 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/lightningNetwork.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/lightningNetwork.ts @@ -15,34 +15,29 @@ export const lightningNetwork: MockDnp = { version: "0.0.3", upstreamVersion: "0.6.1-beta", shortDescription: "Scalable, instant Bitcoin/Blockchain transactions", - description: "The Lightning Network DAppNodePackage (lnd + RTL). The Lightning Network is a decentralized system for instant, high-volume micropayments that removes the risk of delegating custody of funds to trusted third parties.".repeat( - 10 - ), + description: + "The Lightning Network DAppNodePackage (lnd + RTL). The Lightning Network is a decentralized system for instant, high-volume micropayments that removes the risk of delegating custody of funds to trusted third parties.".repeat( + 10 + ), type: "service", backup: [{ name: "data", path: "/root/.lnd/data" }], style: { featuredBackground: "linear-gradient(67deg, #090909, #2f1354)", featuredColor: "#eee" }, - author: - "DAppNode Association (https://github.com/dappnode)", - contributors: [ - "Abel Boldú (@vdo)", - "Eduardo Antuña (https://github.com/eduadiez)" - ], + author: "DAppNode Association (https://github.com/dappnode)", + contributors: ["Abel Boldú (@vdo)", "Eduardo Antuña (https://github.com/eduadiez)"], categories: ["Payment channels", "Economic incentive"], keywords: ["bitcoin", "btc", "lightning network", "lnd"], links: { - homepage: - "https://github.com/dappnode/DAppNodePackage-LightningNetwork#readme", + homepage: "https://github.com/dappnode/DAppNodePackage-LightningNetwork#readme", ui: "http://lightning-network.dappnode", api: "http://lightning-network.dappnode:8080", another: "http://lightning-network.dappnode" }, repository: { type: "git", - url: - "git+https://github.com/dappnode/DAppNodePackage-LightningNetwork.git" + url: "git+https://github.com/dappnode/DAppNodePackage-LightningNetwork.git" }, bugs: { url: "https://github.com/dappnode/DAppNodePackage-LightningNetwork/issues" @@ -90,8 +85,7 @@ export const lightningNetwork: MockDnp = { name: "ONLY_TESTNET" }, title: "Only testnet", - description: - "Mock variable that should only be visible if `network = testnet`", + description: "Mock variable that should only be visible if `network = testnet`", required: true, if: { network: { enum: ["testnet"] } @@ -170,8 +164,7 @@ Content in the first column | Content in the second column packageSentData: { apiKey: "AAXXAAXXAAXXAAXXAAXXAAXXAAXXAAXXAAXXAAXX", secretKey: "ZZXXZZXXZZXXZZXXZZXXZZXXZZXXZZXXZZXXZZXX", - link: - "http://lightningNetwork.dappnode.eth/initialize?token=geagehTEGEgeg36eb.NIGE43" + link: "http://lightningNetwork.dappnode.eth/initialize?token=geagehTEGEgeg36eb.NIGE43" } }, installedContainers: { diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/multiService.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/multiService.ts index 42f7dad20..4cc496cee 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/multiService.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/multiService.ts @@ -17,8 +17,7 @@ export const multiService: MockDnp = { version: "0.2.0", description: "Sample package with two services.", type: "service", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: [], links: { homepage: "https://github.com/multi-service/multi-service#readme" diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/openEthereum.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/openEthereum.ts index d64fdc50d..5e7bc0f5a 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/openEthereum.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/openEthereum.ts @@ -8,16 +8,12 @@ export const openEthereum: MockDnp = { manifest: { name: dnpName, version: "0.2.6", - description: - "Dappnode package responsible for providing the Ethereum blockchain, based on Parity v2.5.8-stable", + description: "Dappnode package responsible for providing the Ethereum blockchain, based on Parity v2.5.8-stable", type: "dncore", chain: "ethereum", upstreamVersion: "v2.5.8-stable", - author: - "DAppNode Association (https://github.com/dappnode)", - contributors: [ - "Eduardo Antuña (https://github.com/eduadiez)" - ], + author: "DAppNode Association (https://github.com/dappnode)", + contributors: ["Eduardo Antuña (https://github.com/eduadiez)"], keywords: ["DAppNodeCore", "Parity", "Mainnet", "Ethereum"], links: { homepage: "https://your-project-homepage-or-docs.io" diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/prysm.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/prysm.ts index f23490c48..a6f52e1b4 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/prysm.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/prysm.ts @@ -1,8 +1,7 @@ import { MockDnp } from "./types"; export const prysm: MockDnp = { - avatar: - "https://github.com/dappnode/DAppNodePackage-prysm/blob/main/avatar-prysm.png", + avatar: "https://github.com/dappnode/DAppNodePackage-prysm/blob/main/avatar-prysm.png", manifest: { name: "prysm.dnp.dappnode.eth", @@ -16,11 +15,8 @@ export const prysm: MockDnp = { type: "service", architectures: ["linux/amd64"], mainService: "validator", - author: - "DAppNode Association (https://github.com/dappnode)", - contributors: [ - "dappLion (https://github.com/dapplion)" - ], + author: "DAppNode Association (https://github.com/dappnode)", + contributors: ["dappLion (https://github.com/dapplion)"], license: "GPL-3.0", repository: { type: "git", @@ -69,8 +65,7 @@ export const prysm: MockDnp = { service: "validator" }, title: "Graffiti", - description: - "Add a string to your proposed blocks, which will be seen on the block explorer" + description: "Add a string to your proposed blocks, which will be seen on the block explorer" }, { id: "HTTP_WEB3PROVIDER", diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/raiden.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/raiden.ts index a8fbeee2e..7a6653b57 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/raiden.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/raiden.ts @@ -24,11 +24,9 @@ export const raiden: MockDnp = { featuredColor: "white", featuredAvatarFilter: "invert(1)" }, - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: ["Abel Boldú (@vdo)"], - //@ts-ignore - homepage: { + links: { homepage: "https://github.com/dappnode/DAppNodePackage-raiden#readme" }, repository: { diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/raidenTestnet.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/raidenTestnet.ts index 59ed11f89..c68c54038 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/raidenTestnet.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/raidenTestnet.ts @@ -12,13 +12,11 @@ export const raidenTestnet: MockDnp = { description: "The Raiden Network is an off-chain scaling solution, enabling near-instant, low-fee and scalable payments. It’s complementary to the Ethereum blockchain and works with any ERC20 compatible token. \n\n\n **Getting started** \n\n Once you have installed the Raiden DAppNode Package you **must** upload your own keystore. Go to this [getting started guide](https://github.com/dappnode/DAppNodePackage-raiden) to learn how to do so. \n\n\n All set? Check out the [documentation and introductory guides](https://raiden-network.readthedocs.io/en/stable/#how-to-get-started) to quickly get started doing payments.", type: "service", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: ["Abel Boldú (@vdo)", "Eduardo Antuña (@eduadiez)"], links: { WebApplication: "http://raiden-testnet.dappnode/", - homepage: - "https://github.com/dappnode/DAppNodePackage-raiden-testnet#readme" + homepage: "https://github.com/dappnode/DAppNodePackage-raiden-testnet#readme" }, repository: { type: "git", diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/trustlines.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/trustlines.ts index 0f7d49bb9..379312450 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/trustlines.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/trustlines.ts @@ -26,11 +26,8 @@ export const trustlines: MockDnp = { featuredBackground: "linear-gradient(67deg, #140a0a, #512424)", featuredColor: "white" }, - author: - "DAppNode Association (https://github.com/dappnode)", - contributors: [ - "Eduardo Antuña (https://github.com/eduadiez)" - ], + author: "DAppNode Association (https://github.com/dappnode)", + contributors: ["Eduardo Antuña (https://github.com/eduadiez)"], categories: ["Blockchain"], links: { homepage: "https://github.com/dappnode/DAppNodePackage-trustlines#readme", @@ -50,8 +47,7 @@ export const trustlines: MockDnp = { specialPermissions: [ { name: "Fake permissions of host access", - details: - "Fake permissions that does not mean anything\n\n - **markdown** _test_" + details: "Fake permissions that does not mean anything\n\n - **markdown** _test_" } ], userSettings: { @@ -86,8 +82,7 @@ export const trustlines: MockDnp = { path: "/config/custom/keys/Trustlines/main-keystore.json" }, title: "Keystore", - description: - "Your Keystore/JSON file containing the private key that you want to use for this node", + description: "Your Keystore/JSON file containing the private key that you want to use for this node", required: true }, { diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/types.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/types.ts index d7744b5ef..55ef76a2f 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/types.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/types.ts @@ -15,9 +15,7 @@ export interface MockDnp { specialPermissions?: SpecialPermission[]; gettingStarted?: string; dependencies?: MockDnp[]; - installedData?: Partial< - InstalledPackageDetailData & { containers: PackageContainer[] } - >; + installedData?: Partial; installedContainers?: { [serviceName: string]: Partial }; requestDnp?: Partial; } diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/web3signer.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/web3signer.ts index 079db4631..7f092ab15 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/web3signer.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/web3signer.ts @@ -1,8 +1,7 @@ import { MockDnp } from "./types"; export const web3signer: MockDnp = { - avatar: - "https://github.com/dappnode/DAppNodePackage-web3signer/blob/master/node-avatar.png", + avatar: "https://github.com/dappnode/DAppNodePackage-web3signer/blob/master/node-avatar.png", manifest: { name: "web3signer.dnp.dappnode.eth", @@ -11,13 +10,11 @@ export const web3signer: MockDnp = { architectures: ["linux/amd64"], upstreamRepo: "ConsenSys/web3signer", mainService: "web3signer", - shortDescription: - "Remote signer + slashing protection database + User interface to import validator keystores", + shortDescription: "Remote signer + slashing protection database + User interface to import validator keystores", description: "Web3Signer is an open-source signing service developed under the Apache 2.0 license and written in Java. Web3Signer is capable of signing on multiple platforms using private keys stored in an external vault, or encrypted on a disk.", type: "service", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", contributors: [ "mgarciate (https://github.com/mgarciate)", "pablomendezroyo (https://github.com/pablomendezroyo" @@ -31,8 +28,7 @@ export const web3signer: MockDnp = { url: "https://github.com/dappnode/DAppNodePackage-web3signer/issues" }, links: { - ui: - "http://ui.web3signer.dappnode?signer_url=http://web3signer.web3signer.dappnode:9000", + ui: "http://ui.web3signer.dappnode?signer_url=http://web3signer.web3signer.dappnode:9000", homepage: "https://docs.web3signer.consensys.net/en/latest/", readme: "https://github.com/ConsenSys/web3signer/blob/master/README.md" }, diff --git a/packages/admin-ui/src/__mock-backend__/data/dnps/wireguard.ts b/packages/admin-ui/src/__mock-backend__/data/dnps/wireguard.ts index 08e9d538c..db13d36df 100644 --- a/packages/admin-ui/src/__mock-backend__/data/dnps/wireguard.ts +++ b/packages/admin-ui/src/__mock-backend__/data/dnps/wireguard.ts @@ -10,8 +10,7 @@ export const wireguard: MockDnp = { version: "0.1.0", description: "Wireguard", type: "service", - author: - "DAppNode Association (https://github.com/dappnode)", + author: "DAppNode Association (https://github.com/dappnode)", links: { WebApplication: "http://wireguard.dappnode/", homepage: "https://github.com/dappnode/DAppNodePackage-wireguard#readme" diff --git a/packages/admin-ui/src/__mock-backend__/data/publicDnps/index.ts b/packages/admin-ui/src/__mock-backend__/data/publicDnps/index.ts index b596b3455..5b17001c4 100644 --- a/packages/admin-ui/src/__mock-backend__/data/publicDnps/index.ts +++ b/packages/admin-ui/src/__mock-backend__/data/publicDnps/index.ts @@ -22,8 +22,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "ok", - description: - "Turbo-Geth is a fork of Go-Ethereum with focus on performance.", + description: "Turbo-Geth is a fork of Go-Ethereum with focus on performance.", avatarUrl: "/ipfs/QmWYB5vQYnXTw1PimzemQfkPHfJHzn8qDMRVWNmFMKrxK9", isInstalled: false, isUpdated: false, @@ -62,8 +61,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "ok", - description: - "BOINC is an open-source software platform for computing using volunteered resour", + description: "BOINC is an open-source software platform for computing using volunteered resour", avatarUrl: "/ipfs/QmRA5jyeRA2M6Ssoc1bfzvWAALXYw8ru6xF1pz4cWBDWwM", isInstalled: false, isUpdated: false, @@ -154,8 +152,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "error", - message: - "External volumes are not allowed 'archipelpublicdappnodeeth_config'" + message: "External volumes are not allowed 'archipelpublicdappnodeeth_config'" }, { index: 8, @@ -176,8 +173,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "ok", - description: - "Polygon is a protocol and a framework for building and connecting Ethereum-compa", + description: "Polygon is a protocol and a framework for building and connecting Ethereum-compa", avatarUrl: "/ipfs/QmcpcWEdinxyJe8orsh1okp3B73KaAQBxGy4eFkuKWtLM6", isInstalled: false, isUpdated: false, @@ -281,8 +277,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "ok", - description: - "Archipel : Divide and federate to run unsinkable services. Welcome aboard to all", + description: "Archipel : Divide and federate to run unsinkable services. Welcome aboard to all", avatarUrl: "/ipfs/QmRjKPQQSxYDuAEnfCEMyU9bwGEHmm22qV1Q1oShJvUqFu", isInstalled: false, isUpdated: false, @@ -295,8 +290,7 @@ export const mockPublicDnps: DirectoryItem[] = [ whitelisted: true, isFeatured: false, status: "ok", - description: - "DAppNode Package FAHClient https://foldingathome.org. More information at https:", + description: "DAppNode Package FAHClient https://foldingathome.org. More information at https:", avatarUrl: "/ipfs/Qmf7NoxkpPBeVkcVvFyw3AMuJZL4KniCLDFVjv5Rzewi5H", isInstalled: false, isUpdated: false, diff --git a/packages/admin-ui/src/__mock-backend__/data/sample.ts b/packages/admin-ui/src/__mock-backend__/data/sample.ts index a72d1f37d..26214ea08 100644 --- a/packages/admin-ui/src/__mock-backend__/data/sample.ts +++ b/packages/admin-ui/src/__mock-backend__/data/sample.ts @@ -1,9 +1,4 @@ -import { - DirectoryItem, - RequestedDnp, - InstalledPackageDetailData, - PackageContainer -} from "@dappnode/types"; +import { DirectoryItem, RequestedDnp, InstalledPackageDetailData, PackageContainer } from "@dappnode/types"; const dnpName = "test.dnp.dappnode.eth"; export const sampleRequestState: RequestedDnp = { diff --git a/packages/admin-ui/src/__mock-backend__/devices.ts b/packages/admin-ui/src/__mock-backend__/devices.ts index 87c97874b..29e7f3888 100644 --- a/packages/admin-ui/src/__mock-backend__/devices.ts +++ b/packages/admin-ui/src/__mock-backend__/devices.ts @@ -8,9 +8,7 @@ const initialDevices: VpnDevice[] = [ { id: "second-admin", admin: true, hasChangedPassword: false, password } ]; -const devicesState = new Map( - initialDevices.map(device => [device.id, device]) -); +const devicesState = new Map(initialDevices.map((device) => [device.id, device])); export const devices: Pick< Routes, diff --git a/packages/admin-ui/src/__mock-backend__/fetchPkgsData.ts b/packages/admin-ui/src/__mock-backend__/fetchPkgsData.ts index 739223c76..4bcacd77f 100644 --- a/packages/admin-ui/src/__mock-backend__/fetchPkgsData.ts +++ b/packages/admin-ui/src/__mock-backend__/fetchPkgsData.ts @@ -8,7 +8,7 @@ export const fetchPkgsData: Pick< fetchCoreUpdateData: async () => sampleCoreUpdateData, fetchDirectory: async () => directory, fetchRegistry: async () => { - return await new Promise(resolve => { + return await new Promise((resolve) => { setTimeout(() => { resolve(registry); }, 10000); diff --git a/packages/admin-ui/src/__mock-backend__/httpsPortal.ts b/packages/admin-ui/src/__mock-backend__/httpsPortal.ts index 56889c4a7..d730b8e02 100644 --- a/packages/admin-ui/src/__mock-backend__/httpsPortal.ts +++ b/packages/admin-ui/src/__mock-backend__/httpsPortal.ts @@ -1,8 +1,4 @@ -import { - ExposableServiceInfo, - HttpsPortalMapping, - Routes -} from "@dappnode/types"; +import { ExposableServiceInfo, HttpsPortalMapping, Routes } from "@dappnode/types"; const mappings = new Map(); @@ -33,11 +29,9 @@ export const httpsPortal: Pick< }, httpsPortalMappingsGet: async () => Array.from(mappings.values()), httpsPortalExposableServicesGet: async () => { - const mappingsById = new Map( - Array.from(mappings.values()).map(mapping => [getId(mapping), mapping]) - ); + const mappingsById = new Map(Array.from(mappings.values()).map((mapping) => [getId(mapping), mapping])); - return exposable.map(mapping => { + return exposable.map((mapping) => { const exposedMapping = mappingsById.get(getId(mapping)); if (exposedMapping) { return { ...exposedMapping, ...mapping, exposed: true }; diff --git a/packages/admin-ui/src/__mock-backend__/index.ts b/packages/admin-ui/src/__mock-backend__/index.ts index 1af534bba..b547e360d 100644 --- a/packages/admin-ui/src/__mock-backend__/index.ts +++ b/packages/admin-ui/src/__mock-backend__/index.ts @@ -41,21 +41,17 @@ const namedSpacedCalls = { ...wifi }; -let dappnodeWebName = "Mock-DAppNode"; +const dappnodeWebName = "Mock-DAppNode"; export const otherCalls: Omit = { - backupGet: async () => - "64020f6e8d2d02aa2324dab9cd68a8ccb186e192232814f79f35d4c2fbf2d1cc", + backupGet: async () => "64020f6e8d2d02aa2324dab9cd68a8ccb186e192232814f79f35d4c2fbf2d1cc", backupRestore: async () => {}, chainDataGet: async () => [ { dnpName: "geth.dnp.dappnode.eth", syncing: true, error: false, - message: [ - "Blocks synced: 543000 / 654000", - "States pulled: 25314123 / 154762142" - ].join("\n\n"), + message: ["Blocks synced: 543000 / 654000", "States pulled: 25314123 / 154762142"].join("\n\n"), help: "http://geth.io" }, { diff --git a/packages/admin-ui/src/__mock-backend__/localProxying.ts b/packages/admin-ui/src/__mock-backend__/localProxying.ts index 9faa78aa5..d9aff0ddc 100644 --- a/packages/admin-ui/src/__mock-backend__/localProxying.ts +++ b/packages/admin-ui/src/__mock-backend__/localProxying.ts @@ -5,15 +5,10 @@ const localProxyingStatusON: LocalProxyingStatus = "running"; const localProxyingStatusOFF: LocalProxyingStatus = "stopped"; let localProxyingStatus: LocalProxyingStatus = localProxyingStatusON; -export const localProxying: Pick< - Routes, - "localProxyingEnableDisable" | "localProxyingStatusGet" -> = { - localProxyingEnableDisable: async enable => { +export const localProxying: Pick = { + localProxyingEnableDisable: async (enable) => { await pause(2000); - localProxyingStatus = enable - ? localProxyingStatusON - : localProxyingStatusOFF; + localProxyingStatus = enable ? localProxyingStatusON : localProxyingStatusOFF; }, localProxyingStatusGet: async () => localProxyingStatus }; diff --git a/packages/admin-ui/src/__mock-backend__/notifications.ts b/packages/admin-ui/src/__mock-backend__/notifications.ts index c3281f736..6fbf581d5 100644 --- a/packages/admin-ui/src/__mock-backend__/notifications.ts +++ b/packages/admin-ui/src/__mock-backend__/notifications.ts @@ -1,9 +1,6 @@ import { PackageNotificationDb, Routes } from "@dappnode/types"; -export const notifications: Pick< - Routes, - "notificationsGet" | "notificationsRemove" | "notificationsTest" -> = { +export const notifications: Pick = { notificationsGet: async () => sampleNotifications, notificationsRemove: async () => {}, notificationsTest: async () => {} @@ -14,8 +11,7 @@ const sampleNotifications: PackageNotificationDb[] = [ id: "notification-web3signer-gnosis.dnp.dappnode.eth", type: "danger", title: "Web3signer eth2 client selected is not available", - body: - "Make sure you hace selected an available client at packages > web3signer > config > eth2 client", + body: "Make sure you hace selected an available client at packages > web3signer > config > eth2 client", timestamp: 153834826, viewed: false }, diff --git a/packages/admin-ui/src/__mock-backend__/packages.ts b/packages/admin-ui/src/__mock-backend__/packages.ts index c77d4128f..fc794be20 100644 --- a/packages/admin-ui/src/__mock-backend__/packages.ts +++ b/packages/admin-ui/src/__mock-backend__/packages.ts @@ -5,14 +5,9 @@ import { pause } from "./utils/pause"; const pkgRestartMs = 2000; -const packagesState = new Map( - dnpInstalled.map(dnp => [dnp.dnpName, dnp]) -); - -function update( - dnpName: string, - fn: (dnp: InstalledPackageDetailData) => Partial -) { +const packagesState = new Map(dnpInstalled.map((dnp) => [dnp.dnpName, dnp])); + +function update(dnpName: string, fn: (dnp: InstalledPackageDetailData) => Partial) { const dnp = packagesState.get(dnpName); if (!dnp) throw Error(`dnpName ${dnpName} not found`); packagesState.set(dnpName, { ...dnp, ...fn(dnp) }); @@ -80,16 +75,16 @@ export const packages: Pick< packageRestart: async ({ dnpName }) => { await pause(pkgRestartMs); - update(dnpName, dnp => ({ - containers: dnp.containers.map(container => ({ + update(dnpName, (dnp) => ({ + containers: dnp.containers.map((container) => ({ ...container, state: "exited" })) })); await pause(pkgRestartMs); - update(dnpName, dnp => ({ - containers: dnp.containers.map(container => ({ + update(dnpName, (dnp) => ({ + containers: dnp.containers.map((container) => ({ ...container, state: "running" })) @@ -102,10 +97,8 @@ export const packages: Pick< packageSetEnvironment: async ({ dnpName, environmentByService }) => { await pause(pkgRestartMs); - for (const [serviceName, environment] of Object.entries( - environmentByService - )) { - update(dnpName, dnp => ({ + for (const [serviceName, environment] of Object.entries(environmentByService)) { + update(dnpName, (dnp) => ({ userSettings: { ...dnp.userSettings, environment: { @@ -121,14 +114,10 @@ export const packages: Pick< packageSetPortMappings: async ({ dnpName, portMappingsByService }) => { await pause(pkgRestartMs); - for (const [serviceName, portMappings] of Object.entries( - portMappingsByService - )) { - update(dnpName, dnp => ({ - containers: dnp.containers.map(container => - container.serviceName === serviceName - ? { ...container, ports: portMappings } - : container + for (const [serviceName, portMappings] of Object.entries(portMappingsByService)) { + update(dnpName, (dnp) => ({ + containers: dnp.containers.map((container) => + container.serviceName === serviceName ? { ...container, ports: portMappings } : container ) })); } @@ -139,8 +128,8 @@ export const packages: Pick< const dnp = packagesState.get(dnpName); if (!dnp) throw Error(`dnpName ${dnpName} not found`); - update(dnp.dnpName, d => ({ - containers: d.containers.map(container => + update(dnp.dnpName, (d) => ({ + containers: d.containers.map((container) => !serviceNames || serviceNames?.includes(container.serviceName) ? { ...container, diff --git a/packages/admin-ui/src/__mock-backend__/releaseTrustedKey.ts b/packages/admin-ui/src/__mock-backend__/releaseTrustedKey.ts index 6ac036982..a98995c1f 100644 --- a/packages/admin-ui/src/__mock-backend__/releaseTrustedKey.ts +++ b/packages/admin-ui/src/__mock-backend__/releaseTrustedKey.ts @@ -7,19 +7,17 @@ const initialTrustedKey: TrustedReleaseKey = { key: "0xf35960302a07022aba880dffaec2fdd64d5bf1c1" }; -const trustedKeys = new Map([ - [initialTrustedKey.name, initialTrustedKey] -]); +const trustedKeys = new Map([[initialTrustedKey.name, initialTrustedKey]]); export const releaseTrustedKey: Pick< Routes, "releaseTrustedKeyAdd" | "releaseTrustedKeyList" | "releaseTrustedKeyRemove" > = { - releaseTrustedKeyAdd: async trustedKey => { + releaseTrustedKeyAdd: async (trustedKey) => { trustedKeys.set(trustedKey.name, trustedKey); }, releaseTrustedKeyList: async () => Array.from(trustedKeys.values()), - releaseTrustedKeyRemove: async keyName => { + releaseTrustedKeyRemove: async (keyName) => { trustedKeys.delete(keyName); } }; diff --git a/packages/admin-ui/src/__mock-backend__/ssh.ts b/packages/admin-ui/src/__mock-backend__/ssh.ts index 6961306ca..de06f9bcc 100644 --- a/packages/admin-ui/src/__mock-backend__/ssh.ts +++ b/packages/admin-ui/src/__mock-backend__/ssh.ts @@ -3,10 +3,7 @@ import { Routes } from "@dappnode/types"; let sshPort = 22; let sshStatus: "enabled" | "disabled" = "enabled"; -export const ssh: Pick< - Routes, - "sshPortGet" | "sshPortSet" | "sshStatusGet" | "sshStatusSet" -> = { +export const ssh: Pick = { sshPortGet: async () => sshPort, sshPortSet: async ({ port }) => { sshPort = port; diff --git a/packages/admin-ui/src/__mock-backend__/stakerConfig.ts b/packages/admin-ui/src/__mock-backend__/stakerConfig.ts index d284baff0..9bbb1c544 100644 --- a/packages/admin-ui/src/__mock-backend__/stakerConfig.ts +++ b/packages/admin-ui/src/__mock-backend__/stakerConfig.ts @@ -1,9 +1,6 @@ import { Routes, Network } from "@dappnode/types"; -export const stakerConfig: Pick< - Routes, - "stakerConfigGet" | "stakerConfigSet" -> = { +export const stakerConfig: Pick = { stakerConfigSet: async () => {}, stakerConfigGet: async (network: T) => { switch (network) { @@ -31,8 +28,7 @@ export const stakerConfig: Pick< signedSafe: true, manifest: { name: "geth.dnp.dappnode.eth", - description: - "Go implementation of ethereum. Execution client", + description: "Go implementation of ethereum. Execution client", shortDescription: "Go implementation of ethereum", version: "0.1.0" } diff --git a/packages/admin-ui/src/__mock-backend__/telegram.ts b/packages/admin-ui/src/__mock-backend__/telegram.ts index f8e1eecf8..f9c96e996 100644 --- a/packages/admin-ui/src/__mock-backend__/telegram.ts +++ b/packages/admin-ui/src/__mock-backend__/telegram.ts @@ -6,10 +6,7 @@ let telegramUserId: string = ""; export const telegram: Pick< Routes, - | "telegramStatusGet" - | "telegramStatusSet" - | "telegramConfigGet" - | "telegramConfigSet" + "telegramStatusGet" | "telegramStatusSet" | "telegramConfigGet" | "telegramConfigSet" > = { telegramStatusGet: async () => isEnabled, telegramStatusSet: async ({ telegramStatus }) => { diff --git a/packages/admin-ui/src/__mock-backend__/userActionLogs.ts b/packages/admin-ui/src/__mock-backend__/userActionLogs.ts index 5554f17f4..62311532f 100644 --- a/packages/admin-ui/src/__mock-backend__/userActionLogs.ts +++ b/packages/admin-ui/src/__mock-backend__/userActionLogs.ts @@ -3,8 +3,7 @@ import { Routes, UserActionLog } from "@dappnode/types"; const userActionLogsState: UserActionLog[] = []; export const userActionLogs: Pick = { - getUserActionLogs: async ({ first = 20, after = 0 }) => - userActionLogsState.slice(after, after + first) + getUserActionLogs: async ({ first = 20, after = 0 }) => userActionLogsState.slice(after, after + first) }; // Generate initial data diff --git a/packages/admin-ui/src/__mock-backend__/utils/pause.ts b/packages/admin-ui/src/__mock-backend__/utils/pause.ts index 86717279e..f721aa12e 100644 --- a/packages/admin-ui/src/__mock-backend__/utils/pause.ts +++ b/packages/admin-ui/src/__mock-backend__/utils/pause.ts @@ -1,3 +1,3 @@ export function pause(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } diff --git a/packages/admin-ui/src/__mock-backend__/volumes.ts b/packages/admin-ui/src/__mock-backend__/volumes.ts index 9728079ab..b0c9e57b3 100644 --- a/packages/admin-ui/src/__mock-backend__/volumes.ts +++ b/packages/admin-ui/src/__mock-backend__/volumes.ts @@ -2,9 +2,7 @@ import { pause } from "./utils/pause"; import { dnpInstalled } from "./data"; import { VolumeData, Routes } from "@dappnode/types"; -const volumesState = new Map( - getInitialVolumes().map(vol => [vol.name, vol]) -); +const volumesState = new Map(getInitialVolumes().map((vol) => [vol.name, vol])); export const volumes: Pick = { volumeRemove: async ({ name }) => { diff --git a/packages/admin-ui/src/__mock-backend__/wireguard.ts b/packages/admin-ui/src/__mock-backend__/wireguard.ts index e15176be1..1d74ff707 100644 --- a/packages/admin-ui/src/__mock-backend__/wireguard.ts +++ b/packages/admin-ui/src/__mock-backend__/wireguard.ts @@ -1,27 +1,20 @@ import { Routes } from "@dappnode/types"; -const initialDevices = [ - "dappnode_admin", - "other-user", - "wireguard-other-user-2" -]; +const initialDevices = ["dappnode_admin", "other-user", "wireguard-other-user-2"]; const devicesState = new Set(initialDevices); export const wireguard: Pick< Routes, - | "wireguardDeviceAdd" - | "wireguardDeviceGet" - | "wireguardDeviceRemove" - | "wireguardDevicesGet" + "wireguardDeviceAdd" | "wireguardDeviceGet" | "wireguardDeviceRemove" | "wireguardDevicesGet" > = { - wireguardDeviceAdd: async id => { + wireguardDeviceAdd: async (id) => { devicesState.add(id); }, - wireguardDeviceRemove: async id => { + wireguardDeviceRemove: async (id) => { devicesState.delete(id); }, wireguardDevicesGet: async () => Array.from(devicesState.values()), - wireguardDeviceGet: async id => { + wireguardDeviceGet: async (id) => { if (!devicesState.has(id)) throw Error(`No device id ${id}`); const configRemote = `[Interface] Address = 172.34.1.2 diff --git a/packages/admin-ui/src/__tests__/README.md b/packages/admin-ui/src/__tests__/README.md index c0b6feeb4..6e8619a28 100644 --- a/packages/admin-ui/src/__tests__/README.md +++ b/packages/admin-ui/src/__tests__/README.md @@ -55,13 +55,13 @@ Action code ```javascript function create() { - return function(dispatch) { + return function (dispatch) { dispatch(createStart()); return getBooking().then( - function(data) { + function (data) { dispatch(createFinish(data)); }, - function(err) { + function (err) { dispatch(createFail(err)); } ); @@ -73,7 +73,7 @@ Test code ```javascript describe("create", () => { - it("dispatch start and finish", done => { + it("dispatch start and finish", (done) => { const middlewares = [thunk]; const mockStore = configureStore(middlewares); const store = mockStore({}); diff --git a/packages/admin-ui/src/__tests__/pages/devices/helpers/coerceDeviceName.test.js b/packages/admin-ui/src/__tests__/pages/devices/helpers/coerceDeviceName.test.js index 64822eeab..e070e9528 100644 --- a/packages/admin-ui/src/__tests__/pages/devices/helpers/coerceDeviceName.test.js +++ b/packages/admin-ui/src/__tests__/pages/devices/helpers/coerceDeviceName.test.js @@ -1,5 +1,6 @@ import coerceDeviceName from "../../../../pages/vpn/helpers/coerceDeviceName"; import { maxIdLength } from "../../../../pages/vpn/data"; +import { expect, describe, it } from "@jest/globals"; describe("devices > helpers > coerceDeviceName", () => { it("Should remove non-alphanumeric characters", () => { diff --git a/packages/admin-ui/src/__tests__/pages/installer/helpers.test.ts b/packages/admin-ui/src/__tests__/pages/installer/helpers.test.ts index 97324a00c..d66cd2bc9 100644 --- a/packages/admin-ui/src/__tests__/pages/installer/helpers.test.ts +++ b/packages/admin-ui/src/__tests__/pages/installer/helpers.test.ts @@ -34,9 +34,7 @@ describe("pages > installer > helpers", () => { it("Should filter directory by input", () => { const query = dnp1Name; const selectedCategories: SelectedCategories = {}; - expect( - filterDirectory({ directory, query, selectedCategories }) - ).toEqual([dnp1]); + expect(filterDirectory({ directory, query, selectedCategories })).toEqual([dnp1]); }); it("Should filter directory by type", () => { @@ -45,9 +43,7 @@ describe("pages > installer > helpers", () => { Blockchain: false, Storage: true }; - expect( - filterDirectory({ directory, query, selectedCategories }) - ).toEqual([dnp2]); + expect(filterDirectory({ directory, query, selectedCategories })).toEqual([dnp2]); }); }); }); diff --git a/packages/admin-ui/src/__tests__/pages/installer/parsers/setupWizardParser.test.ts b/packages/admin-ui/src/__tests__/pages/installer/parsers/setupWizardParser.test.ts index c8e27af3b..d22674058 100644 --- a/packages/admin-ui/src/__tests__/pages/installer/parsers/setupWizardParser.test.ts +++ b/packages/admin-ui/src/__tests__/pages/installer/parsers/setupWizardParser.test.ts @@ -1,7 +1,4 @@ -import { - formDataToUserSettings, - userSettingsToFormData -} from "pages/installer/parsers/formDataParser"; +import { formDataToUserSettings, userSettingsToFormData } from "pages/installer/parsers/formDataParser"; import { SetupWizardFormDataReturn } from "pages/installer/types"; import { UserSettingsAllDnps } from "@dappnode/types"; import deepmerge from "deepmerge"; @@ -63,8 +60,7 @@ const testCases: { }, fileUploads: { [dnpName]: { - "/usr/src/app/config.json": - "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" + "/usr/src/app/config.json": "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" } } }, @@ -177,15 +173,11 @@ describe("setupWizardParsers", () => { for (const { testName, setupTarget, userSettings, formData } of testCases) { describe(testName, () => { it("formDataToUserSettings", () => { - expect(formDataToUserSettings(formData, setupTarget)).toEqual( - userSettings - ); + expect(formDataToUserSettings(formData, setupTarget)).toEqual(userSettings); }); it("userSettingsToFormData", () => { - expect(userSettingsToFormData(userSettings, setupTarget)).toEqual( - formData - ); + expect(userSettingsToFormData(userSettings, setupTarget)).toEqual(formData); }); }); } @@ -201,14 +193,9 @@ describe("setupWizardParsers", () => { } }; - const formDataWithUnknownProps: SetupWizardFormDataReturn = deepmerge( - formData, - formDataUnknownProps - ); + const formDataWithUnknownProps: SetupWizardFormDataReturn = deepmerge(formData, formDataUnknownProps); - expect( - formDataToUserSettings(formDataWithUnknownProps, setupTarget) - ).toEqual(userSettings); + expect(formDataToUserSettings(formDataWithUnknownProps, setupTarget)).toEqual(userSettings); }); it("userSettingsToFormData", () => { @@ -230,15 +217,9 @@ describe("setupWizardParsers", () => { } }; - const userSettingsWithUnknownProps: UserSettingsAllDnps = deepmerge( - userSettings, - userSettingsUnknownProps - ); + const userSettingsWithUnknownProps: UserSettingsAllDnps = deepmerge(userSettings, userSettingsUnknownProps); - const formDataResult = userSettingsToFormData( - userSettingsWithUnknownProps, - setupTarget - ); + const formDataResult = userSettingsToFormData(userSettingsWithUnknownProps, setupTarget); expect(formDataResult).toEqual(formData); }); diff --git a/packages/admin-ui/src/__tests__/services/isInstallingLogs/reducer.test.ts b/packages/admin-ui/src/__tests__/services/isInstallingLogs/reducer.test.ts index efa30a2cd..b4b779f17 100644 --- a/packages/admin-ui/src/__tests__/services/isInstallingLogs/reducer.test.ts +++ b/packages/admin-ui/src/__tests__/services/isInstallingLogs/reducer.test.ts @@ -1,8 +1,5 @@ import { reducer } from "services/isInstallingLogs/reducer"; -import { - updateIsInstallingLog, - clearIsInstallingLog -} from "services/isInstallingLogs/actions"; +import { updateIsInstallingLog, clearIsInstallingLog } from "services/isInstallingLogs/actions"; describe("services > isInstallingLogs > reducer", () => { describe("isInstallingLog dedicated reducers", () => { diff --git a/packages/admin-ui/src/__tests__/services/isInstallingLogs/selector.test.ts b/packages/admin-ui/src/__tests__/services/isInstallingLogs/selector.test.ts index 08877898b..40717a449 100644 --- a/packages/admin-ui/src/__tests__/services/isInstallingLogs/selector.test.ts +++ b/packages/admin-ui/src/__tests__/services/isInstallingLogs/selector.test.ts @@ -35,9 +35,7 @@ describe("service/isInstallingLogs", () => { // Cast Partial state to state to keep the test without writing the rest of the state const state = { [mountPoint]: isInstallingLogsState } as Partial; it("Should a nicely formated object ready to query", () => { - expect(getProgressLogsByDnp(state as RootState)).toEqual( - progressLogsByDnpExpected - ); + expect(getProgressLogsByDnp(state as RootState)).toEqual(progressLogsByDnpExpected); }); it("Should check that dnpName1 is installing", () => { diff --git a/packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.js b/packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.ts similarity index 78% rename from packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.js rename to packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.ts index b65bc3699..f8cb3b7ab 100644 --- a/packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.js +++ b/packages/admin-ui/src/__tests__/utils/computeSemverUpdateType.test.ts @@ -1,4 +1,5 @@ -import computeSemverUpdateType from "../../utils/computeSemverUpdateType"; +import { expect } from "chai"; +import computeSemverUpdateType from "../../utils/computeSemverUpdateType.js"; describe("utils > computeSemverUpdateType", () => { it("Should deal with invalid versions", () => { @@ -10,7 +11,7 @@ describe("utils > computeSemverUpdateType", () => { { from: null, to: "/ipfs/Amasjdnja" } ]; for (const { from, to } of cases) { - expect(computeSemverUpdateType(from, to)).toEqual(null); + expect(computeSemverUpdateType(from, to)).equal(null); } }); @@ -21,7 +22,7 @@ describe("utils > computeSemverUpdateType", () => { { from: "0.2.2", to: "0.2.1" } ]; for (const { from, to } of cases) { - expect(computeSemverUpdateType(from, to)).toEqual("downgrade"); + expect(computeSemverUpdateType(from, to)).equal("downgrade"); } }); @@ -32,7 +33,7 @@ describe("utils > computeSemverUpdateType", () => { { from: "1.2.3", to: "2.1.2" } ]; for (const { from, to } of cases) { - expect(computeSemverUpdateType(from, to)).toEqual("major"); + expect(computeSemverUpdateType(from, to)).equal("major"); } }); @@ -42,14 +43,14 @@ describe("utils > computeSemverUpdateType", () => { { from: "1.2.3", to: "1.3.2" } ]; for (const { from, to } of cases) { - expect(computeSemverUpdateType(from, to)).toEqual("minor"); + expect(computeSemverUpdateType(from, to)).equal("minor"); } }); it("Should detect different types of patch", () => { const cases = [{ from: "1.2.3", to: "1.2.4" }]; for (const { from, to } of cases) { - expect(computeSemverUpdateType(from, to)).toEqual("patch"); + expect(computeSemverUpdateType(from, to)).equal("patch"); } }); }); diff --git a/packages/admin-ui/src/__tests__/utils/format.test.ts b/packages/admin-ui/src/__tests__/utils/format.test.ts index c45ff7774..8128ff1c8 100644 --- a/packages/admin-ui/src/__tests__/utils/format.test.ts +++ b/packages/admin-ui/src/__tests__/utils/format.test.ts @@ -4,9 +4,7 @@ describe("utils > format", () => { describe("prettyVolumeName", () => { const dnpName = "geth-user.dnp.dappnode.eth"; it("Prettify own volume name", () => { - expect( - prettyVolumeName("dncore_gethdnpdappnodeeth_data", dnpName) - ).toEqual({ + expect(prettyVolumeName("dncore_gethdnpdappnodeeth_data", dnpName)).toEqual({ name: "Data", owner: "Geth" }); diff --git a/packages/admin-ui/src/__tests__/utils/lodashExtended.test.ts b/packages/admin-ui/src/__tests__/utils/lodashExtended.test.ts index 82daa84a0..049ce79f7 100644 --- a/packages/admin-ui/src/__tests__/utils/lodashExtended.test.ts +++ b/packages/admin-ui/src/__tests__/utils/lodashExtended.test.ts @@ -1,6 +1,6 @@ import { UserSettingsAllDnps } from "@dappnode/types"; import deepmerge from "deepmerge"; -import { difference, isDeepEmpty } from "utils/lodashExtended"; +import { difference, isDeepEmpty } from "../../utils/lodashExtended"; describe("lodashExtended", () => { describe("difference", () => { @@ -37,8 +37,7 @@ describe("lodashExtended", () => { [dnpName]: { fileUploads: { [dnpName]: { - "/usr/src/app/config.json": - "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" + "/usr/src/app/config.json": "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" } } }, @@ -56,13 +55,12 @@ describe("lodashExtended", () => { it("Should return the difference of an object with new keys", () => { const newUserSettings = deepmerge(userSettings, additionalUserSettings); - expect(difference(userSettings, newUserSettings)).toEqual( - additionalUserSettings - ); + expect(difference(userSettings, newUserSettings)).toEqual(additionalUserSettings); }); }); describe("isDeepEmpty", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const jsons: { json: any; empty: boolean; id: string }[] = [ // First level { id: "Empty object", json: {}, empty: true }, diff --git a/packages/admin-ui/src/api/auth.ts b/packages/admin-ui/src/api/auth.ts index 38e8e5d54..189303145 100644 --- a/packages/admin-ui/src/api/auth.ts +++ b/packages/admin-ui/src/api/auth.ts @@ -11,9 +11,7 @@ import { IApiAuth } from "./interface"; export const apiAuth: IApiAuth = { async fetchLoginStatus() { try { - const res = await fetchAuthPost<{}, LoginStatusReturn>( - apiUrls.loginStatus - ); + const res = await fetchAuthPost(apiUrls.loginStatus); return { status: "logged-in", username: res.username }; } catch (e) { switch (e.message) { @@ -82,6 +80,7 @@ async function parseBodyErrorMessage(res: Response): Promise { return bodyText; } } catch (e) { + console.error(`Error parsing body: ${e.message}\n${bodyText}`); return bodyText; } } diff --git a/packages/admin-ui/src/api/index.ts b/packages/admin-ui/src/api/index.ts index 835f5a9c7..d011c35fd 100644 --- a/packages/admin-ui/src/api/index.ts +++ b/packages/admin-ui/src/api/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { useEffect } from "react"; import useSWR, { responseInterface } from "swr"; import { mapValues } from "lodash-es"; @@ -28,15 +29,13 @@ export { apiRoutes }; // Inject mock API code to have a workable UI offline // Usefull for developing and testing UI elements without any server if (import.meta.env.VITE_APP_MOCK) { - import("./mock").then(mock => { + import("./mock").then((mock) => { Object.assign(apiAuth, mock.apiAuth); Object.assign(apiRoutes, mock.apiRoutes); Object.assign(apiRpc, mock.apiRpc); }); } -/* eslint-disable no-console */ - /** * Bridges events from the API websockets client to any consumer in the App * All WAMP events will be emitted in this PubSub instance @@ -49,9 +48,7 @@ if (import.meta.env.VITE_APP_MOCK) { const apiEventBridge = mitt(); // Map redux subscriptions to eventBridge -mapSubscriptionsToRedux( - subscriptionsFactory(apiEventBridge, subscriptionsLogger) -); +mapSubscriptionsToRedux(subscriptionsFactory(apiEventBridge, subscriptionsLogger)); export async function startApi(refetchStatus: () => void) { apiRpc.start( @@ -70,11 +67,9 @@ export async function startApi(refetchStatus: () => void) { ); } -const routeSubscription: Partial< - { - [K in keyof Routes]: keyof Subscriptions; - } -> = { +const routeSubscription: Partial<{ + [K in keyof Routes]: keyof Subscriptions; +}> = { autoUpdateDataGet: "autoUpdateData", devicesList: "devices", getUserActionLogs: "userActionLog", @@ -100,7 +95,9 @@ async function callRoute(method: string, params: any[]): Promise { */ export const api: Routes = mapValues( routesData, - (_data, route) => (...args: any[]) => callRoute(route, args) + (_data, route) => + (...args: any[]) => + callRoute(route, args) ); /** @@ -108,11 +105,9 @@ export const api: Routes = mapValues( * Useful to keep track of changing data that may need to be revalidated */ export const useApi: { - [K in keyof Routes]: ( - ...args: Parameters - ) => responseInterface, Error>; + [K in keyof Routes]: (...args: Parameters) => responseInterface, Error>; } = mapValues(routesData, (_data, route) => { - return function(...args: any[]) { + return function (...args: any[]) { const argsKey = args.length > 0 ? JSON.stringify(args) : ""; const fetcher = (...args: any[]) => callRoute(route, args); const res = useSWR([route, argsKey], () => fetcher(...args)); @@ -130,10 +125,7 @@ export const useApi: { * Bridges a single event from the websockets API client to any consumer in the App * **Note**: this callback MUST be memoized */ -export function useSubscribe( - route: keyof Subscriptions, - callback: (data: any) => void -): void { +export function useSubscribe(route: keyof Subscriptions, callback: (data: any) => void): void { useEffect(() => { apiEventBridge.on(route, callback); return () => { @@ -163,11 +155,9 @@ export function useSubscribe( * ``` */ export const useSubscription: { - [K in keyof Subscriptions]: ( - callback: (...args: Parameters) => void - ) => void; + [K in keyof Subscriptions]: (callback: (...args: Parameters) => void) => void; } = mapValues(subscriptionsData, (_data, route) => { - return function(callback: (...args: any) => void) { + return function (callback: (...args: any) => void) { useSubscribe(route as keyof Subscriptions, callback); }; }); diff --git a/packages/admin-ui/src/api/initialCalls.ts b/packages/admin-ui/src/api/initialCalls.ts index 938dc4331..97c68f179 100644 --- a/packages/admin-ui/src/api/initialCalls.ts +++ b/packages/admin-ui/src/api/initialCalls.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { store } from "../store"; import { fetchDnpInstalled } from "services/dnpInstalled/actions"; import { fetchCoreUpdateData } from "services/coreUpdate/actions"; diff --git a/packages/admin-ui/src/api/interface.ts b/packages/admin-ui/src/api/interface.ts index 3cb4598e5..1b16f8d99 100644 --- a/packages/admin-ui/src/api/interface.ts +++ b/packages/admin-ui/src/api/interface.ts @@ -11,14 +11,8 @@ export interface IApiAuth { fetchLoginStatus(): Promise; login(data: { username: string; password: string }): Promise<{ ok: true }>; logoutAndReload(): Promise; - register(data: { - username: string; - password: string; - }): Promise<{ recoveryToken: string }>; - changePass(data: { - password: string; - newPassword: string; - }): Promise<{ ok: true }>; + register(data: { username: string; password: string }): Promise<{ recoveryToken: string }>; + changePass(data: { password: string; newPassword: string }): Promise<{ ok: true }>; recoverPass(data: { token: string }): Promise<{ ok: true }>; } @@ -34,18 +28,11 @@ export interface IApiRoutes { /** Per container URL to download all of its logs */ containerLogsUrl(data: { containerName: string }): string; /** Upload file to Dappnode and get a fileId */ - uploadFile( - file: File, - onProgress: (data: { loaded: number; total: number }) => void - ): Promise<{ fileId: string }>; + uploadFile(file: File, onProgress: (data: { loaded: number; total: number }) => void): Promise<{ fileId: string }>; } export interface IApiRpc { - start( - apiEventBridge: Emitter, - onConnect: () => void, - onError: (errorMessage: string) => void - ): void; + start(apiEventBridge: Emitter, onConnect: () => void, onError: (errorMessage: string) => void): void; call(payload: RpcPayload): Promise>; } diff --git a/packages/admin-ui/src/api/mock/index.ts b/packages/admin-ui/src/api/mock/index.ts index 3c23ed860..3aaab038a 100644 --- a/packages/admin-ui/src/api/mock/index.ts +++ b/packages/admin-ui/src/api/mock/index.ts @@ -4,8 +4,7 @@ export { apiRpc } from "./rpc"; // Make sure to crash the UI if mock node is enabled in production -// @ts-ignore -window.mockEnabled = true; +//window.mockEnabled = true; console.warn("Mock mode enabled"); if (window.location.host === "my.dappnode") { throw Error("Mock must never be used in production"); diff --git a/packages/admin-ui/src/api/mock/routes.ts b/packages/admin-ui/src/api/mock/routes.ts index b781ed095..b03db2d1e 100644 --- a/packages/admin-ui/src/api/mock/routes.ts +++ b/packages/admin-ui/src/api/mock/routes.ts @@ -31,7 +31,7 @@ export const apiRoutes: IApiRoutes = { const total = file.size; for (let percent = 0; percent <= 100; percent++) { onProgress({ total, loaded: (total * percent) / 100 }); - await new Promise(r => setTimeout(r, 20)); + await new Promise((r) => setTimeout(r, 20)); } return { diff --git a/packages/admin-ui/src/api/mock/rpc.ts b/packages/admin-ui/src/api/mock/rpc.ts index 3fbe5f9b5..1beeb6be3 100644 --- a/packages/admin-ui/src/api/mock/rpc.ts +++ b/packages/admin-ui/src/api/mock/rpc.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { RpcPayload, RpcResponse } from "@dappnode/types"; import { calls } from "../../__mock-backend__"; import { IApiRpc } from "../interface"; @@ -8,9 +9,7 @@ export const apiRpc: IApiRpc = { if (typeof calls[method] !== "function") { throw Error(`method ${payload.method} not supported`); } - const result: R = await (calls[method] as ( - ...params: any[] - ) => Promise)(...payload.params); + const result: R = await (calls[method] as (...params: any[]) => Promise)(...payload.params); return { result }; }, diff --git a/packages/admin-ui/src/api/routes/index.ts b/packages/admin-ui/src/api/routes/index.ts index 52d9cf9f5..ee48ade47 100644 --- a/packages/admin-ui/src/api/routes/index.ts +++ b/packages/admin-ui/src/api/routes/index.ts @@ -32,22 +32,21 @@ export const apiRoutes: IApiRoutes = { formData.append("file", file); // Define what happens on successful data submission - xhr.addEventListener("load", e => { + xhr.addEventListener("load", (e) => { if (!e.target) return reject(Error("No upload responseText")); // ### Pending bug: .responseText is not typed in XMLHttpRequestEventTarget + // eslint-disable-next-line @typescript-eslint/no-explicit-any const fileId = (e.target as any).responseText; // if responseText is not a 32bytes hex, abort - if (!/[0-9A-Fa-f]{64}/.test(fileId)) - return reject(Error(`Wrong response: ${fileId}`)); + if (!/[0-9A-Fa-f]{64}/.test(fileId)) return reject(Error(`Wrong response: ${fileId}`)); resolve({ fileId }); }); // Define what happens in case of error - xhr.addEventListener("error", _e => reject(Error("Error loading file"))); + xhr.addEventListener("error", () => reject(Error("Error loading file"))); - if (xhr.upload) - xhr.upload.addEventListener("progress", onProgress, false); + if (xhr.upload) xhr.upload.addEventListener("progress", onProgress, false); // Set up our request xhr.open("POST", apiUrls.upload); diff --git a/packages/admin-ui/src/api/rpc.ts b/packages/admin-ui/src/api/rpc.ts index 724503e67..9b43ba83b 100644 --- a/packages/admin-ui/src/api/rpc.ts +++ b/packages/admin-ui/src/api/rpc.ts @@ -11,7 +11,7 @@ let apiStarted = false; export const apiRpc: IApiRpc = { async call(payload: RpcPayload) { const socket = setupSocket(); - return await new Promise>(resolve => { + return await new Promise>((resolve) => { socket.emit("rpc", payload, resolve); }); }, @@ -26,7 +26,7 @@ export const apiRpc: IApiRpc = { const socket = setupSocket(); - socket.on("connect", function() { + socket.on("connect", function () { for (const route of Object.keys(subscriptionsData)) { socket.on(route, (...args: Args) => { apiEventBridge.emit(route, ...args); @@ -53,7 +53,6 @@ export const apiRpc: IApiRpc = { function setupSocket(): Socket { if (!socketGlobal) { - /* eslint-disable-next-line no-console */ console.log("Connecting API with Socket.io to", socketIoUrl); socketGlobal = io(socketIoUrl); } diff --git a/packages/admin-ui/src/api/subscriptions.ts b/packages/admin-ui/src/api/subscriptions.ts index 7a37ca891..c0315fb16 100644 --- a/packages/admin-ui/src/api/subscriptions.ts +++ b/packages/admin-ui/src/api/subscriptions.ts @@ -1,10 +1,7 @@ import { store } from "../store"; // Actions to push received content import { pushNotification } from "services/notifications/actions"; -import { - clearIsInstallingLog, - updateIsInstallingLog -} from "services/isInstallingLogs/actions"; +import { clearIsInstallingLog, updateIsInstallingLog } from "services/isInstallingLogs/actions"; import { updateVolumes, setSystemInfo } from "services/dappnodeStatus/actions"; import { setDnpInstalled } from "services/dnpInstalled/actions"; import { updateDnpDirectory } from "services/dnpDirectory/actions"; @@ -12,39 +9,38 @@ import { updateDnpRegistry } from "services/dnpRegistry/actions"; import { Subscriptions } from "@dappnode/types"; export function mapSubscriptionsToRedux(subscriptions: Subscriptions): void { - subscriptions.directory.on(directoryDnps => { + subscriptions.directory.on((directoryDnps) => { store.dispatch(updateDnpDirectory(directoryDnps)); }); - subscriptions.registry.on(registryDnps => { + subscriptions.registry.on((registryDnps) => { store.dispatch(updateDnpRegistry(registryDnps)); }); - subscriptions.packages.on(dnpsInstalled => { + subscriptions.packages.on((dnpsInstalled) => { store.dispatch(setDnpInstalled(dnpsInstalled)); }); - subscriptions.progressLog.on(progressLog => { + subscriptions.progressLog.on((progressLog) => { const { id, dnpName, message: log, clear } = progressLog; if (clear) store.dispatch(clearIsInstallingLog({ id })); else store.dispatch(updateIsInstallingLog({ id, dnpName, log })); }); - subscriptions.pushNotification.on(notification => { + subscriptions.pushNotification.on((notification) => { store.dispatch(pushNotification(notification)); }); - subscriptions.systemInfo.on(systemInfo => { + subscriptions.systemInfo.on((systemInfo) => { store.dispatch(setSystemInfo(systemInfo)); }); - subscriptions.volumes.on(volumes => { + subscriptions.volumes.on((volumes) => { store.dispatch(updateVolumes(volumes)); }); // The DAPPMANAGER may ask the UI to reload - subscriptions.reloadClient.on(data => { - /* eslint-disable-next-line no-console */ + subscriptions.reloadClient.on((data) => { console.log(`DAPPMANAGER triggered a client reload`, data); // If we needed to pull the document from the web-server again (such as where // the document contents change dynamically) we would pass the argument as 'true'. diff --git a/packages/admin-ui/src/api/utils.ts b/packages/admin-ui/src/api/utils.ts index 079291fc0..5714054dc 100644 --- a/packages/admin-ui/src/api/utils.ts +++ b/packages/admin-ui/src/api/utils.ts @@ -17,19 +17,12 @@ function isCallDisconnectedError(e: Error): boolean { * Wrapper to convert API calls that may throw a callee disconnected error * into successful resolved calls */ -export function continueIfCalleDisconnected( - fn: () => Promise, - dnpName: string -): () => Promise { - return async function(...args) { +export function continueIfCalleDisconnected(fn: () => Promise, dnpName: string): () => Promise { + return async function (...args) { try { await fn(...args); } catch (e) { - if ( - isCallDisconnectedError(e) && - (!dnpName || dnpName === dappmanagerDnpName || dnpName === coreDnpName) - ) - return; + if (isCallDisconnectedError(e) && (!dnpName || dnpName === dappmanagerDnpName || dnpName === coreDnpName)) return; else throw e; } }; diff --git a/packages/admin-ui/src/components/AlertDismissible.tsx b/packages/admin-ui/src/components/AlertDismissible.tsx index 0276a7e78..5f4afba1b 100644 --- a/packages/admin-ui/src/components/AlertDismissible.tsx +++ b/packages/admin-ui/src/components/AlertDismissible.tsx @@ -12,12 +12,7 @@ export const AlertDismissible: React.FC<{ }> = ({ children, className, variant }) => { const [show, setShow] = useState(true); return show ? ( - setShow(false)} - dismissible - className={className} - > + setShow(false)} dismissible className={className}> {children} ) : null; diff --git a/packages/admin-ui/src/components/Button.tsx b/packages/admin-ui/src/components/Button.tsx index 2f936b765..c05fc1d58 100644 --- a/packages/admin-ui/src/components/Button.tsx +++ b/packages/admin-ui/src/components/Button.tsx @@ -1,8 +1,6 @@ import React from "react"; import { IconType } from "react-icons/lib"; -import ButtonBootstap, { - ButtonProps as ButtonBootstrapProps -} from "react-bootstrap/esm/Button"; +import ButtonBootstap, { ButtonProps as ButtonBootstrapProps } from "react-bootstrap/esm/Button"; import { joinCssClass } from "utils/css"; import "./button.scss"; @@ -29,9 +27,7 @@ interface ButtonProps { Icon?: IconType; } -const Button: React.FC> = ({ +const Button: React.FC> = ({ variant = defaultVariant, children, pill, diff --git a/packages/admin-ui/src/components/ConfirmDialog.tsx b/packages/admin-ui/src/components/ConfirmDialog.tsx index 965c41c2c..7987056b8 100644 --- a/packages/admin-ui/src/components/ConfirmDialog.tsx +++ b/packages/admin-ui/src/components/ConfirmDialog.tsx @@ -67,28 +67,20 @@ function Modal({
{ + onClick={(e) => { if (modalEl.current === e.target) onClose(); }} >
{title &&

{title}

} - {text && ( -
- {typeof text === "string" ? : text} -
- )} + {text &&
{typeof text === "string" ? : text}
} {list && Array.isArray(list) && list.length > 0 && (
{list.map((item, i) => (
{item.title}
- {typeof item.body === "string" ? ( - - ) : ( - item.body - )} + {typeof item.body === "string" ? : item.body}
))} @@ -127,14 +119,11 @@ export function confirm(props: ConfirmDialogProps) { document.body.appendChild(root); } // render (or re-render) and mount the dialog - render( - unmountComponentAtNode(root)} />, - root - ); + render( unmountComponentAtNode(root)} />, root); } export function confirmPromise(props: ConfirmDialogProps): Promise { - return new Promise(resolve => + return new Promise((resolve) => confirm({ ...props, onClick: resolve diff --git a/packages/admin-ui/src/components/ErrorBoundary.tsx b/packages/admin-ui/src/components/ErrorBoundary.tsx index a38fe2754..8d5bfca3c 100644 --- a/packages/admin-ui/src/components/ErrorBoundary.tsx +++ b/packages/admin-ui/src/components/ErrorBoundary.tsx @@ -1,7 +1,8 @@ import React from "react"; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export default class ErrorBoundary extends React.Component { - constructor(props: {}) { + constructor(props: object) { super(props); this.state = { error: null, errorInfo: null }; } diff --git a/packages/admin-ui/src/components/ErrorView.tsx b/packages/admin-ui/src/components/ErrorView.tsx index 4e3c3006b..24361c9d3 100644 --- a/packages/admin-ui/src/components/ErrorView.tsx +++ b/packages/admin-ui/src/components/ErrorView.tsx @@ -31,8 +31,7 @@ export default function ErrorView({ } function parseError(error: Error | string) { - if (error instanceof Error) - return { message: error.message, detail: error.stack }; + if (error instanceof Error) return { message: error.message, detail: error.stack }; if (typeof error === "string") return { message: error }; return { message: JSON.stringify(error), detail: "" }; } diff --git a/packages/admin-ui/src/components/EthMultiClient.tsx b/packages/admin-ui/src/components/EthMultiClient.tsx index 42b56d0f1..4bd6c75e2 100644 --- a/packages/admin-ui/src/components/EthMultiClient.tsx +++ b/packages/admin-ui/src/components/EthMultiClient.tsx @@ -22,8 +22,7 @@ import { getEthClientTarget } from "services/dappnodeStatus/selectors"; export const fallbackToBoolean = (fallback: EthClientFallback): boolean => fallback === "on" ? true : fallback === "off" ? false : false; -export const booleanToFallback = (bool: boolean): EthClientFallback => - bool ? "on" : "off"; +export const booleanToFallback = (bool: boolean): EthClientFallback => (bool ? "on" : "off"); /** * Get client type from a target @@ -37,9 +36,7 @@ export function getEthClientType(target: Eth2ClientTarget): string { } } -export function getEthClientPrettyStatusError( - statusError: EthClientStatusError -): string { +export function getEthClientPrettyStatusError(statusError: EthClientStatusError): string { switch (statusError.code) { case "UNKNOWN_ERROR": return `unknown error: ${(statusError.error || {}).message}`; @@ -186,7 +183,7 @@ function EthMultiClients({ } const getSvgClass = (_highlight: keyof EthClientDataStats) => joinCssClass({ - active: highlights.find(highlight => highlight === _highlight) + active: highlights.find((highlight) => highlight === _highlight) }); return ( )} - {selected && - selectedTarget && - selectedTarget !== "remote" && - options !== "remote" && ( - <> - { + const newEc = Object.values(ExecutionClientMainnet).find((ec) => prettyDnpName(ec) === newOpt); + if (newEc) { + onTargetChange({ + ...(selectedTarget || {}), + execClient: newEc + }); } - options={options.execClients - .filter(Boolean) - .map(prettyDnpName)} - onValueChange={(newOpt: string) => { - const newEc = Object.values(ExecutionClientMainnet).find( - ec => prettyDnpName(ec) === newOpt - ); - if (newEc) { - onTargetChange({ - ...(selectedTarget || {}), - execClient: newEc - }); - } - }} - prepend="Execution client" - /> + }} + prepend="Execution client" + /> - + onValueChange(e.target.value)} - > - {options.map(option => ( + @@ -27,11 +23,7 @@ export default function Select({ return (
- {typeof prepend === "string" ? ( - {prepend} - ) : ( - prepend - )} + {typeof prepend === "string" ? {prepend} : prepend}
{select}
diff --git a/packages/admin-ui/src/components/SetupWizard/EditorAdvanced.tsx b/packages/admin-ui/src/components/SetupWizard/EditorAdvanced.tsx index edcb9d01d..f53e99674 100644 --- a/packages/admin-ui/src/components/SetupWizard/EditorAdvanced.tsx +++ b/packages/admin-ui/src/components/SetupWizard/EditorAdvanced.tsx @@ -14,13 +14,7 @@ interface EditableTableProps { setValue: (valueId: string, value: string) => void; } -const EditableTable: React.FC = ({ - headers, - placeholder, - values, - disabledValues, - setValue -}) => { +const EditableTable: React.FC = ({ headers, placeholder, values, disabledValues, setValue }) => { if (!values || isEmpty(values)) return null; const valuesArray = orderBy( Object.entries(values).map(([key, value]) => ({ id: key, value })), @@ -30,7 +24,7 @@ const EditableTable: React.FC = ({ - {headers.map(header => ( + {headers.map((header) => ( @@ -71,54 +65,46 @@ export function EditorAdvanced({
{prettyDnpName(dnpName)}
{dnpSettings.environment && - Object.entries(dnpSettings.environment).map( - ([serviceName, environment]) => ( -
-
- {prettyDnpName(serviceName)} -
- - onChange({ - [dnpName]: { - environment: { - [serviceName]: { [valueId]: envValue } - } + Object.entries(dnpSettings.environment).map(([serviceName, environment]) => ( +
+
{prettyDnpName(serviceName)}
+ + onChange({ + [dnpName]: { + environment: { + [serviceName]: { [valueId]: envValue } } - }) - } - /> -
- ) - )} + } + }) + } + /> +
+ ))} {dnpSettings.portMappings && - Object.entries(dnpSettings.portMappings).map( - ([serviceName, portMappings]) => ( -
-
- {prettyDnpName(serviceName)} -
- - onChange({ - [dnpName]: { - portMappings: { - [serviceName]: { [valueId]: hostPort } - } + Object.entries(dnpSettings.portMappings).map(([serviceName, portMappings]) => ( +
+
{prettyDnpName(serviceName)}
+ + onChange({ + [dnpName]: { + portMappings: { + [serviceName]: { [valueId]: hostPort } } - }) - } - /> -
- ) - )} + } + }) + } + /> +
+ ))} {/* Rules for volumes: Can't be edited if they are already set */} (
{prettyDnpName(dnpName)}
- {setupWizardDnp.fields.map(field => { + {setupWizardDnp.fields.map((field) => { const { id } = field; - const ownErrors = errors.filter( - error => error.dnpName === dnpName && error.id === id - ); + const ownErrors = errors.filter((error) => error.dnpName === dnpName && error.id === id); return (
{field.title}
@@ -37,11 +35,9 @@ export function EditorV2({ - onNewFormData({ [dnpName]: { [id]: newValue } }) - } + onValueChange={(newValue) => onNewFormData({ [dnpName]: { [id]: newValue } })} /> - {ownErrors.map(error => ( + {ownErrors.map((error) => (
{error.message}
diff --git a/packages/admin-ui/src/components/SetupWizard/InputField.tsx b/packages/admin-ui/src/components/SetupWizard/InputField.tsx index 4278d96cc..09747b0b5 100644 --- a/packages/admin-ui/src/components/SetupWizard/InputField.tsx +++ b/packages/admin-ui/src/components/SetupWizard/InputField.tsx @@ -16,36 +16,14 @@ export default function InputField({ value: string; onValueChange: (newValue: string) => void; }) { - if ( - !field.target || - field.target.type === "environment" || - field.target.type === "portMapping" - ) { - if (field.enum) - return ( - - ); - else if (isSecretField(field)) - return ; + if (!field.target || field.target.type === "environment" || field.target.type === "portMapping") { + if (field.enum) return ; + else if (isSecretField(field)) return ; else return ; } else if (field.target.type === "fileUpload") { - return ( - - ); - } else if ( - field.target.type === "namedVolumeMountpoint" || - field.target.type === "allNamedVolumesMountpoint" - ) { - return ( - - ); + return ; + } else if (field.target.type === "namedVolumeMountpoint" || field.target.type === "allNamedVolumesMountpoint") { + return ; } else { return
Unknown target type
; } @@ -55,11 +33,6 @@ function isSecretField(field: SetupWizardField): boolean { if (field.secret !== undefined) return field.secret; return ( - isSecret(field.id) || - Boolean( - field.target && - field.target.type === "environment" && - isSecret(field.target.name) - ) + isSecret(field.id) || Boolean(field.target && field.target.type === "environment" && isSecret(field.target.name)) ); } diff --git a/packages/admin-ui/src/components/SetupWizard/InputFieldFile.tsx b/packages/admin-ui/src/components/SetupWizard/InputFieldFile.tsx index 197e9a718..4c2dda25f 100644 --- a/packages/admin-ui/src/components/SetupWizard/InputFieldFile.tsx +++ b/packages/admin-ui/src/components/SetupWizard/InputFieldFile.tsx @@ -10,17 +10,14 @@ function fileToDataURL(files: FileList): Promise { return new Promise((resolve, reject) => { const reader = new window.FileReader(); reader.onerror = reject; - reader.onload = event => { - if (event.target && event.target.result) - resolve(addNameToDataURL(event.target.result.toString(), file.name)); + reader.onload = (event) => { + if (event.target && event.target.result) resolve(addNameToDataURL(event.target.result.toString(), file.name)); }; reader.readAsDataURL(file); }); } -function dataURLtoFile( - dataURL: string -): { +function dataURLtoFile(dataURL: string): { name: string; size: number; type: string; @@ -32,7 +29,7 @@ function dataURLtoFile( // Get mime-type from params const type = params[0].replace("data:", ""); // Filter the name property from params - const properties = params.filter(param => { + const properties = params.filter((param) => { return param.split("=")[0] === "name"; }); // Look for the name and use unknown if no name property. @@ -91,7 +88,7 @@ export default function InputFieldFile({ type="file" className="custom-file-input" accept={accept} - onChange={e => { + onChange={(e) => { if (e.target.files) onSelectFile(e.target.files); }} disabled={processing} @@ -100,8 +97,8 @@ export default function InputFieldFile({ {processing ? "Loading file..." : file - ? `${decodeURIComponent(file.name)} - ${humanFS(file.size)}` - : "Choose file"} + ? `${decodeURIComponent(file.name)} - ${humanFS(file.size)}` + : "Choose file"}
); diff --git a/packages/admin-ui/src/components/SetupWizard/InputFieldSelect.tsx b/packages/admin-ui/src/components/SetupWizard/InputFieldSelect.tsx index 99573e9b5..89762f70f 100644 --- a/packages/admin-ui/src/components/SetupWizard/InputFieldSelect.tsx +++ b/packages/admin-ui/src/components/SetupWizard/InputFieldSelect.tsx @@ -13,10 +13,7 @@ export default function InputFieldSelect({ return ( { {isEmpty(categories) && registry.length ? (
) : ( - + )} {ethClientWarning && ( - The DAppStore will not work temporarily. Eth client not available:{" "} - {ethClientWarning} + The DAppStore will not work temporarily. Eth client not available: {ethClientWarning}
- Enable the{" "} - - repository source fallback - {" "} - to use the DAppStore meanwhile + Enable the repository source fallback to use the DAppStore + meanwhile
)} @@ -149,9 +134,7 @@ export const InstallerPublic: React.FC = () => { showErrorDnps ? ( ) : ( - + ) ) : null}
diff --git a/packages/admin-ui/src/pages/installer/helpers/filterDirectory.ts b/packages/admin-ui/src/pages/installer/helpers/filterDirectory.ts index c56e365b0..809d463f7 100644 --- a/packages/admin-ui/src/pages/installer/helpers/filterDirectory.ts +++ b/packages/admin-ui/src/pages/installer/helpers/filterDirectory.ts @@ -25,17 +25,13 @@ export default function filterDirectory({ query: string; selectedCategories: SelectedCategories; }): DirectoryItem[] { - const isSomeCategorySelected = Object.values(selectedCategories).reduce( - (acc, val) => acc || val, - false - ); + const isSomeCategorySelected = Object.values(selectedCategories).reduce((acc, val) => acc || val, false); return directory - .filter(dnp => !query || includesSafe(dnp, query)) + .filter((dnp) => !query || includesSafe(dnp, query)) .filter( - dnp => + (dnp) => !isSomeCategorySelected || - (dnp.status === "ok" && - (dnp.categories || []).some(category => selectedCategories[category])) + (dnp.status === "ok" && (dnp.categories || []).some((category) => selectedCategories[category])) ); } @@ -46,6 +42,7 @@ export default function filterDirectory({ * @param sourceObj = { hello: "world" } * @param target = "hell" */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function includesSafe(sourceObj: any, target: string): boolean { try { return JSON.stringify(sourceObj).includes(target); diff --git a/packages/admin-ui/src/pages/installer/parsers/formDataErrors.ts b/packages/admin-ui/src/pages/installer/parsers/formDataErrors.ts index f0877ad03..f70fd50bf 100644 --- a/packages/admin-ui/src/pages/installer/parsers/formDataErrors.ts +++ b/packages/admin-ui/src/pages/installer/parsers/formDataErrors.ts @@ -17,19 +17,13 @@ const isAbsolute = (path: string) => /^\/[^\/]+/.test(path); * Enforces rules on user settings: * - namedVolumeMountpoints: must be absolute paths. Renaming for a different named volume is not allowed */ -export function getUserSettingsDataErrors( - dataAllDnps: UserSettingsAllDnps -): string[] { +export function getUserSettingsDataErrors(dataAllDnps: UserSettingsAllDnps): string[] { const errors: string[] = []; for (const [dnpName, data] of Object.entries(dataAllDnps)) { if (data.namedVolumeMountpoints) { - for (const [volName, volPath] of Object.entries( - data.namedVolumeMountpoints - )) { + for (const [volName, volPath] of Object.entries(data.namedVolumeMountpoints)) { if (volPath && !isAbsolute(volPath)) - errors.push( - `Mountpoint path for '${dnpName}' '${volName}' must be an absolute path` - ); + errors.push(`Mountpoint path for '${dnpName}' '${volName}' must be an absolute path`); } } } @@ -48,8 +42,7 @@ export function parseSetupWizardErrors( const dataErrors: SetupWizardError[] = []; for (const [dnpName, setupWizardDnp] of Object.entries(setupWizard)) { for (const field of setupWizardDnp.fields) { - const value = - (formData[dnpName] ? formData[dnpName][field.id] : "") || ""; + const value = (formData[dnpName] ? formData[dnpName][field.id] : "") || ""; const addError = (type: SetupWizardErrorType, message: string) => dataErrors.push({ dnpName, @@ -67,8 +60,7 @@ export function parseSetupWizardErrors( } else if (field.pattern) { const regExp = new RegExp(field.pattern); if (!regExp.test(value)) - if (field.patternErrorMessage) - addError("pattern", field.patternErrorMessage); + if (field.patternErrorMessage) addError("pattern", field.patternErrorMessage); else addError("pattern", `Must match pattern '${field.pattern}'`); } } diff --git a/packages/admin-ui/src/pages/installer/parsers/formDataParser.ts b/packages/admin-ui/src/pages/installer/parsers/formDataParser.ts index 798ded0d8..b5d807d7b 100644 --- a/packages/admin-ui/src/pages/installer/parsers/formDataParser.ts +++ b/packages/admin-ui/src/pages/installer/parsers/formDataParser.ts @@ -1,11 +1,7 @@ import { mapValues, isEmpty } from "lodash-es"; import deepmerge from "deepmerge"; import Ajv from "ajv"; -import { - UserSettingsAllDnps, - UserSettings, - SetupWizardAllDnps -} from "@dappnode/types"; +import { UserSettingsAllDnps, UserSettings, SetupWizardAllDnps } from "@dappnode/types"; import { SetupWizardFormDataReturn } from "../types"; import { SetupSchema } from "@dappnode/types"; import { SetupTargetAllDnps } from "types"; @@ -16,10 +12,8 @@ const ajv = new Ajv({ allErrors: true }); * Extract setup target objects from the setupWizard * @param setupWizard */ -export function setupWizardToSetupTarget( - setupWizard: SetupWizardAllDnps -): SetupTargetAllDnps { - return mapValues(setupWizard, setupWizardDnp => +export function setupWizardToSetupTarget(setupWizard: SetupWizardAllDnps): SetupTargetAllDnps { + return mapValues(setupWizard, (setupWizardDnp) => setupWizardDnp.fields.reduce((targets, field) => { return { ...targets, [field.id]: field.target }; }, {}) @@ -50,7 +44,6 @@ export function formDataToUserSettings( if (target && target.type) switch (target.type) { case "environment": - const envValue = value; if (target.name) /** * deepmerge function joins the properties of two objects @@ -61,31 +54,26 @@ export function formDataToUserSettings( userSettings.environment = deepmerge( userSettings.environment || {}, getServicesNames(target.service || dnpName, { - [target.name]: envValue + [target.name]: value }) ); break; case "portMapping": - const hostPort = value; if (target.containerPort) - userSettings.portMappings = deepmerge( - userSettings.portMappings || {}, - { - [target.service || dnpName]: { - [target.containerPort]: hostPort - } + userSettings.portMappings = deepmerge(userSettings.portMappings || {}, { + [target.service || dnpName]: { + [target.containerPort]: value } - ); + }); break; case "namedVolumeMountpoint": { const mountpointHostPath = value; if (target.volumeName) - userSettings.namedVolumeMountpoints = deepmerge( - userSettings.namedVolumeMountpoints || {}, - { [target.volumeName]: mountpointHostPath } - ); + userSettings.namedVolumeMountpoints = deepmerge(userSettings.namedVolumeMountpoints || {}, { + [target.volumeName]: mountpointHostPath + }); break; } @@ -96,12 +84,10 @@ export function formDataToUserSettings( } case "fileUpload": - const fileDataUrl = value; if (target.path) - userSettings.fileUploads = deepmerge( - userSettings.fileUploads || {}, - { [target.service || dnpName]: { [target.path]: fileDataUrl } } - ); + userSettings.fileUploads = deepmerge(userSettings.fileUploads || {}, { + [target.service || dnpName]: { [target.path]: value } + }); break; } } @@ -138,26 +124,21 @@ export function userSettingsToFormData( if (target && target.type) { switch (target.type) { case "environment": - const serviceNames = target.service || dnpName; /** * The following loop check if the field service is an array or a string in order to * define an environment object with its properties * */ - for (let service of Array.isArray(serviceNames) - ? serviceNames - : [serviceNames]) { + for (const service of Array.isArray(target.service) ? target.service : [target.service || dnpName]) { const environmentService = environment[service]; - if (hasProperty(target.name, environmentService)) - formDataDnp[propId] = environmentService[target.name]; + if (hasProperty(target.name, environmentService)) formDataDnp[propId] = environmentService[target.name]; } break; case "portMapping": - const portMappingsService = portMappings[target.service || dnpName]; - if (hasProperty(target.containerPort, portMappingsService)) - formDataDnp[propId] = portMappingsService[target.containerPort]; + if (hasProperty(target.containerPort, portMappings[target.service || dnpName])) + formDataDnp[propId] = portMappings[target.service || dnpName][target.containerPort]; break; case "namedVolumeMountpoint": { @@ -172,9 +153,8 @@ export function userSettingsToFormData( } case "fileUpload": - const fileUploadsService = fileUploads[target.service || dnpName]; - if (hasProperty(target.path, fileUploadsService)) - formDataDnp[propId] = fileUploadsService[target.path]; + if (hasProperty(target.path, fileUploads[target.service || dnpName])) + formDataDnp[propId] = fileUploads[target.service || dnpName][target.path]; break; } } @@ -195,7 +175,7 @@ export function filterActiveSetupWizard( ): SetupWizardAllDnps { return mapValues(setupWizard, (setupWizardDnp, dnpName) => ({ ...setupWizardDnp, - fields: setupWizardDnp.fields.filter(field => { + fields: setupWizardDnp.fields.filter((field) => { if (field.if) { try { return ajv.validate(correctJsonSchema(field.if), formData[dnpName]); @@ -213,10 +193,7 @@ export function filterActiveSetupWizard( /** * Util: Type-safe wrapper around `key in obj` which will be ok whatever type obj is */ -function hasProperty( - key: string, - obj: { [key: string]: string } | undefined -): boolean { +function hasProperty(key: string, obj: { [key: string]: string } | undefined): boolean { return Boolean(key && obj && key in obj); } @@ -227,6 +204,7 @@ function hasProperty( * If it doesn't follow this structure, it will be forced * @param schemaOrProperties */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any function correctJsonSchema(schemaOrProperties: any): SetupSchema { if (typeof schemaOrProperties.properties === "object") { const schema = schemaOrProperties; @@ -252,9 +230,7 @@ export function isSetupWizardEmpty(setupWizard?: SetupWizardAllDnps): boolean { return ( !setupWizard || isEmpty(setupWizard) || - Object.values(setupWizard).every( - setupWizardDnp => isEmpty(setupWizardDnp) || !setupWizardDnp.fields.length - ) + Object.values(setupWizard).every((setupWizardDnp) => isEmpty(setupWizardDnp) || !setupWizardDnp.fields.length) ); } @@ -277,14 +253,9 @@ interface EnvVarObject { * @returns EnvVarObject */ -function getServicesNames( - serviceNames: string | string[], - envValue: T -): EnvVarObject { - let envObj: EnvVarObject = {}; - for (let service of Array.isArray(serviceNames) - ? serviceNames - : [serviceNames]) { +function getServicesNames(serviceNames: string | string[], envValue: T): EnvVarObject { + const envObj: EnvVarObject = {}; + for (const service of Array.isArray(serviceNames) ? serviceNames : [serviceNames]) { envObj[service] = envValue; } return envObj; diff --git a/packages/admin-ui/src/pages/packages/actions.ts b/packages/admin-ui/src/pages/packages/actions.ts index 8749b56ca..b76743763 100644 --- a/packages/admin-ui/src/pages/packages/actions.ts +++ b/packages/admin-ui/src/pages/packages/actions.ts @@ -16,32 +16,24 @@ export async function packageSetEnvironment( envNames?: string[] ): Promise { const envList = (envNames || []).join(", "); - await withToastNoThrow( - () => api.packageSetEnvironment({ dnpName, environmentByService }), - { - message: `Updating ${prettyDnpName(dnpName)} ${envList}...`, - onSuccess: `Updated ${prettyDnpName(dnpName)} ${envList}` - } - ); + await withToastNoThrow(() => api.packageSetEnvironment({ dnpName, environmentByService }), { + message: `Updating ${prettyDnpName(dnpName)} ${envList}...`, + onSuccess: `Updated ${prettyDnpName(dnpName)} ${envList}` + }); } // Used in package interface / controls -export async function packageRestart( - dnp: InstalledPackageData, - container?: PackageContainer -): Promise { +export async function packageRestart(dnp: InstalledPackageData, container?: PackageContainer): Promise { // Restart only a single service container const serviceNames = container && [container.serviceName]; const dnpName = dnp.dnpName; - const name = container - ? [prettyFullName(container)].join(" ") - : prettyDnpName(dnpName); + const name = container ? [prettyFullName(container)].join(" ") : prettyDnpName(dnpName); // If the DNP is not gracefully stopped, ask for confirmation to reset - if (dnp && dnp.containers.some(container => container.running)) - await new Promise(resolve => { + if (dnp && dnp.containers.some((container) => container.running)) + await new Promise((resolve) => { confirm({ title: `Restarting ${name}`, text: `This action cannot be undone. If this DAppNode Package holds state, it may be lost.`, @@ -52,10 +44,7 @@ export async function packageRestart( await withToastNoThrow( // If call errors with "callee disconnected", resolve with success - continueIfCalleDisconnected( - () => api.packageRestart({ dnpName, serviceNames }), - dnpName - ), + continueIfCalleDisconnected(() => api.packageRestart({ dnpName, serviceNames }), dnpName), { message: `Restarting ${name}...`, onSuccess: `Restarted ${name}` diff --git a/packages/admin-ui/src/pages/packages/components/AlertPackageUpdateAvailable.tsx b/packages/admin-ui/src/pages/packages/components/AlertPackageUpdateAvailable.tsx index 37b146205..935bd05eb 100644 --- a/packages/admin-ui/src/pages/packages/components/AlertPackageUpdateAvailable.tsx +++ b/packages/admin-ui/src/pages/packages/components/AlertPackageUpdateAvailable.tsx @@ -16,22 +16,12 @@ export function AlertPackageUpdateAvailable({ const [show, setShow] = useState(true); const navigate = useNavigate(); return show ? ( - setShow(false)} - dismissible - className="main-notification" - > + setShow(false)} dismissible className="main-notification">
- {prettyDnpName(dnpName)} update available to version{" "} - {updateAvailable.newVersion}{" "} - {updateAvailable.upstreamVersion && - `(${updateAvailable.upstreamVersion} upstream)`} + {prettyDnpName(dnpName)} update available to version {updateAvailable.newVersion}{" "} + {updateAvailable.upstreamVersion && `(${updateAvailable.upstreamVersion} upstream)`}
-
diff --git a/packages/admin-ui/src/pages/packages/components/Backup/Download.tsx b/packages/admin-ui/src/pages/packages/components/Backup/Download.tsx index d3ba40658..7ed5f36e5 100644 --- a/packages/admin-ui/src/pages/packages/components/Backup/Download.tsx +++ b/packages/admin-ui/src/pages/packages/components/Backup/Download.tsx @@ -12,13 +12,7 @@ import newTabProps from "utils/newTabProps"; import { PackageBackup } from "@dappnode/types"; import { ReqStatus } from "types"; -export function BackupDownload({ - dnpName, - backup -}: { - dnpName: string; - backup: PackageBackup[]; -}) { +export function BackupDownload({ dnpName, backup }: { dnpName: string; backup: PackageBackup[] }) { const [reqStatus, setReqStatus] = useState>({}); /** @@ -45,10 +39,7 @@ export function BackupDownload({ return ( <> -

- Download a backup of the critical files of this package in your local - machine. -

+

Download a backup of the critical files of this package in your local machine.

{reqStatus.result ? ( <> @@ -65,16 +56,11 @@ export function BackupDownload({
- This backup may contain sensitive data such as private keys. Make - sure to store it safely + This backup may contain sensitive data such as private keys. Make sure to store it safely ) : ( - )} diff --git a/packages/admin-ui/src/pages/packages/components/Backup/Restore.tsx b/packages/admin-ui/src/pages/packages/components/Backup/Restore.tsx index c310a0a48..09b0a05f9 100644 --- a/packages/admin-ui/src/pages/packages/components/Backup/Restore.tsx +++ b/packages/admin-ui/src/pages/packages/components/Backup/Restore.tsx @@ -15,13 +15,7 @@ import { PackageBackup } from "@dappnode/types"; type ProgressType = { label: string; percent?: number }; type UploadReqStatus = ReqStatus; -export function BackupRestore({ - dnpName, - backup -}: { - dnpName: string; - backup: PackageBackup[]; -}) { +export function BackupRestore({ dnpName, backup }: { dnpName: string; backup: PackageBackup[] }) { const [reqStatus, setReqStatus] = useState({}); const isOnProgress = Boolean(reqStatus.loading !== undefined); @@ -32,24 +26,19 @@ export function BackupRestore({ try { setReqStatus({ loading: { label: "Uploading file" } }); - const { fileId } = await apiRoutes.uploadFile(file, progressData => { + const { fileId } = await apiRoutes.uploadFile(file, (progressData) => { const { loaded, total } = progressData; - const percent = parseFloat( - ((100 * (loaded || 0)) / (total || 1)).toFixed(2) - ); + const percent = parseFloat(((100 * (loaded || 0)) / (total || 1)).toFixed(2)); const label = `${percent}% ${humanFS(loaded)} / ${humanFS(total)}`; setReqStatus({ loading: { percent, label } }); }); setReqStatus({ loading: { label: "Restoring backup..." } }); - await withToastNoThrow( - () => api.backupRestore({ dnpName, backup, fileId }), - { - message: `Restoring backup for ${prettyDnpName(dnpName)}...`, - onSuccess: `Restored backup for ${prettyDnpName(dnpName)}` - } - ); + await withToastNoThrow(() => api.backupRestore({ dnpName, backup, fileId }), { + message: `Restoring backup for ${prettyDnpName(dnpName)}...`, + onSuccess: `Restored backup for ${prettyDnpName(dnpName)}` + }); setReqStatus({ result: true }); } catch (e) { @@ -61,9 +50,7 @@ export function BackupRestore({ confirm({ title: `Restoring backup`, text: `This action cannot be undone. The backup data will overwrite any previously existing data.`, - list: [ - { title: "Selected file", body: `${file.name} (${humanFS(file.size)})` } - ], + list: [{ title: "Selected file", body: `${file.name} (${humanFS(file.size)})` }], label: "Restore", onClick: () => restoreBackup(file), variant: "dappnode" @@ -75,10 +62,7 @@ export function BackupRestore({ return ( <> -

- Restore an existing backup. Note that this action will overwrite - existing data. -

+

Restore an existing backup. Note that this action will overwrite existing data.

} diff --git a/packages/admin-ui/src/pages/packages/components/FileManager/To.tsx b/packages/admin-ui/src/pages/packages/components/FileManager/To.tsx index 21ae47e38..20c77ad5e 100644 --- a/packages/admin-ui/src/pages/packages/components/FileManager/To.tsx +++ b/packages/admin-ui/src/pages/packages/components/FileManager/To.tsx @@ -12,13 +12,7 @@ import { PackageContainer } from "@dappnode/types"; const fileSizeWarning = 1e6; -export function CopyFileTo({ - container, - toPathDefault -}: { - container: PackageContainer; - toPathDefault?: string; -}) { +export function CopyFileTo({ container, toPathDefault }: { container: PackageContainer; toPathDefault?: string }) { const [file, setFile] = useState(); const [toPath, setToPath] = useState(""); @@ -49,9 +43,7 @@ export function CopyFileTo({ } ); } catch (e) { - console.error( - `Error on copyFileTo ${prettyName} ${toPath}: ${e.stack}` - ); + console.error(`Error on copyFileTo ${prettyName} ${toPath}: ${e.stack}`); } } @@ -63,9 +55,8 @@ export function CopyFileTo({ { - if (e && e.target && e.target.files && e.target.files[0]) - setFile(e.target.files[0]); + onChange={(e) => { + if (e && e.target && e.target.files && e.target.files[0]) setFile(e.target.files[0]); }} />
{deletable && ( @@ -250,18 +224,14 @@ export function PortsByService({
{header} @@ -202,16 +190,10 @@ export function PortsByService({ - editPort(i, { container: parseInt(value) || undefined }) - } + onValueChange={(value: string) => editPort(i, { container: parseInt(value) || undefined })} /> ) : ( - {}} - /> + {}} /> )} @@ -221,26 +203,18 @@ export function PortsByService({ value={protocol} onValueChange={(value: string) => editPort(i, { - protocol: - value === "UDP" ? PortProtocol.UDP : PortProtocol.TCP + protocol: value === "UDP" ? PortProtocol.UDP : PortProtocol.TCP }) } /> ) : ( - {}} - /> + {}} /> )} -
- {errors.map(error => ( + {errors.map((error) => (
{error}
))}
- @@ -278,11 +248,7 @@ export function PortsByService({ * @param portMappings */ function portsToId(portMappings: PortMapping[]): string { - return portMappings - .map(({ host, container, protocol }) => - [host, container, protocol].join("") - ) - .join(""); + return portMappings.map(({ host, container, protocol }) => [host, container, protocol].join("")).join(""); } /** @@ -296,8 +262,7 @@ function getHostPortMappings(dnps: InstalledPackageData[]) { const hostPortMappings: { [portId: string]: string } = {}; for (const dnp of dnps) for (const container of dnp.containers) - for (const port of container.ports || []) - if (port.host) hostPortMappings[getHostPortId(port)] = dnp.dnpName; + for (const port of container.ports || []) if (port.host) hostPortMappings[getHostPortId(port)] = dnp.dnpName; return hostPortMappings; } diff --git a/packages/admin-ui/src/pages/packages/components/Network/index.tsx b/packages/admin-ui/src/pages/packages/components/Network/index.tsx index a36bee50a..511dce5fb 100644 --- a/packages/admin-ui/src/pages/packages/components/Network/index.tsx +++ b/packages/admin-ui/src/pages/packages/components/Network/index.tsx @@ -9,17 +9,13 @@ import { HttpsMappings } from "./HttpsMappings"; import "./network.scss"; export function Network({ containers }: { containers: PackageContainer[] }) { - const serviceNames = containers.map(c => c.serviceName); + const serviceNames = containers.map((c) => c.serviceName); const [serviceName, setServiceName] = useState(serviceNames[0]); - const container = containers.find(c => c.serviceName === serviceName); + const container = containers.find((c) => c.serviceName === serviceName); return ( <> - + {container && (
Container IP: @@ -32,19 +28,12 @@ export function Network({ containers }: { containers: PackageContainer[] }) { <> Public port mapping - + HTTPs domain mapping - + )} diff --git a/packages/admin-ui/src/pages/packages/components/NoDnpInstalled.tsx b/packages/admin-ui/src/pages/packages/components/NoDnpInstalled.tsx index 9684dc4b5..223b56d84 100644 --- a/packages/admin-ui/src/pages/packages/components/NoDnpInstalled.tsx +++ b/packages/admin-ui/src/pages/packages/components/NoDnpInstalled.tsx @@ -3,10 +3,7 @@ import { useNavigate } from "react-router-dom"; // Components import Button from "components/Button"; // Modules -import { - relativePath as installedRelativePath, - getInstallerPath -} from "pages/installer"; +import { relativePath as installedRelativePath, getInstallerPath } from "pages/installer"; // Utils import { prettyDnpName } from "utils/format"; @@ -16,15 +13,10 @@ export const NoDnpInstalled = ({ id }: { id: string }) => {

{id} is not installed

Go back to packages or click below to install it

- - +
); }; diff --git a/packages/admin-ui/src/pages/packages/components/NoPackagesYet.tsx b/packages/admin-ui/src/pages/packages/components/NoPackagesYet.tsx index ae9759124..0457d7793 100644 --- a/packages/admin-ui/src/pages/packages/components/NoPackagesYet.tsx +++ b/packages/admin-ui/src/pages/packages/components/NoPackagesYet.tsx @@ -10,12 +10,8 @@ export const NoPackagesYet = () => { return (

No installed DAppNode Packages yet

-

- If you would like install a DAppNode package, go to the DAppStore tab. -

- +

If you would like install a DAppNode package, go to the DAppStore tab.

+
); }; diff --git a/packages/admin-ui/src/pages/packages/components/PackagesList.tsx b/packages/admin-ui/src/pages/packages/components/PackagesList.tsx index 893562ee7..d64ff820a 100644 --- a/packages/admin-ui/src/pages/packages/components/PackagesList.tsx +++ b/packages/admin-ui/src/pages/packages/components/PackagesList.tsx @@ -21,56 +21,46 @@ import "./packages.scss"; export const PackagesList = ({ coreDnps }: { coreDnps: boolean }) => { const dnpsRequest = useApi.packagesGet(); - return renderResponse( - dnpsRequest, - ["Loading installed DAppNode Packages"], - dnps => { - const filteredDnps = dnps.filter( - dnp => - Boolean(coreDnps) === Boolean(dnp.isCore) && - dnp.dnpName !== coreDnpName - ); - if (!filteredDnps.length) return ; + return renderResponse(dnpsRequest, ["Loading installed DAppNode Packages"], (dnps) => { + const filteredDnps = dnps.filter((dnp) => Boolean(coreDnps) === Boolean(dnp.isCore) && dnp.dnpName !== coreDnpName); + if (!filteredDnps.length) return ; - return ( - - + return ( + + -
-
Status
-
-
Name
-
Open
-
Restart
- {sortBy(filteredDnps, dnp => dnp.dnpName).map(dnp => ( - - {/* */} - -  - - {prettyDnpName(dnp.dnpName)} - - - - - packageRestart(dnp).catch(console.error)} - /> -
-
- ))} -
-
- ); - } - ); +
+
Status
+
+
Name
+
Open
+
Restart
+ {sortBy(filteredDnps, (dnp) => dnp.dnpName).map((dnp) => ( + + {/* */} + +  + + {prettyDnpName(dnp.dnpName)} + + + + + packageRestart(dnp).catch(console.error)} + /> +
+
+ ))} +
+
+ ); + }); }; diff --git a/packages/admin-ui/src/pages/packages/components/ServiceSelector.tsx b/packages/admin-ui/src/pages/packages/components/ServiceSelector.tsx index 13298c912..3f2211436 100644 --- a/packages/admin-ui/src/pages/packages/components/ServiceSelector.tsx +++ b/packages/admin-ui/src/pages/packages/components/ServiceSelector.tsx @@ -12,18 +12,13 @@ export function ServiceSelector({ containers: PackageContainer[]; }) { // services should already be sorted from the DAPPMANAGER, `calls/packagesGet.ts` - const serviceNames = containers.map(c => c.serviceName); + const serviceNames = containers.map((c) => c.serviceName); if (serviceNames.length <= 1) return null; return (
-
); } diff --git a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeContainer.tsx b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeContainer.tsx index ea24692fc..cbea30610 100644 --- a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeContainer.tsx +++ b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeContainer.tsx @@ -2,21 +2,14 @@ import React from "react"; import { parseContainerState, PackageContainerStatus } from "./utils"; import "./stateBadge.scss"; -export function StateBadgeContainer({ - container -}: { - container: PackageContainerStatus; -}) { +export function StateBadgeContainer({ container }: { container: PackageContainerStatus }) { return ; } export function StateBadge(props: ReturnType) { const { variant, state, title } = props; return ( - + {state} ); diff --git a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeDnp.tsx b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeDnp.tsx index a955650e3..dba1e4dbc 100644 --- a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeDnp.tsx +++ b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeDnp.tsx @@ -15,15 +15,11 @@ export function StateBadgeDnp({ dnp }: { dnp: InstalledPackageData }) { return ( - {dnp.containers.map(container => { + {dnp.containers.map((container) => { const { variant, title } = parseContainerState(container); return ( - + {/* Use a single character to force consistent height */} | diff --git a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeLegend.tsx b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeLegend.tsx index cfebcc775..16978e950 100644 --- a/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeLegend.tsx +++ b/packages/admin-ui/src/pages/packages/components/StateBadge/StateBadgeLegend.tsx @@ -1,21 +1,13 @@ import React from "react"; import { InstalledPackageData } from "@dappnode/types"; -import { - allContainersHaveSameVariant, - BadgeVariant, - parseContainerState, - SimpleState -} from "./utils"; +import { allContainersHaveSameVariant, BadgeVariant, parseContainerState, SimpleState } from "./utils"; import "./stateBadge.scss"; /** * Renders a state badge color legend only if necessary */ export function StateBadgeLegend({ dnps }: { dnps: InstalledPackageData[] }) { - const states = new Map< - string, - { variant: BadgeVariant; state: SimpleState } - >(); + const states = new Map(); // Find out if a legend is needed, and for what colors for (const dnp of dnps) { diff --git a/packages/admin-ui/src/pages/packages/components/StateBadge/utils.ts b/packages/admin-ui/src/pages/packages/components/StateBadge/utils.ts index de1f2f345..3fedfcbea 100644 --- a/packages/admin-ui/src/pages/packages/components/StateBadge/utils.ts +++ b/packages/admin-ui/src/pages/packages/components/StateBadge/utils.ts @@ -1,20 +1,14 @@ import { PackageContainer } from "@dappnode/types"; -export type SimpleState = - | "stopped" - | "crashed" - | "running" - | "restarting" - | "removing"; +export type SimpleState = "stopped" | "crashed" | "running" | "restarting" | "removing"; export type BadgeVariant = "danger" | "success" | "secondary" | "warning"; -export type PackageContainerStatus = Pick< - PackageContainer, - "state" | "exitCode" ->; +export type PackageContainerStatus = Pick; -export function parseContainerState( - container: PackageContainerStatus -): { variant: BadgeVariant; state: SimpleState; title: string } { +export function parseContainerState(container: PackageContainerStatus): { + variant: BadgeVariant; + state: SimpleState; + title: string; +} { const { state, exitCode } = container; switch (state) { @@ -51,15 +45,11 @@ export function parseContainerState( } } -export function allContainersHaveSameVariant( - containers: PackageContainer[] -): boolean { +export function allContainersHaveSameVariant(containers: PackageContainer[]): boolean { return ( containers.length <= 1 || containers.every( - container => - parseContainerState(container).variant === - parseContainerState(containers[0]).variant + (container) => parseContainerState(container).variant === parseContainerState(containers[0]).variant ) ); } diff --git a/packages/admin-ui/src/pages/packages/data.ts b/packages/admin-ui/src/pages/packages/data.ts index 7a37b26d3..1b2bf8594 100644 --- a/packages/admin-ui/src/pages/packages/data.ts +++ b/packages/admin-ui/src/pages/packages/data.ts @@ -7,4 +7,3 @@ export const subPaths = { my: "my/*", system: "system/*" }; - diff --git a/packages/admin-ui/src/pages/packages/pages/ById.tsx b/packages/admin-ui/src/pages/packages/pages/ById.tsx index 436830e76..ea2546257 100644 --- a/packages/admin-ui/src/pages/packages/pages/ById.tsx +++ b/packages/admin-ui/src/pages/packages/pages/ById.tsx @@ -69,17 +69,13 @@ export const PackageById: React.FC = () => { { name: "Info", subPath: "info", - render: () => ( - - ), + render: () => , available: true }, { name: "Config", subPath: "config", - render: () => ( - - ), + render: () => , available: userSettings && !isEmpty(userSettings.environment) }, { @@ -106,20 +102,16 @@ export const PackageById: React.FC = () => { render: () => , available: true } - ].filter(route => route.available); + ].filter((route) => route.available); return ( <> <div className="horizontal-navbar"> - {availableRoutes.map(route => ( + {availableRoutes.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -127,20 +119,13 @@ export const PackageById: React.FC = () => { </div> {updateAvailable && ( - <AlertPackageUpdateAvailable - dnpName={dnpName} - updateAvailable={updateAvailable} - ></AlertPackageUpdateAvailable> + <AlertPackageUpdateAvailable dnpName={dnpName} updateAvailable={updateAvailable}></AlertPackageUpdateAvailable> )} <div className="packages-content"> <Routes> - {availableRoutes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={route.render()} - /> + {availableRoutes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={route.render()} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/packages/pages/PackagesHome.tsx b/packages/admin-ui/src/pages/packages/pages/PackagesHome.tsx index dce3db0d0..2bdfa319d 100644 --- a/packages/admin-ui/src/pages/packages/pages/PackagesHome.tsx +++ b/packages/admin-ui/src/pages/packages/pages/PackagesHome.tsx @@ -14,6 +14,7 @@ export function PackagesHome() { name: string; subPath: string; subLink: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any component: React.ComponentType<any>; }[] = [ { @@ -35,13 +36,9 @@ export function PackagesHome() { <Title title={title} /> <div className="horizontal-navbar"> - {routes.map(option => ( + {routes.map((option) => ( <button key={option.subPath} className="item-container"> - <NavLink - to={option.subLink} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={option.subLink} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {option.name} </NavLink> </button> @@ -49,7 +46,7 @@ export function PackagesHome() { </div> <Routes> - {routes.map(route => ( + {routes.map((route) => ( <Route key={route.subPath} path={route.subPath} diff --git a/packages/admin-ui/src/pages/repository/components/Eth.tsx b/packages/admin-ui/src/pages/repository/components/Eth.tsx index c5a26d973..86b1ce63e 100644 --- a/packages/admin-ui/src/pages/repository/components/Eth.tsx +++ b/packages/admin-ui/src/pages/repository/components/Eth.tsx @@ -11,10 +11,7 @@ import { changeEthClientTarget } from "pages/system/actions"; import { withToastNoThrow } from "components/toast/Toast"; import { api } from "api"; import SubTitle from "components/SubTitle"; -import { - getEthClientPrettyStatus, - EthMultiClientsAndFallback -} from "components/EthMultiClient"; +import { getEthClientPrettyStatus, EthMultiClientsAndFallback } from "components/EthMultiClient"; import Alert from "react-bootstrap/esm/Alert"; import Button from "components/Button"; import Card from "components/Card"; @@ -27,9 +24,7 @@ export default function Eth() { const ethClientStatus = useSelector(getEthClientStatus); const ethClientFallback = useSelector(getEthClientFallback); const dispatch = useDispatch(); - const [target, setTarget] = useState<Eth2ClientTarget | null>( - ethClientTarget || null - ); + const [target, setTarget] = useState<Eth2ClientTarget | null>(ethClientTarget || null); const [newEthRemoteRpc, setNewEthRemoteRpc] = useState<string>(""); useEffect(() => { @@ -47,10 +42,7 @@ export default function Eth() { } async function changeFallback(newFallback: EthClientFallback) { - await withToastNoThrow( - () => api.ethClientFallbackSet({ fallback: newFallback }), - { onError: true } - ); + await withToastNoThrow(() => api.ethClientFallbackSet({ fallback: newFallback }), { onError: true }); } /** @@ -75,17 +67,13 @@ export default function Eth() { switch (ethClientStatus.code) { case "NOT_RUNNING": return ( - <Alert variant="warning"> - Selected client is not running. Please, restart the client or select - remote - </Alert> + <Alert variant="warning">Selected client is not running. Please, restart the client or select remote</Alert> ); case "NOT_INSTALLED": case "UNINSTALLED": return ( <Alert variant="warning"> - Selected client is not installed. Please, re-install the client or - select remote + Selected client is not installed. Please, re-install the client or select remote </Alert> ); default: @@ -96,25 +84,18 @@ export default function Eth() { <Card className="dappnode-identity"> <SubTitle>Ethereum</SubTitle> <div> + <p>Dappnode uses smart contracts to access a decentralized repository of DApps.</p> <p> - Dappnode uses smart contracts to access a decentralized repository of - DApps. - </p> - <p> - Choose to connect to a <strong>remote network</strong> or use your own{" "} - <strong>local node.</strong> + Choose to connect to a <strong>remote network</strong> or use your own <strong>local node.</strong> </p> </div> {ethClientTarget && ethClientTarget !== "remote" && ( <div className="description"> - <strong>Execution Client:</strong>{" "} - {prettyDnpName(ethClientTarget.execClient)} + <strong>Execution Client:</strong> {prettyDnpName(ethClientTarget.execClient)} <br /> - <strong>Consensus Client:</strong>{" "} - {prettyDnpName(ethClientTarget.consClient)} + <strong>Consensus Client:</strong> {prettyDnpName(ethClientTarget.consClient)} <br /> - <strong>Status:</strong>{" "} - {getEthClientPrettyStatus(ethClientStatus, ethClientFallback)} + <strong>Status:</strong> {getEthClientPrettyStatus(ethClientStatus, ethClientFallback)} </div> )} @@ -135,11 +116,7 @@ export default function Eth() { <Button variant="dappnode" onClick={changeClient} - disabled={ - !target || - (isEqual(ethClientTarget, target) && - ethRemoteRpc === newEthRemoteRpc) - } + disabled={!target || (isEqual(ethClientTarget, target) && ethRemoteRpc === newEthRemoteRpc)} > Change </Button> diff --git a/packages/admin-ui/src/pages/repository/components/Ipfs.tsx b/packages/admin-ui/src/pages/repository/components/Ipfs.tsx index 24f88a8c3..1c49c67ac 100644 --- a/packages/admin-ui/src/pages/repository/components/Ipfs.tsx +++ b/packages/admin-ui/src/pages/repository/components/Ipfs.tsx @@ -11,19 +11,12 @@ import { forumUrl } from "params"; export default function Ipfs() { const ipfsRepository = useApi.ipfsClientTargetGet(); - const [ - ipfsClientTarget, - setIpfsClientTarget - ] = useState<IpfsClientTarget | null>(null); - const [ipfsGatewayTarget, setIpfsGatewayTarget] = useState<string | null>( - null - ); + const [ipfsClientTarget, setIpfsClientTarget] = useState<IpfsClientTarget | null>(null); + const [ipfsGatewayTarget, setIpfsGatewayTarget] = useState<string | null>(null); useEffect(() => { - if (ipfsRepository.data) - setIpfsClientTarget(ipfsRepository.data.ipfsClientTarget); - if (ipfsRepository.data) - setIpfsGatewayTarget(ipfsRepository.data.ipfsGateway); + if (ipfsRepository.data) setIpfsClientTarget(ipfsRepository.data.ipfsClientTarget); + if (ipfsRepository.data) setIpfsGatewayTarget(ipfsRepository.data.ipfsGateway); }, [ipfsRepository.data]); async function changeIpfsClient() { @@ -48,12 +41,9 @@ export default function Ipfs() { <Card className="dappnode-identity"> <SubTitle>IPFS</SubTitle> <div> - DAppNode uses IPFS to distribute DAppNode packages in a decentralized - way. Choose to connect to a remote IPFS gateway or use your own local - IPFS node. More information at:{" "} - <LinkDocs href={forumUrl.ipfsRemoteHowTo}> - How to use DAppNode IPFS remote - </LinkDocs> + DAppNode uses IPFS to distribute DAppNode packages in a decentralized way. Choose to connect to a remote IPFS + gateway or use your own local IPFS node. More information at:{" "} + <LinkDocs href={forumUrl.ipfsRemoteHowTo}>How to use DAppNode IPFS remote</LinkDocs> </div> {ipfsRepository.data ? ( <> diff --git a/packages/admin-ui/src/pages/repository/components/Repository.tsx b/packages/admin-ui/src/pages/repository/components/Repository.tsx index f6651136d..26b04bf37 100644 --- a/packages/admin-ui/src/pages/repository/components/Repository.tsx +++ b/packages/admin-ui/src/pages/repository/components/Repository.tsx @@ -9,6 +9,7 @@ export const Repository: React.FC = () => { const availableRoutes: { name: string; subPath: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any component: React.ComponentType<any>; }[] = [ { @@ -27,13 +28,9 @@ export const Repository: React.FC = () => { <> <Title title={title} /> <div className="horizontal-navbar"> - {availableRoutes.map(route => ( + {availableRoutes.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -42,12 +39,8 @@ export const Repository: React.FC = () => { <div className="section-spacing"> <Routes> - {availableRoutes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {availableRoutes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/rollups/components/OpCommunity.tsx b/packages/admin-ui/src/pages/rollups/components/OpCommunity.tsx index c0fc6734d..f146a959e 100644 --- a/packages/admin-ui/src/pages/rollups/components/OpCommunity.tsx +++ b/packages/admin-ui/src/pages/rollups/components/OpCommunity.tsx @@ -23,43 +23,36 @@ export default function OpCommunity() { onClick={() => setIsOpen(!isOpen)} style={{ cursor: "pointer" }} > - {isOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} - <b>Optimism Community</b> + {isOpen ? <IoIosArrowUp /> : <IoIosArrowDown />} <b>Optimism Community</b> </Accordion.Toggle> <Accordion.Collapse eventKey="0"> <Card.Body> <div style={{ marginBottom: "1rem" }}> - Dive into the next-gen blockchain scalability solution. Optimism - revolutionizes transaction speeds, ensuring a seamless and - efficient decentralized experience. Be part of the movement - that's shaping the future of blockchain. + Dive into the next-gen blockchain scalability solution. Optimism revolutionizes transaction speeds, + ensuring a seamless and efficient decentralized experience. Be part of the movement that's shaping the + future of blockchain. </div> <div> <a href="https://discord.gg/optimism" className="iconLink"> <BsDiscord style={iconStyle} /> </a> - <b>Discord</b>: Connect with fellow enthusiasts, share insights, - seek assistance, or simply engage in lively blockchain - discussions. + <b>Discord</b>: Connect with fellow enthusiasts, share insights, seek assistance, or simply engage in + lively blockchain discussions. </div> <div> <a href="https://gov.optimism.io/" className="iconLink"> <MdForum style={iconStyle} /> </a> - <b>Governance Forum</b>: Delve into deep-dive discussions, share - your perspectives, or keep abreast with the latest updates. + <b>Governance Forum</b>: Delve into deep-dive discussions, share your perspectives, or keep abreast with + the latest updates. </div> <div> - <a - href="https://vote.optimism.io" - className="iconLink" - > + <a href="https://vote.optimism.io" className="iconLink"> <MdHowToVote style={iconStyle} /> </a> - <b>Snapshot Governance Voting</b>: Have a say in the future of - Optimism. Voice your opinion and cast your vote on key - proposals. + <b>Snapshot Governance Voting</b>: Have a say in the future of Optimism. Voice your opinion and cast + your vote on key proposals. </div> </Card.Body> </Accordion.Collapse> diff --git a/packages/admin-ui/src/pages/rollups/components/Optimism.tsx b/packages/admin-ui/src/pages/rollups/components/Optimism.tsx index 51da714a7..454655f02 100644 --- a/packages/admin-ui/src/pages/rollups/components/Optimism.tsx +++ b/packages/admin-ui/src/pages/rollups/components/Optimism.tsx @@ -49,8 +49,7 @@ export default function Optimism({ description }: { description: string }) { await new Promise((resolve: (confirmOnSetConfig: boolean) => void) => { confirm({ title: `Optimism configuration`, - text: - "Are you sure you want to implement this Optimism configuration?", + text: "Are you sure you want to implement this Optimism configuration?", buttons: [ { label: "Continue", @@ -80,9 +79,7 @@ export default function Optimism({ description }: { description: string }) { rollup: newRollup ? { ...newRollup, - mainnetRpcUrl: customMainnetRpcUrl - ? customMainnetRpcUrl - : newRollup?.mainnetRpcUrl + mainnetRpcUrl: customMainnetRpcUrl ? customMainnetRpcUrl : newRollup?.mainnetRpcUrl } : undefined, executionClient: newExecClient @@ -117,11 +114,10 @@ export default function Optimism({ description }: { description: string }) { Set up your Optimism node configuration: <br /> (1) <b>Choose</b> an <b>Execution Client</b> <br /> (2) <b>Select</b> the <b>Optimism Node</b> <br /> - (3) <b>Input</b> the <b>Ethereum RPC URL</b> (Not necessary if you - are already running an Ethereum mainnet node on this Dappnode) + (3) <b>Input</b> the <b>Ethereum RPC URL</b> (Not necessary if you are already running an Ethereum mainnet + node on this Dappnode) <br /> - (4) [Optional] <b>Select Legacy Geth</b> to enable historical - transactions + (4) [Optional] <b>Select Legacy Geth</b> to enable historical transactions </p> <br /> @@ -145,18 +141,14 @@ export default function Optimism({ description }: { description: string }) { <Row className="staker-network"> <Col> <SubTitle>Execution Clients</SubTitle> - {currentOptimismConfigReq.data.executionClients.map( - (executionClient, i) => ( - <ExecutionClient - key={i} - executionClient={executionClient} - setNewExecClient={setNewExecClient} - isSelected={ - executionClient.dnpName === newExecClient?.dnpName - } - /> - ) - )} + {currentOptimismConfigReq.data.executionClients.map((executionClient, i) => ( + <ExecutionClient + key={i} + executionClient={executionClient} + setNewExecClient={setNewExecClient} + isSelected={executionClient.dnpName === newExecClient?.dnpName} + /> + ))} </Col> <Col> @@ -164,10 +156,7 @@ export default function Optimism({ description }: { description: string }) { <OptimismNode rollup={currentOptimismConfigReq.data.rollup} setNewRollup={setNewRollup} - isSelected={ - currentOptimismConfigReq.data.rollup.dnpName === - newRollup?.dnpName - } + isSelected={currentOptimismConfigReq.data.rollup.dnpName === newRollup?.dnpName} /> </Col> @@ -176,10 +165,7 @@ export default function Optimism({ description }: { description: string }) { <LegacyGeth archive={currentOptimismConfigReq.data.archive} setNewArchive={setNewArchive} - isSelected={ - currentOptimismConfigReq.data.archive.dnpName === - newArchive?.dnpName - } + isSelected={currentOptimismConfigReq.data.archive.dnpName === newArchive?.dnpName} /> </Col> </Row> @@ -207,9 +193,7 @@ export default function Optimism({ description }: { description: string }) { </> )} - {reqStatus.error && ( - <ErrorView error={reqStatus.error} hideIcon red /> - )} + {reqStatus.error && <ErrorView error={reqStatus.error} hideIcon red />} </div> </Card> ) : currentOptimismConfigReq.error ? ( diff --git a/packages/admin-ui/src/pages/rollups/components/RollupsRoot.tsx b/packages/admin-ui/src/pages/rollups/components/RollupsRoot.tsx index 11cffc372..4921d867b 100644 --- a/packages/admin-ui/src/pages/rollups/components/RollupsRoot.tsx +++ b/packages/admin-ui/src/pages/rollups/components/RollupsRoot.tsx @@ -4,40 +4,35 @@ import Title from "components/Title"; import { NavLink, Routes, Route } from "react-router-dom"; import { title } from "../data"; - const RollupsRoot: React.FC = () => { const rollupsItems: { subPath: string; title: string; component: () => React.JSX.Element; }[] = [ - { - subPath: "optimism", - title: "Optimism", - component: () => - Optimism({ - description: "Optimism is a Layer 2 scaling solution for Ethereum." - }) - }, - /* { + { + subPath: "optimism", + title: "Optimism", + component: () => + Optimism({ + description: "Optimism is a Layer 2 scaling solution for Ethereum." + }) + } + /* { title: "zkEVM", subPath: "zkevm", component: () => Zkevm() } */ - ]; + ]; return ( <> <Title title={title} /> <div className="horizontal-navbar"> - {rollupsItems.map(route => ( + {rollupsItems.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.title} </NavLink> </button> @@ -46,12 +41,8 @@ const RollupsRoot: React.FC = () => { <div className="section-spacing"> <Routes> - {rollupsItems.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={route.component()} - /> + {rollupsItems.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={route.component()} /> ))} </Routes> </div> @@ -59,4 +50,4 @@ const RollupsRoot: React.FC = () => { ); }; -export default RollupsRoot; \ No newline at end of file +export default RollupsRoot; diff --git a/packages/admin-ui/src/pages/rollups/components/ZKevmCommunity.tsx b/packages/admin-ui/src/pages/rollups/components/ZKevmCommunity.tsx index ec5526e72..291db2ab3 100644 --- a/packages/admin-ui/src/pages/rollups/components/ZKevmCommunity.tsx +++ b/packages/admin-ui/src/pages/rollups/components/ZKevmCommunity.tsx @@ -23,54 +23,35 @@ export default function ZkevmCommunity() { onClick={() => setIsOpen(!isOpen)} style={{ cursor: "pointer" }} > - {isOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} - <b>zkEVM Community</b> + {isOpen ? <IoIosArrowUp /> : <IoIosArrowDown />} <b>zkEVM Community</b> </Accordion.Toggle> <Accordion.Collapse eventKey="0"> <Card.Body> <div style={{ marginBottom: "1rem" }}> - Dive into the next-gen blockchain scalability solution. zkEVM - revolutionizes transaction speeds, ensuring a seamless and - efficient decentralized experience. Be part of the movement - that's shaping the future of blockchain. + Dive into the next-gen blockchain scalability solution. zkEVM revolutionizes transaction speeds, + ensuring a seamless and efficient decentralized experience. Be part of the movement that's shaping the + future of blockchain. </div> <div> - <a - href="https://discord.com/invite/0xPolygon" - className="iconLink" - target="_blank" - rel="noreferrer" - > + <a href="https://discord.com/invite/0xPolygon" className="iconLink" target="_blank" rel="noreferrer"> <BsDiscord style={iconStyle} /> </a> - <b>Discord</b>: Connect with fellow enthusiasts, share insights, - seek assistance, or simply engage in lively blockchain - discussions. + <b>Discord</b>: Connect with fellow enthusiasts, share insights, seek assistance, or simply engage in + lively blockchain discussions. </div> <div> - <a - href="https://forum.polygon.technology/" - className="iconLink" - target="_blank" - rel="noreferrer" - > + <a href="https://forum.polygon.technology/" className="iconLink" target="_blank" rel="noreferrer"> <MdForum style={iconStyle} /> </a> - <b>Forum</b>: The place for thoughtful discussion on Zero - Knowledge, Polygon products and Improvement Proposals + <b>Forum</b>: The place for thoughtful discussion on Zero Knowledge, Polygon products and Improvement + Proposals </div> <div> - <a - href="https://polygon.technology/governance" - className="iconLink" - target="_blank" - rel="noreferrer" - > + <a href="https://polygon.technology/governance" className="iconLink" target="_blank" rel="noreferrer"> <MdForum style={iconStyle} /> </a> - <b>Governance</b>: Participate in shaping the zkEVM and Polygon - protocols + <b>Governance</b>: Participate in shaping the zkEVM and Polygon protocols </div> </Card.Body> </Accordion.Collapse> @@ -78,4 +59,4 @@ export default function ZkevmCommunity() { </Accordion> </div> ); -} \ No newline at end of file +} diff --git a/packages/admin-ui/src/pages/rollups/components/Zkevm.tsx b/packages/admin-ui/src/pages/rollups/components/Zkevm.tsx index 3b5e52468..76e95b190 100644 --- a/packages/admin-ui/src/pages/rollups/components/Zkevm.tsx +++ b/packages/admin-ui/src/pages/rollups/components/Zkevm.tsx @@ -15,7 +15,8 @@ import ZkevmCommunity from "./ZKevmCommunity"; import { prettyDnpName } from "utils/format"; import { getInstallerPath } from "pages/installer"; -function ZkevmCard({ zkevmDnp, zkevmRunning, navigate }: { zkevmDnp: any, zkevmRunning?: boolean, navigate: any }) { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function ZkevmCard({ zkevmDnp, zkevmRunning, navigate }: { zkevmDnp: any; zkevmRunning?: boolean; navigate: any }) { const isRunning = zkevmRunning ?? false; return ( @@ -26,13 +27,17 @@ function ZkevmCard({ zkevmDnp, zkevmRunning, navigate }: { zkevmDnp: any, zkevmR <div className="title">{prettyDnpName(zkevmDnp?.dnpName)}</div> <br /> {isRunning ? ( - <Alert variant="success">The Zkevm package is currently <span className="running-text">running</span></Alert> + <Alert variant="success"> + The Zkevm package is currently <span className="running-text">running</span> + </Alert> ) : ( <Alert variant="warning">The Zkevm package is installed but not currently running.</Alert> )} {isRunning ? ( <a href={zkevmUiUrl} target="_blank" rel="noopener noreferrer"> - <Button variant="dappnode" className="fullWidthButton">Go to UI</Button> + <Button variant="dappnode" className="fullWidthButton"> + Go to UI + </Button> </a> ) : ( <Button variant="dappnode" className="fullWidthButton" onClick={() => navigate(packageInfoPath)}> @@ -47,23 +52,27 @@ export function Zkevm() { const navigate = useNavigate(); const [reqStatus] = useState<ReqStatus>({}); const dnpsRequest = useApi.packagesGet(); - const zkevmDnp = dnpsRequest.data?.find(dnp => dnp.dnpName === zkevmDnpName); - const zkevmRunning = zkevmDnp?.containers.every(container => container.running); + const zkevmDnp = dnpsRequest.data?.find((dnp) => dnp.dnpName === zkevmDnpName); + const zkevmRunning = zkevmDnp?.containers.every((container) => container.running); return ( <div> <ZkevmCommunity /> <Card> - <p>The zkEVM is a zero-knowledge powered scalability solution. You can use your dappnode to run self-sovereign tools to empower yourself. - Currently, you can deploy your own UI to Force Transactions in the zkEVM without needing the sequencer, making you uncensorable. Most of the times you won't need this, as it needs ETH in L1 to pay for it, but if something were to happen to the zkEVM, you would be able to withdraw your funds.</p> + <p> + The zkEVM is a zero-knowledge powered scalability solution. You can use your dappnode to run self-sovereign + tools to empower yourself. Currently, you can deploy your own UI to Force Transactions in the zkEVM without + needing the sequencer, making you uncensorable. Most of the times you won't need this, as it needs ETH in L1 + to pay for it, but if something were to happen to the zkEVM, you would be able to withdraw your funds. + </p> <Row> <Col md={4}> {zkevmDnp ? ( <> <SubTitle>zkEVM Token Withdrawal</SubTitle> - {zkevmRunning !== undefined && + {zkevmRunning !== undefined && ( <ZkevmCard zkevmDnp={zkevmDnp} zkevmRunning={zkevmRunning} navigate={navigate} /> - } + )} </> ) : ( <Card className="not-found"> @@ -73,7 +82,11 @@ export function Zkevm() { <div className="title">Zkevm Package Not Found</div> <br /> <p>You must install the Zkevm package</p> - <Button variant="dappnode" className="fullWidthButton" onClick={() => navigate(`${getInstallerPath(zkevmDnpName)}/${zkevmDnpName}`)}> + <Button + variant="dappnode" + className="fullWidthButton" + onClick={() => navigate(`${getInstallerPath(zkevmDnpName)}/${zkevmDnpName}`)} + > GET </Button> </Card> @@ -84,4 +97,4 @@ export function Zkevm() { <div>{reqStatus.error && <ErrorView error={reqStatus.error} hideIcon red />}</div> </div> ); -} \ No newline at end of file +} diff --git a/packages/admin-ui/src/pages/rollups/components/columns/ExecutionClient.tsx b/packages/admin-ui/src/pages/rollups/components/columns/ExecutionClient.tsx index aab178837..c7e41ac0b 100644 --- a/packages/admin-ui/src/pages/rollups/components/columns/ExecutionClient.tsx +++ b/packages/admin-ui/src/pages/rollups/components/columns/ExecutionClient.tsx @@ -16,9 +16,7 @@ export default function ExecutionClient({ ...props }: { executionClient: OptimismItem<"execution">; - setNewExecClient: React.Dispatch< - React.SetStateAction<OptimismItemOk<"execution"> | undefined> - >; + setNewExecClient: React.Dispatch<React.SetStateAction<OptimismItemOk<"execution"> | undefined>>; isSelected: boolean; }) { const navigate = useNavigate(); @@ -48,32 +46,21 @@ export default function ExecutionClient({ <div className="title">{prettyDnpName(executionClient.dnpName)} </div> - {executionClient.status === "ok" && - isSelected && - executionClient.isInstalled && - !executionClient.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(executionClient.dnpName)}/${ - executionClient.dnpName - }` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {executionClient.status === "ok" && isSelected && executionClient.isInstalled && !executionClient.isUpdated && ( + <> + <Button + onClick={() => navigate(`${getInstallerPath(executionClient.dnpName)}/${executionClient.dnpName}`)} + variant="dappnode" + > + UPDATE + </Button> + <br /> + <br /> + </> + )} {executionClient.status === "ok" && ( - <div className="description"> - {isSelected && executionClient.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && executionClient.data?.manifest?.shortDescription}</div> )} </Card> ); diff --git a/packages/admin-ui/src/pages/rollups/components/columns/LegacyGeth.tsx b/packages/admin-ui/src/pages/rollups/components/columns/LegacyGeth.tsx index ac3ead043..28c2494f7 100644 --- a/packages/admin-ui/src/pages/rollups/components/columns/LegacyGeth.tsx +++ b/packages/admin-ui/src/pages/rollups/components/columns/LegacyGeth.tsx @@ -16,9 +16,7 @@ export default function LegacyGeth({ ...props }: { archive: OptimismItem<"archive">; - setNewArchive: React.Dispatch< - React.SetStateAction<OptimismItemOk<"archive"> | undefined> - >; + setNewArchive: React.Dispatch<React.SetStateAction<OptimismItemOk<"archive"> | undefined>>; isSelected: boolean; }) { const navigate = useNavigate(); @@ -48,30 +46,21 @@ export default function LegacyGeth({ <div className="title">{prettyDnpName(archive.dnpName)} </div> - {archive.status === "ok" && - isSelected && - archive.isInstalled && - !archive.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(archive.dnpName)}/${archive.dnpName}` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {archive.status === "ok" && isSelected && archive.isInstalled && !archive.isUpdated && ( + <> + <Button + onClick={() => navigate(`${getInstallerPath(archive.dnpName)}/${archive.dnpName}`)} + variant="dappnode" + > + UPDATE + </Button> + <br /> + <br /> + </> + )} {archive.status === "ok" && ( - <div className="description"> - {isSelected && archive.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && archive.data?.manifest?.shortDescription}</div> )} </Card> ); diff --git a/packages/admin-ui/src/pages/rollups/components/columns/OptimismNode.tsx b/packages/admin-ui/src/pages/rollups/components/columns/OptimismNode.tsx index a94cbab04..e9c3c838e 100644 --- a/packages/admin-ui/src/pages/rollups/components/columns/OptimismNode.tsx +++ b/packages/admin-ui/src/pages/rollups/components/columns/OptimismNode.tsx @@ -16,26 +16,16 @@ export default function OptimismNode({ ...props }: { rollup: OptimismItem<"rollup">; - setNewRollup: React.Dispatch< - React.SetStateAction<OptimismItemOk<"rollup"> | undefined> - >; + setNewRollup: React.Dispatch<React.SetStateAction<OptimismItemOk<"rollup"> | undefined>>; isSelected: boolean; }) { const navigate = useNavigate(); return ( - <Card - {...props} - className={`optimism-node ${joinCssClass({ isSelected })}`} - shadow={isSelected} - > + <Card {...props} className={`optimism-node ${joinCssClass({ isSelected })}`} shadow={isSelected}> <div onClick={ - rollup.status === "ok" - ? isSelected - ? () => setNewRollup(undefined) - : () => setNewRollup(rollup) - : undefined + rollup.status === "ok" ? (isSelected ? () => setNewRollup(undefined) : () => setNewRollup(rollup)) : undefined } > {rollup.status === "ok" ? ( @@ -51,30 +41,18 @@ export default function OptimismNode({ <div className="title">{prettyDnpName(rollup.dnpName)} </div> </div> - {rollup.status === "ok" && - isSelected && - rollup.isInstalled && - !rollup.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(rollup.dnpName)}/${rollup.dnpName}` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {rollup.status === "ok" && isSelected && rollup.isInstalled && !rollup.isUpdated && ( + <> + <Button onClick={() => navigate(`${getInstallerPath(rollup.dnpName)}/${rollup.dnpName}`)} variant="dappnode"> + UPDATE + </Button> + <br /> + <br /> + </> + )} {rollup.status === "ok" && ( - <div className="description"> - {isSelected && rollup.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && rollup.data?.manifest?.shortDescription}</div> )} </Card> ); diff --git a/packages/admin-ui/src/pages/rollups/components/useOptimismConfig.ts b/packages/admin-ui/src/pages/rollups/components/useOptimismConfig.ts index 911b840e2..024be4726 100644 --- a/packages/admin-ui/src/pages/rollups/components/useOptimismConfig.ts +++ b/packages/admin-ui/src/pages/rollups/components/useOptimismConfig.ts @@ -1,34 +1,20 @@ import { useState, useEffect } from "react"; import { ReqStatus } from "types"; -import { - OptimismConfigGet, - OptimismConfigSet, - OptimismItemOk, - OptimismType, - OptimismItem -} from "@dappnode/types"; +import { OptimismConfigGet, OptimismConfigSet, OptimismItemOk, OptimismType, OptimismItem } from "@dappnode/types"; import { responseInterface } from "swr"; -export const useOptimismConfig = ( - currentOptimismConfigReq: responseInterface<OptimismConfigGet, Error> -) => { +export const useOptimismConfig = (currentOptimismConfigReq: responseInterface<OptimismConfigGet, Error>) => { // Request status const [reqStatus, setReqStatus] = useState<ReqStatus>({}); // Error const [ethRpcUrlError, setEthRpcUrlError] = useState<string | null>(null); // New config - const [newExecClient, setNewExecClient] = useState< - OptimismItemOk<"execution"> - >(); - const [customMainnetRpcUrl, setCustomMainnetRpcUrl] = useState<string | null>( - null - ); + const [newExecClient, setNewExecClient] = useState<OptimismItemOk<"execution">>(); + const [customMainnetRpcUrl, setCustomMainnetRpcUrl] = useState<string | null>(null); const [newRollup, setNewRollup] = useState<OptimismItemOk<"rollup">>(); const [newArchive, setNewArchive] = useState<OptimismItemOk<"archive">>(); - const [currentOptimismConfig, setCurrentOptimismConfig] = useState< - OptimismConfigSet - >(); + const [currentOptimismConfig, setCurrentOptimismConfig] = useState<OptimismConfigSet>(); // Changes const [changes, setChanges] = useState<{ isAllowed: boolean; @@ -38,31 +24,21 @@ export const useOptimismConfig = ( useEffect(() => { if (currentOptimismConfigReq.data) { - const { - executionClients, - rollup, - archive - } = currentOptimismConfigReq.data; - - const executionClient = executionClients.find(ec => - isOkSelectedInstalledAndRunning(ec) - ); + const { executionClients, rollup, archive } = currentOptimismConfigReq.data; + + const executionClient = executionClients.find((ec) => isOkSelectedInstalledAndRunning(ec)); - if (executionClient && executionClient.status === "ok") - setNewExecClient(executionClient); + if (executionClient && executionClient.status === "ok") setNewExecClient(executionClient); - if (isOkSelectedInstalledAndRunning(rollup) && rollup.status === "ok") - setNewRollup(rollup); + if (isOkSelectedInstalledAndRunning(rollup) && rollup.status === "ok") setNewRollup(rollup); - if (isOkSelectedInstalledAndRunning(archive) && archive.status === "ok") - setNewArchive(archive); + if (isOkSelectedInstalledAndRunning(archive) && archive.status === "ok") setNewArchive(archive); if (rollup.mainnetRpcUrl) setCustomMainnetRpcUrl(rollup.mainnetRpcUrl); // Set the current config to be displayed in advance view setCurrentOptimismConfig({ - executionClient: - executionClient?.status === "ok" ? executionClient : undefined, + executionClient: executionClient?.status === "ok" ? executionClient : undefined, rollup: rollup?.status === "ok" ? rollup : undefined, archive: archive?.status === "ok" ? archive : undefined }); @@ -81,14 +57,7 @@ export const useOptimismConfig = ( customMainnetRpcUrl }) ); - }, [ - currentOptimismConfig, - newExecClient, - newRollup, - newArchive, - ethRpcUrlError, - customMainnetRpcUrl - ]); + }, [currentOptimismConfig, newExecClient, newRollup, newArchive, ethRpcUrlError, customMainnetRpcUrl]); useEffect(() => { // If the URL is null, then OP Node will use the corresponding RPC to _DAPPNODE_GLOBAL_EXECUTION_CLIENT_MAINNET @@ -200,18 +169,12 @@ function validateUrl(str: string): string | null { try { new URL(str); return null; + // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (_) { return "Invalid URL"; } } -function isOkSelectedInstalledAndRunning<T extends OptimismType>( - item: OptimismItem<T> -): boolean { - return ( - item.status === "ok" && - item.isSelected && - item.isInstalled && - item.isRunning - ); +function isOkSelectedInstalledAndRunning<T extends OptimismType>(item: OptimismItem<T>): boolean { + return item.status === "ok" && item.isSelected && item.isInstalled && item.isRunning; } diff --git a/packages/admin-ui/src/pages/sdk/components/SdkHome.tsx b/packages/admin-ui/src/pages/sdk/components/SdkHome.tsx index a70a4db3b..83070f6c3 100644 --- a/packages/admin-ui/src/pages/sdk/components/SdkHome.tsx +++ b/packages/admin-ui/src/pages/sdk/components/SdkHome.tsx @@ -25,37 +25,24 @@ export default function SdkHome() { <SubTitle>What is the SDK?</SubTitle> <Card> <p> - The Dappnode Software Development Kit (dappnodesdk) is a tool to make - as simple as possible the creation of new Dappnode packages. It helps - to initialize and publish an Aragon Package Manager Repo in the - Ethereum mainnet. + The Dappnode Software Development Kit (dappnodesdk) is a tool to make as simple as possible the creation of + new Dappnode packages. It helps to initialize and publish an Aragon Package Manager Repo in the Ethereum + mainnet. </p> <p> - We have deployed a public APM (Aragon Package Manager) registry in - which anyone can create their own APM repository:{" "} - <a href="https://etherscan.io/address/public.dappnode.eth"> - public.dappnode.eth - </a> + We have deployed a public APM (Aragon Package Manager) registry in which anyone can create their own APM + repository: <a href="https://etherscan.io/address/public.dappnode.eth">public.dappnode.eth</a> </p> - <div - className="alert alert-secondary" - role="alert" - style={{ backgroundColor: "#f1f1f3" }} - > - The <strong>dappnodesdk</strong> is a <strong>CLI tool</strong>. This - section provides only additional complimentary functionality + <div className="alert alert-secondary" role="alert" style={{ backgroundColor: "#f1f1f3" }}> + The <strong>dappnodesdk</strong> is a <strong>CLI tool</strong>. This section provides only additional + complimentary functionality </div> <p> - The dappnodesdk can be installed locally with npm. Then you can - initialize a Dappnode Package, build it's docker image and publish it - on the Aragon Package Manager (APM) on the Ethereum mainnet + The dappnodesdk can be installed locally with npm. Then you can initialize a Dappnode Package, build it's + docker image and publish it on the Aragon Package Manager (APM) on the Ethereum mainnet </p> - <a - className="btn btn-outline-secondary float-right" - href={sdkGuideUrl} - {...newTabProps} - > + <a className="btn btn-outline-secondary float-right" href={sdkGuideUrl} {...newTabProps}> Full Guide </a> </Card> diff --git a/packages/admin-ui/src/pages/stakers/components/StakerNetwork.tsx b/packages/admin-ui/src/pages/stakers/components/StakerNetwork.tsx index 5a9e7f9c2..d95579549 100644 --- a/packages/admin-ui/src/pages/stakers/components/StakerNetwork.tsx +++ b/packages/admin-ui/src/pages/stakers/components/StakerNetwork.tsx @@ -25,19 +25,11 @@ import { AlertDismissible } from "components/AlertDismissible"; import { docsSmooth } from "params"; import { BsInfoCircleFill } from "react-icons/bs"; -export default function StakerNetwork({ - network, - description -}: { - network: Network; - description: string; -}) { +export default function StakerNetwork({ network, description }: { network: Network; description: string }) { // Context const { theme } = React.useContext(AppContext); - const currentStakerConfigReq = useApi.stakerConfigGet( - network - ) as responseInterface<StakerConfigGet, Error>; + const currentStakerConfigReq = useApi.stakerConfigGet(network) as responseInterface<StakerConfigGet, Error>; // hooks const { @@ -65,35 +57,30 @@ export default function StakerNetwork({ if (changes) { // TODO: Ask for removing the previous Execution Client and/or Consensus Client if its different if (!isLaunchpad) { - await new Promise( - (resolve: (confirmOnSetConfig: boolean) => void) => { - confirm({ - title: `Staker configuration`, - text: - "Are you sure you want to implement this staker configuration?", - buttons: [ - { - label: "Continue", - onClick: () => resolve(true) - } - ] - }); - } - ); - await new Promise( - (resolve: (confirmOnSetConfig: boolean) => void) => { - confirm({ - title: `Disclaimer`, - text: disclaimer, - buttons: [ - { - label: "Continue", - onClick: () => resolve(true) - } - ] - }); - } - ); + await new Promise((resolve: (confirmOnSetConfig: boolean) => void) => { + confirm({ + title: `Staker configuration`, + text: "Are you sure you want to implement this staker configuration?", + buttons: [ + { + label: "Continue", + onClick: () => resolve(true) + } + ] + }); + }); + await new Promise((resolve: (confirmOnSetConfig: boolean) => void) => { + confirm({ + title: `Disclaimer`, + text: disclaimer, + buttons: [ + { + label: "Continue", + onClick: () => resolve(true) + } + ] + }); + }); } setReqStatus({ loading: true }); @@ -136,8 +123,7 @@ export default function StakerNetwork({ {network === "prater" && ( <AlertDismissible variant="warning"> <p> - The prater network is about to be deprecated, please migrate to{" "} - <b>Holesky</b>. + The prater network is about to be deprecated, please migrate to <b>Holesky</b>. </p> </AlertDismissible> )} @@ -146,10 +132,9 @@ export default function StakerNetwork({ <AlertDismissible variant="info"> <p> <BsInfoCircleFill className="smooth-alert-icon" /> - <b>Smooth is out!</b> Discover the new MEV Smoothing Pool designed - for solo validators. It allows you to pool your MEV rewards, - ensuring consistent higher rewards. Subscribing is as easy as - changing your fee recipient!{" "} + <b>Smooth is out!</b> Discover the new MEV Smoothing Pool designed for solo validators. It allows you to + pool your MEV rewards, ensuring consistent higher rewards. Subscribing is as easy as changing your fee + recipient!{" "} <b> <a href={docsSmooth} target="_blank" rel="noopener noreferrer"> Learn more @@ -163,16 +148,15 @@ export default function StakerNetwork({ {currentStakerConfigReq.data ? ( <Card> <p> - Set up your Proof-of-Stake validator configuration for Ethereum - and Ethereum-based chains. You will need to: <br /> + Set up your Proof-of-Stake validator configuration for Ethereum and Ethereum-based chains. You will need + to: <br /> (1) Choose an Execution Layer client <br /> (2) Choose a Consensus Layer client (+ validator) <br /> - (3) Install the web3signer, which will hold the validator keys and - sign <br /> + (3) Install the web3signer, which will hold the validator keys and sign <br /> {network !== "gnosis" && network !== "lukso" && ( <> - (4) Optional; delegate block-building capacities through the - MEV Boost network and potentially profit from MEV + (4) Optional; delegate block-building capacities through the MEV Boost network and potentially profit + from MEV </> )} </p> @@ -183,34 +167,26 @@ export default function StakerNetwork({ <Row className="staker-network"> <Col> <SubTitle>Execution Clients</SubTitle> - {currentStakerConfigReq.data.executionClients.map( - (executionClient, i) => ( - <ExecutionClient - key={i} - executionClient={executionClient} - setNewExecClient={setNewExecClient} - isSelected={ - executionClient.dnpName === newExecClient?.dnpName - } - /> - ) - )} + {currentStakerConfigReq.data.executionClients.map((executionClient, i) => ( + <ExecutionClient + key={i} + executionClient={executionClient} + setNewExecClient={setNewExecClient} + isSelected={executionClient.dnpName === newExecClient?.dnpName} + /> + ))} </Col> <Col> <SubTitle>Consensus Clients</SubTitle> - {currentStakerConfigReq.data.consensusClients.map( - (consensusClient, i) => ( - <ConsensusClient - key={i} - consensusClient={consensusClient} - setNewConsClient={setNewConsClient} - isSelected={ - consensusClient.dnpName === newConsClient?.dnpName - } - /> - ) - )} + {currentStakerConfigReq.data.consensusClients.map((consensusClient, i) => ( + <ConsensusClient + key={i} + consensusClient={consensusClient} + setNewConsClient={setNewConsClient} + isSelected={consensusClient.dnpName === newConsClient?.dnpName} + /> + ))} </Col> <Col> @@ -221,24 +197,20 @@ export default function StakerNetwork({ isSelected={Boolean(newWeb3signer)} /> </Col> - {["prater", "mainnet", "holesky"].includes(network) && - currentStakerConfigReq.data.mevBoost && ( - <Col> - <SubTitle>Mev Boost</SubTitle> - <MevBoost - network={network} - mevBoost={currentStakerConfigReq.data.mevBoost} - newMevBoost={newMevBoost} - setNewMevBoost={setNewMevBoost} - newRelays={newRelays} - setNewRelays={setNewRelays} - isSelected={ - currentStakerConfigReq.data.mevBoost.dnpName === - newMevBoost?.dnpName - } - /> - </Col> - )} + {["prater", "mainnet", "holesky"].includes(network) && currentStakerConfigReq.data.mevBoost && ( + <Col> + <SubTitle>Mev Boost</SubTitle> + <MevBoost + network={network} + mevBoost={currentStakerConfigReq.data.mevBoost} + newMevBoost={newMevBoost} + setNewMevBoost={setNewMevBoost} + newRelays={newRelays} + setNewRelays={setNewRelays} + isSelected={currentStakerConfigReq.data.mevBoost.dnpName === newMevBoost?.dnpName} + /> + </Col> + )} </Row> <hr /> <div> @@ -262,9 +234,7 @@ export default function StakerNetwork({ </> )} - {reqStatus.error && ( - <ErrorView error={reqStatus.error} hideIcon red /> - )} + {reqStatus.error && <ErrorView error={reqStatus.error} hideIcon red />} </div> </Card> ) : currentStakerConfigReq.error ? ( diff --git a/packages/admin-ui/src/pages/stakers/components/StakersRoot.tsx b/packages/admin-ui/src/pages/stakers/components/StakersRoot.tsx index cff39d4c4..7be7a58fb 100644 --- a/packages/admin-ui/src/pages/stakers/components/StakersRoot.tsx +++ b/packages/admin-ui/src/pages/stakers/components/StakersRoot.tsx @@ -64,9 +64,7 @@ const StakersRoot: React.FC = () => { ]; // Remove the "Prater" tab from the stakersItems array - const filteredStakersItems = stakersItems.filter( - item => item.subPath !== "prater" - ); + const filteredStakersItems = stakersItems.filter((item) => item.subPath !== "prater"); return ( <> @@ -74,13 +72,9 @@ const StakersRoot: React.FC = () => { <div className="horizontal-navbar"> {/* Render the staker tabs, excluding "Prater" which is hidden due to deprecation */} - {filteredStakersItems.map(route => ( + {filteredStakersItems.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.title} </NavLink> </button> @@ -89,12 +83,8 @@ const StakersRoot: React.FC = () => { <div className="section-spacing"> <Routes> - {stakersItems.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {stakersItems.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/stakers/components/columns/ConsensusClient.tsx b/packages/admin-ui/src/pages/stakers/components/columns/ConsensusClient.tsx index 6f2b153d5..a952d5d1c 100644 --- a/packages/admin-ui/src/pages/stakers/components/columns/ConsensusClient.tsx +++ b/packages/admin-ui/src/pages/stakers/components/columns/ConsensusClient.tsx @@ -23,11 +23,7 @@ export default function ConsensusClient({ const navigate = useNavigate(); return ( - <Card - {...props} - className={`consensus-client ${joinCssClass({ isSelected })}`} - shadow={isSelected} - > + <Card {...props} className={`consensus-client ${joinCssClass({ isSelected })}`} shadow={isSelected}> <div onClick={ consensusClient.status === "ok" @@ -43,10 +39,7 @@ export default function ConsensusClient({ > {consensusClient.status === "ok" ? ( <div className="avatar"> - <img - src={consensusClient.avatarUrl || defaultAvatar} - alt="avatar" - /> + <img src={consensusClient.avatarUrl || defaultAvatar} alt="avatar" /> </div> ) : consensusClient.status === "error" ? ( <div className="avatar"> @@ -62,13 +55,7 @@ export default function ConsensusClient({ {consensusClient.isInstalled && !consensusClient.isUpdated && ( <> <Button - onClick={() => - navigate( - `${getInstallerPath(consensusClient.dnpName)}/${ - consensusClient.dnpName - }` - ) - } + onClick={() => navigate(`${getInstallerPath(consensusClient.dnpName)}/${consensusClient.dnpName}`)} variant="dappnode" > UPDATE @@ -79,9 +66,7 @@ export default function ConsensusClient({ )} <> {consensusClient.data && ( - <div className="description"> - {consensusClient.data?.manifest?.shortDescription} - </div> + <div className="description">{consensusClient.data?.manifest?.shortDescription}</div> )} </> </> @@ -89,12 +74,10 @@ export default function ConsensusClient({ {isSelected && // cast to any as long as the gnosis prysm was deprecated - (consensusClient.dnpName as any) === - "gnosis-beacon-chain-prysm.dnp.dappnode.eth" && ( + (consensusClient.dnpName as string) === "gnosis-beacon-chain-prysm.dnp.dappnode.eth" && ( <Alert variant="warning"> - It is <b>not recommended</b> to use <b>Prysm</b> as a consensus - client <b>in Gnosis</b>. Use it at your own risk or change to - another alternative. + It is <b>not recommended</b> to use <b>Prysm</b> as a consensus client <b>in Gnosis</b>. Use it at your own + risk or change to another alternative. </Alert> )} </Card> diff --git a/packages/admin-ui/src/pages/stakers/components/columns/ExecutionClient.tsx b/packages/admin-ui/src/pages/stakers/components/columns/ExecutionClient.tsx index 607bcd926..3bed94b04 100644 --- a/packages/admin-ui/src/pages/stakers/components/columns/ExecutionClient.tsx +++ b/packages/admin-ui/src/pages/stakers/components/columns/ExecutionClient.tsx @@ -45,32 +45,21 @@ export default function ExecutionClient({ <div className="title">{prettyDnpName(executionClient.dnpName)} </div> - {executionClient.status === "ok" && - isSelected && - executionClient.isInstalled && - !executionClient.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(executionClient.dnpName)}/${ - executionClient.dnpName - }` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {executionClient.status === "ok" && isSelected && executionClient.isInstalled && !executionClient.isUpdated && ( + <> + <Button + onClick={() => navigate(`${getInstallerPath(executionClient.dnpName)}/${executionClient.dnpName}`)} + variant="dappnode" + > + UPDATE + </Button> + <br /> + <br /> + </> + )} {executionClient.status === "ok" && ( - <div className="description"> - {isSelected && executionClient.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && executionClient.data?.manifest?.shortDescription}</div> )} </Card> ); diff --git a/packages/admin-ui/src/pages/stakers/components/columns/MevBoost.tsx b/packages/admin-ui/src/pages/stakers/components/columns/MevBoost.tsx index c64fda1b2..b7fe9be97 100644 --- a/packages/admin-ui/src/pages/stakers/components/columns/MevBoost.tsx +++ b/packages/admin-ui/src/pages/stakers/components/columns/MevBoost.tsx @@ -39,11 +39,7 @@ export default function MevBoost({ const navigate = useNavigate(); return ( - <Card - {...props} - className={`mev-boost ${joinCssClass({ isSelected })}`} - shadow={isSelected} - > + <Card {...props} className={`mev-boost ${joinCssClass({ isSelected })}`} shadow={isSelected}> <div onClick={ mevBoost.status === "ok" @@ -66,38 +62,25 @@ export default function MevBoost({ <div className="title">{prettyDnpName(mevBoost.dnpName)} </div> </div> - {mevBoost.status === "ok" && - isSelected && - mevBoost.isInstalled && - !mevBoost.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(mevBoost.dnpName)}/${mevBoost.dnpName}` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {mevBoost.status === "ok" && isSelected && mevBoost.isInstalled && !mevBoost.isUpdated && ( + <> + <Button + onClick={() => navigate(`${getInstallerPath(mevBoost.dnpName)}/${mevBoost.dnpName}`)} + variant="dappnode" + > + UPDATE + </Button> + <br /> + <br /> + </> + )} {newMevBoost?.status === "ok" && isSelected && ( - <RelaysList - network={network} - newRelays={newRelays} - setNewRelays={setNewRelays} - /> + <RelaysList network={network} newRelays={newRelays} setNewRelays={setNewRelays} /> )} {mevBoost.status === "ok" && ( - <div className="description"> - {isSelected && mevBoost.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && mevBoost.data?.manifest?.shortDescription}</div> )} </Card> ); @@ -121,11 +104,7 @@ function RelaysList({ <th>Relay</th> <th> OFAC - <a - href="https://www.mevwatch.info/" - target="_blank" - rel="noopener noreferrer" - > + <a href="https://www.mevwatch.info/" target="_blank" rel="noopener noreferrer"> <AiFillInfoCircle /> </a> </th> @@ -134,12 +113,7 @@ function RelaysList({ </thead> <tbody> {defaultRelays.map((relay, index) => ( - <Relay - key={index} - relay={relay} - newRelays={newRelays} - setNewRelays={setNewRelays} - /> + <Relay key={index} relay={relay} newRelays={newRelays} setNewRelays={setNewRelays} /> ))} </tbody> </Table> @@ -156,9 +130,7 @@ function Relay({ newRelays: string[]; setNewRelays: React.Dispatch<React.SetStateAction<string[]>>; }) { - const [isAdded, setIsAdded] = useState( - newRelays.includes(relay.url) ? true : false - ); + const [isAdded, setIsAdded] = useState(newRelays.includes(relay.url) ? true : false); return ( <tr> @@ -171,13 +143,7 @@ function Relay({ <>{relay.operator}</> )} </td> - <td> - {relay.ofacCompliant === undefined - ? "-" - : relay.ofacCompliant - ? "Yes" - : "No"} - </td> + <td>{relay.ofacCompliant === undefined ? "-" : relay.ofacCompliant ? "Yes" : "No"}</td> <td> <Form.Check onChange={() => { @@ -185,7 +151,7 @@ function Relay({ setNewRelays([...newRelays, relay.url]); setIsAdded(true); } else { - setNewRelays(newRelays.filter(r => r !== relay.url)); + setNewRelays(newRelays.filter((r) => r !== relay.url)); setIsAdded(false); } }} @@ -208,57 +174,49 @@ const getDefaultRelays = (network: Network): RelayIface[] => { operator: "Agnostic Boost", ofacCompliant: false, docs: "https://agnostic-relay.net/", - url: - "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net" + url: "https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net" }, { operator: "Ultra Sound", ofacCompliant: false, docs: "https://relay.ultrasound.money/", - url: - "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money" + url: "https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money" }, { operator: "Flashbots", ofacCompliant: true, docs: "https://boost.flashbots.net/", - url: - "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net" + url: "https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net" }, { operator: "bloXroute (Max profit)", ofacCompliant: true, docs: "https://bloxroute.com/", - url: - "https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com" + url: "https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com" }, { operator: "bloXroute (Regulated)", ofacCompliant: true, docs: "https://bloxroute.com/", - url: - "https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com" + url: "https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com" }, { operator: "Eden Network", ofacCompliant: true, docs: "https://docs.edennetwork.io/", - url: - "https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io" + url: "https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io" }, { operator: "Aestus", ofacCompliant: false, docs: "https://aestus.live/", - url: - "https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live" + url: "https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live" }, { operator: "Manifold", ofacCompliant: false, docs: "https://kb.manifoldfinance.com/", - url: - "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com" + url: "https://0x98650451ba02064f7b000f5768cf0cf4d4e492317d82871bdc87ef841a0743f69f0f1eea11168503240ac35d101c9135@mainnet-relay.securerpc.com" } ]; case "prater": @@ -266,32 +224,27 @@ const getDefaultRelays = (network: Network): RelayIface[] => { { operator: "Flashbots", docs: "https://www.flashbots.net/", - url: - "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net" + url: "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@builder-relay-goerli.flashbots.net" }, { operator: "bloXroute", docs: "https://bloxroute.com/", - url: - "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.max-profit.builder.goerli.blxrbdn.com" + url: "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.max-profit.builder.goerli.blxrbdn.com" }, { operator: "Blocknative", docs: "https://www.blocknative.com/", - url: - "https://0x8f7b17a74569b7a57e9bdafd2e159380759f5dc3ccbd4bf600414147e8c4e1dc6ebada83c0139ac15850eb6c975e82d0@builder-relay-goerli.blocknative.com" + url: "https://0x8f7b17a74569b7a57e9bdafd2e159380759f5dc3ccbd4bf600414147e8c4e1dc6ebada83c0139ac15850eb6c975e82d0@builder-relay-goerli.blocknative.com" }, { operator: "Eden Network", docs: "https://docs.edennetwork.io/", - url: - "https://0xb1d229d9c21298a87846c7022ebeef277dfc321fe674fa45312e20b5b6c400bfde9383f801848d7837ed5fc449083a12@relay-goerli.edennetwork.io" + url: "https://0xb1d229d9c21298a87846c7022ebeef277dfc321fe674fa45312e20b5b6c400bfde9383f801848d7837ed5fc449083a12@relay-goerli.edennetwork.io" }, { operator: "Manifold", docs: "https://securerpc.com/", - url: - "https://0x8a72a5ec3e2909fff931c8b42c9e0e6c6e660ac48a98016777fc63a73316b3ffb5c622495106277f8dbcc17a06e92ca3@goerli-relay.securerpc.com/" + url: "https://0x8a72a5ec3e2909fff931c8b42c9e0e6c6e660ac48a98016777fc63a73316b3ffb5c622495106277f8dbcc17a06e92ca3@goerli-relay.securerpc.com/" } ]; case "holesky": @@ -299,33 +252,27 @@ const getDefaultRelays = (network: Network): RelayIface[] => { { operator: "Flashbots", docs: "https://www.flashbots.net/", - url: - "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net" + url: "https://0xafa4c6985aa049fb79dd37010438cfebeb0f2bd42b115b89dd678dab0670c1de38da0c4e9138c9290a398ecd9a0b3110@boost-relay-holesky.flashbots.net" }, { operator: "Aestus", - docs: - "https://flashbots.notion.site/Relay-API-Documentation-5fb0819366954962bc02e81cb33840f5#417abe417dde45caaff3dc15aaae65dd", - url: - "https://0xab78bf8c781c58078c3beb5710c57940874dd96aef2835e7742c866b4c7c0406754376c2c8285a36c630346aa5c5f833@holesky.aestus.live" + docs: "https://flashbots.notion.site/Relay-API-Documentation-5fb0819366954962bc02e81cb33840f5#417abe417dde45caaff3dc15aaae65dd", + url: "https://0xab78bf8c781c58078c3beb5710c57940874dd96aef2835e7742c866b4c7c0406754376c2c8285a36c630346aa5c5f833@holesky.aestus.live" }, { operator: "Ultrasound", docs: "https://github.com/ultrasoundmoney/frontend", - url: - "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money" + url: "https://0xb1559beef7b5ba3127485bbbb090362d9f497ba64e177ee2c8e7db74746306efad687f2cf8574e38d70067d40ef136dc@relay-stag.ultrasound.money" }, { operator: "Titan", docs: "https://docs.titanrelay.xyz/", - url: - "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@holesky.titanrelay.xyz" + url: "https://0xaa58208899c6105603b74396734a6263cc7d947f444f396a90f7b7d3e65d102aec7e5e5291b27e08d02c50a050825c2f@holesky.titanrelay.xyz" }, { operator: "bloXroute", docs: "https://bloxroute.holesky.blxrbdn.com/", - url: - "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.holesky.blxrbdn.com" + url: "https://0x821f2a65afb70e7f2e820a925a9b4c80a159620582c1766b1b09729fec178b11ea22abb3a51f07b288be815a1a2ff516@bloxroute.holesky.blxrbdn.com" } ]; default: diff --git a/packages/admin-ui/src/pages/stakers/components/columns/RemoteSigner.tsx b/packages/admin-ui/src/pages/stakers/components/columns/RemoteSigner.tsx index dd5e604c6..fe59fc87e 100644 --- a/packages/admin-ui/src/pages/stakers/components/columns/RemoteSigner.tsx +++ b/packages/admin-ui/src/pages/stakers/components/columns/RemoteSigner.tsx @@ -23,11 +23,7 @@ export default function RemoteSigner({ const navigate = useNavigate(); return ( - <Card - {...props} - className={`remote-signer ${joinCssClass({ isSelected })}`} - shadow={isSelected} - > + <Card {...props} className={`remote-signer ${joinCssClass({ isSelected })}`} shadow={isSelected}> <div onClick={ signer.status === "ok" @@ -50,51 +46,32 @@ export default function RemoteSigner({ <div className="title">{prettyDnpName(signer.dnpName)} </div> </div> - {signer.status === "ok" && - isSelected && - signer.isInstalled && - !signer.isUpdated && ( - <> - <Button - onClick={() => - navigate( - `${getInstallerPath(signer.dnpName)}/${signer.dnpName}` - ) - } - variant="dappnode" - > - UPDATE - </Button> - <br /> - <br /> - </> - )} + {signer.status === "ok" && isSelected && signer.isInstalled && !signer.isUpdated && ( + <> + <Button onClick={() => navigate(`${getInstallerPath(signer.dnpName)}/${signer.dnpName}`)} variant="dappnode"> + UPDATE + </Button> + <br /> + <br /> + </> + )} - {signer.status === "ok" && - isSelected && - signer.isInstalled && - signer.data?.manifest?.links?.ui && ( - <div - style={{ - alignItems: "center", - textTransform: "capitalize", - whiteSpace: "nowrap" - }} - > - <a - href={signer.data.manifest.links.ui} - target="_blank" - rel="noreferrer noopener" - > - <FaKey /> {" "} Upload keystores - </a> - </div> - )} + {signer.status === "ok" && isSelected && signer.isInstalled && signer.data?.manifest?.links?.ui && ( + <div + style={{ + alignItems: "center", + textTransform: "capitalize", + whiteSpace: "nowrap" + }} + > + <a href={signer.data.manifest.links.ui} target="_blank" rel="noreferrer noopener"> + <FaKey /> {" "} Upload keystores + </a> + </div> + )} {signer.status === "ok" && ( - <div className="description"> - {isSelected && signer.data?.manifest?.shortDescription} - </div> + <div className="description">{isSelected && signer.data?.manifest?.shortDescription}</div> )} </Card> ); diff --git a/packages/admin-ui/src/pages/stakers/components/useStakerConfig.ts b/packages/admin-ui/src/pages/stakers/components/useStakerConfig.ts index dbe7c6b54..55d23e1ec 100644 --- a/packages/admin-ui/src/pages/stakers/components/useStakerConfig.ts +++ b/packages/admin-ui/src/pages/stakers/components/useStakerConfig.ts @@ -1,12 +1,6 @@ import { useState, useEffect } from "react"; import { ReqStatus } from "types"; -import { - StakerConfigGet, - StakerConfigSet, - StakerItemOk, - StakerItem, - Network -} from "@dappnode/types"; +import { StakerConfigGet, StakerConfigSet, StakerItemOk, StakerItem, Network } from "@dappnode/types"; import { responseInterface } from "swr"; export const useStakerConfig = <T extends Network>( @@ -20,9 +14,7 @@ export const useStakerConfig = <T extends Network>( const [newMevBoost, setNewMevBoost] = useState<StakerItemOk | null>(null); const [newRelays, setNewRelays] = useState<string[]>([]); const [newWeb3signer, setNewWeb3signer] = useState<StakerItemOk | null>(null); - const [currentStakerConfig, setCurrentStakerConfig] = useState< - StakerConfigSet - >(); + const [currentStakerConfig, setCurrentStakerConfig] = useState<StakerConfigSet>(); // Changes const [changes, setChanges] = useState<{ isAllowed: boolean; @@ -32,37 +24,22 @@ export const useStakerConfig = <T extends Network>( useEffect(() => { if (currentStakerConfigReq.data) { - const { - executionClients, - consensusClients, - mevBoost, - web3Signer - } = currentStakerConfigReq.data; - - const executionClient = executionClients.find(ec => - isOkSelectedInstalledAndRunning(ec) - ); - const consensusClient = consensusClients.find(cc => - isOkSelectedInstalledAndRunning(cc) - ); + const { executionClients, consensusClients, mevBoost, web3Signer } = currentStakerConfigReq.data; + + const executionClient = executionClients.find((ec) => isOkSelectedInstalledAndRunning(ec)); + const consensusClient = consensusClients.find((cc) => isOkSelectedInstalledAndRunning(cc)); - if (executionClient && executionClient.status === "ok") - setNewExecClient(executionClient); - if (consensusClient && consensusClient.status === "ok") - setNewConsClient(consensusClient); + if (executionClient && executionClient.status === "ok") setNewExecClient(executionClient); + if (consensusClient && consensusClient.status === "ok") setNewConsClient(consensusClient); - const currentMevBoost = - mevBoost && isOkSelectedInstalledAndRunning(mevBoost) ? mevBoost : null; + const currentMevBoost = mevBoost && isOkSelectedInstalledAndRunning(mevBoost) ? mevBoost : null; if (currentMevBoost && mevBoost?.status === "ok") { setNewMevBoost(mevBoost); mevBoost.relays && setNewRelays(mevBoost.relays); } - const currentWeb3signer = isOkSelectedInstalledAndRunning(web3Signer) - ? web3Signer - : null; - if (currentWeb3signer && web3Signer.status === "ok") - setNewWeb3signer(web3Signer); + const currentWeb3signer = isOkSelectedInstalledAndRunning(web3Signer) ? web3Signer : null; + if (currentWeb3signer && web3Signer.status === "ok") setNewWeb3signer(web3Signer); setCurrentStakerConfig({ network, @@ -90,15 +67,7 @@ export const useStakerConfig = <T extends Network>( } }) ); - }, [ - network, - currentStakerConfig, - newConsClient, - newMevBoost, - newRelays, - newWeb3signer, - newExecClient - ]); + }, [network, currentStakerConfig, newConsClient, newMevBoost, newRelays, newWeb3signer, newExecClient]); return { reqStatus, @@ -142,23 +111,12 @@ function getChanges({ reason?: string; severity?: "warning" | "secondary" | "danger"; } { - const { - executionDnpName, - consensusDnpName, - mevBoostDnpName, - relays, - web3signerDnpName - } = currentStakerConfig; - const isExecAndConsSelected = Boolean( - newStakerConfig.executionDnpName && newStakerConfig.consensusDnpName - ); - const isExecAndConsDeSelected = Boolean( - !newStakerConfig.executionDnpName && !newStakerConfig.consensusDnpName - ); + const { executionDnpName, consensusDnpName, mevBoostDnpName, relays, web3signerDnpName } = currentStakerConfig; + const isExecAndConsSelected = Boolean(newStakerConfig.executionDnpName && newStakerConfig.consensusDnpName); + const isExecAndConsDeSelected = Boolean(!newStakerConfig.executionDnpName && !newStakerConfig.consensusDnpName); // Order and compare relays, returns true if changes were made - const mevBoostRelaysChanged = - relays.sort().join(",") !== newStakerConfig.relays.sort().join(","); + const mevBoostRelaysChanged = relays.sort().join(",") !== newStakerConfig.relays.sort().join(","); // Not allowed if no changes if ( @@ -186,26 +144,18 @@ function getChanges({ }; // Not allowed if changes AND (EC AND CC are deselected) AND (changes in signer or MEV boost) - if ( - isExecAndConsDeSelected && - (newStakerConfig.web3signerDnpName || newStakerConfig.mevBoostDnpName) - ) + if (isExecAndConsDeSelected && (newStakerConfig.web3signerDnpName || newStakerConfig.mevBoostDnpName)) return { isAllowed: false, - reason: - "MEV Boost and/or Web3Signer selected but no consensus and execution client selected", + reason: "MEV Boost and/or Web3Signer selected but no consensus and execution client selected", severity: "warning" }; // Not allowed if changes AND (EC or CC are deselected) AND (signer or mev boost) - if ( - !isExecAndConsSelected && - (newStakerConfig.web3signerDnpName || newStakerConfig.mevBoostDnpName) - ) + if (!isExecAndConsSelected && (newStakerConfig.web3signerDnpName || newStakerConfig.mevBoostDnpName)) return { isAllowed: false, - reason: - "To enable web3signer and/or MEV boost, execution and consensus clients must be selected", + reason: "To enable web3signer and/or MEV boost, execution and consensus clients must be selected", severity: "warning" }; @@ -221,10 +171,5 @@ function getChanges({ } function isOkSelectedInstalledAndRunning(StakerItem: StakerItem): boolean { - return ( - StakerItem.status === "ok" && - StakerItem.isSelected && - StakerItem.isInstalled && - StakerItem.isRunning - ); + return StakerItem.status === "ok" && StakerItem.isSelected && StakerItem.isInstalled && StakerItem.isRunning; } diff --git a/packages/admin-ui/src/pages/support/components/Activity.tsx b/packages/admin-ui/src/pages/support/components/Activity.tsx index 4f32c3fbe..6799a0c8b 100644 --- a/packages/admin-ui/src/pages/support/components/Activity.tsx +++ b/packages/admin-ui/src/pages/support/components/Activity.tsx @@ -35,23 +35,18 @@ export default function Activity() { }, [userActionLogs.data]); function loadMore() { - setCount(n => n + 50); + setCount((n) => n + 50); } return ( <> <p> - If a developer asks for more information regarding an error; please find - the error in the list below, tap on it and copy everything in the - expanded grey text area. + If a developer asks for more information regarding an error; please find the error in the list below, tap on it + and copy everything in the expanded grey text area. </p> <div> - <a - href={apiRoutes.userActionLogsUrl()} - {...newTabProps} - className="no-a-style" - > + <a href={apiRoutes.userActionLogsUrl()} {...newTabProps} className="no-a-style"> <Button variant="dappnode"> Download all logs</Button> </a> </div> @@ -66,14 +61,10 @@ export default function Activity() { ) : userActionLogs.error ? ( <ErrorView error={userActionLogs.error} /> ) : userActionLogs.isValidating ? ( - <Loading - steps={["Loading user action logs", "Parsing user action logs"]} - /> + <Loading steps={["Loading user action logs", "Parsing user action logs"]} /> ) : null} - {userActionLogs.data && userActionLogs.data.length === count && ( - <Button onClick={loadMore}>Load more</Button> - )} + {userActionLogs.data && userActionLogs.data.length === count && <Button onClick={loadMore}>Load more</Button>} </> ); } @@ -88,7 +79,7 @@ function ActivityItem({ log }: { log: UserActionLog }) { // Force a re-render every 15 seconds for the timeFrom to show up correctly const [, setClock] = useState(0); useEffect(() => { - const interval = setInterval(() => setClock(n => n + 1), 15 * 1000); + const interval = setInterval(() => setClock((n) => n + 1), 15 * 1000); return () => { clearInterval(interval); }; @@ -97,33 +88,23 @@ function ActivityItem({ log }: { log: UserActionLog }) { // memo JSON.stringify to prevent re-running it every time the clock is refreshed const argsString = useMemo( () => - Array.isArray(log.args) && log.args.length === 1 - ? stringifyObjSafe(log.args[0]) - : stringifyObjSafe(log.args), + Array.isArray(log.args) && log.args.length === 1 ? stringifyObjSafe(log.args[0]) : stringifyObjSafe(log.args), [log.args] ); return ( <div className="user-log"> - <div - className="list-group-item-action log-container" - onClick={() => setCollapsed(!collapsed)} - > + <div className="list-group-item-action log-container" onClick={() => setCollapsed(!collapsed)}> <div className="d-flex justify-content-between"> {/* Top row - left */} <div className="log-header"> {/* Error badge */} - {log.level === "error" ? ( - <span className={badgeClass + type}>{log.level}</span> - ) : null} + {log.level === "error" ? <span className={badgeClass + type}>{log.level}</span> : null} {/* Count badge */} - {log.count ? ( - <span className={badgeClass + "light"}>{log.count}</span> - ) : null} + {log.count ? <span className={badgeClass + "light"}>{log.count}</span> : null} {/* Call name */} <span className={"text-" + type}> - <span className="call-to">Call to</span>{" "} - <strong>{eventShort}</strong> + <span className="call-to">Call to</span> <strong>{eventShort}</strong> </span> </div> {/* Top row - right */} diff --git a/packages/admin-ui/src/pages/support/components/Ports.tsx b/packages/admin-ui/src/pages/support/components/Ports.tsx index 60baa2822..d3dabd823 100644 --- a/packages/admin-ui/src/pages/support/components/Ports.tsx +++ b/packages/admin-ui/src/pages/support/components/Ports.tsx @@ -19,19 +19,14 @@ export default function Ports() { <Ok ok={true} msg={"Dappnode has detected UPnP as enabled"} /> ) : ( <> - <Ok - ok={false} - msg={"Dappnode has detected UPnP as disabled"} - /> + <Ok ok={false} msg={"Dappnode has detected UPnP as disabled"} /> <p> - Enable UPnP or manually open and associate the necessary - ports in the router to the Dappnode local IP: + Enable UPnP or manually open and associate the necessary ports in the router to the Dappnode local + IP: <strong>{systemInfo.data.internalIp}</strong> </p> <br /> - <strong> - UDP ports must be manually checked in the router - </strong> + <strong>UDP ports must be manually checked in the router</strong> </> )} </> diff --git a/packages/admin-ui/src/pages/support/components/PortsStatusTable.tsx b/packages/admin-ui/src/pages/support/components/PortsStatusTable.tsx index 8253e0a27..6695991b6 100644 --- a/packages/admin-ui/src/pages/support/components/PortsStatusTable.tsx +++ b/packages/admin-ui/src/pages/support/components/PortsStatusTable.tsx @@ -10,11 +10,7 @@ import { ReqStatus } from "types"; import { useApi } from "api"; import { api } from "api"; import { prettyDnpName } from "utils/format"; -import { - ApiTablePortStatus, - PortToOpen, - UpnpTablePortStatus -} from "@dappnode/types"; +import { ApiTablePortStatus, PortToOpen, UpnpTablePortStatus } from "@dappnode/types"; import Switch from "components/Switch"; function RenderApiStatus({ @@ -24,9 +20,7 @@ function RenderApiStatus({ apiScanResult: ApiTablePortStatus[]; portToOpen: PortToOpen; }) { - const apiPortMatch = apiScanResult.find( - apiPort => apiPort.port === portToOpen.portNumber - ); + const apiPortMatch = apiScanResult.find((apiPort) => apiPort.port === portToOpen.portNumber); if (!apiPortMatch) return <Ok unknown={true} msg="Not found" />; @@ -38,12 +32,7 @@ function RenderApiStatus({ case "closed": return <Ok ok={false} msg="Closed" />; case "error": - return ( - <Ok - ok={false} - msg={"Error " + (apiPortMatch.message ? apiPortMatch.message : "")} - /> - ); + return <Ok ok={false} msg={"Error " + (apiPortMatch.message ? apiPortMatch.message : "")} />; } } @@ -54,9 +43,7 @@ function RenderUpnpStatus({ upnpScanResult: UpnpTablePortStatus[]; portToOpen: PortToOpen; }) { - const upnpPortMatch = upnpScanResult.find( - upnpPort => upnpPort.port === portToOpen.portNumber - ); + const upnpPortMatch = upnpScanResult.find((upnpPort) => upnpPort.port === portToOpen.portNumber); if (!upnpPortMatch) return <Ok unknown={true} msg="Not found" />; @@ -72,17 +59,9 @@ function ScanningPort() { return <Ok loading={true} msg="Scanning" />; } -export function PortsStatusTable({ - isUpnpEnabled -}: { - isUpnpEnabled: boolean; -}) { - const [upnpReqStatus, setUpnpReqStatus] = useState< - ReqStatus<UpnpTablePortStatus[]> - >({}); - const [apiReqStatus, setApiReqStatus] = useState< - ReqStatus<ApiTablePortStatus[]> - >({}); +export function PortsStatusTable({ isUpnpEnabled }: { isUpnpEnabled: boolean }) { + const [upnpReqStatus, setUpnpReqStatus] = useState<ReqStatus<UpnpTablePortStatus[]>>({}); + const [apiReqStatus, setApiReqStatus] = useState<ReqStatus<ApiTablePortStatus[]>>({}); const [upnpOpenReqStatus, setUpnpOpenReqStatus] = useState<ReqStatus>({}); const portsToOpen = useApi.portsToOpenGet(); @@ -118,13 +97,10 @@ export function PortsStatusTable({ async function onUpnpSwitchToggle(checked: boolean) { try { setUpnpOpenReqStatus({ loading: true }); - await withToast( - () => api.natRenewalEnable({ enableNatRenewal: checked }), - { - message: "Refreshing UPnP port mapping..", - onSuccess: "Successfully mapped ports using UPnP" - } - ); + await withToast(() => api.natRenewalEnable({ enableNatRenewal: checked }), { + message: "Refreshing UPnP port mapping..", + onSuccess: "Successfully mapped ports using UPnP" + }); setUpnpOpenReqStatus({ result: true }); if (upnpReqStatus.result) await upnpStatusGet(); if (apiReqStatus.result) await apiStatusGet(); @@ -167,22 +143,14 @@ export function PortsStatusTable({ <th>Port</th> <th>Protocol</th> <th>Service</th> - {(apiReqStatus.result || apiReqStatus.loading) && ( - <th>Status (API) *</th> - )} - {apiReqStatus.error && ( - <ErrorView hideIcon red error={apiReqStatus.error} /> - )} - {(upnpReqStatus.result || upnpReqStatus.loading) && ( - <th>Status (UPnP) **</th> - )} - {upnpReqStatus.error && ( - <ErrorView hideIcon red error={upnpReqStatus.error} /> - )} + {(apiReqStatus.result || apiReqStatus.loading) && <th>Status (API) *</th>} + {apiReqStatus.error && <ErrorView hideIcon red error={apiReqStatus.error} />} + {(upnpReqStatus.result || upnpReqStatus.loading) && <th>Status (UPnP) **</th>} + {upnpReqStatus.error && <ErrorView hideIcon red error={upnpReqStatus.error} />} </tr> </thead> <tbody> - {portsToOpen.data.map(port => ( + {portsToOpen.data.map((port) => ( <tr> <td>{port.portNumber}</td> <td>{port.protocol}</td> @@ -190,10 +158,7 @@ export function PortsStatusTable({ {apiReqStatus.result && ( <td> - <RenderApiStatus - apiScanResult={apiReqStatus.result} - portToOpen={port} - /> + <RenderApiStatus apiScanResult={apiReqStatus.result} portToOpen={port} /> </td> )} {apiReqStatus.loading && ( @@ -204,10 +169,7 @@ export function PortsStatusTable({ {upnpReqStatus.result && ( <td> - <RenderUpnpStatus - upnpScanResult={upnpReqStatus.result} - portToOpen={port} - /> + <RenderUpnpStatus upnpScanResult={upnpReqStatus.result} portToOpen={port} /> </td> )} {upnpReqStatus.loading && ( @@ -224,16 +186,14 @@ export function PortsStatusTable({ {apiReqStatus.result ? ( <p> <br /> - <strong>Status API*: </strong>ports status according to API scan. - Not valid for UDP ports. + <strong>Status API*: </strong>ports status according to API scan. Not valid for UDP ports. </p> ) : null} {upnpReqStatus.result ? ( <p> <br /> - <strong>Status UPnP**: </strong>ports status according to UPnP scan. - Only available if UPnP is enabled. + <strong>Status UPnP**: </strong>ports status according to UPnP scan. Only available if UPnP is enabled. </p> ) : null} @@ -251,7 +211,6 @@ export function PortsStatusTable({ </> ); if (portsToOpen.error) return <ErrorView error={portsToOpen.error} />; - if (portsToOpen.isValidating) - return <Loading steps={["Loading ports table"]} />; + if (portsToOpen.isValidating) return <Loading steps={["Loading ports table"]} />; return <ErrorView error={"No data available"} />; } diff --git a/packages/admin-ui/src/pages/support/components/Report.tsx b/packages/admin-ui/src/pages/support/components/Report.tsx index 0a7df1e59..0638d5fec 100644 --- a/packages/admin-ui/src/pages/support/components/Report.tsx +++ b/packages/admin-ui/src/pages/support/components/Report.tsx @@ -18,9 +18,7 @@ export default function Report() { const hostStatsReq = useApi.statsDiskGet(); const { versionData, versionDataVpn } = systemInfoReq.data || {}; const diskUsedPercentage = - hostStatsReq.data?.usedPercentage != null - ? `${hostStatsReq.data?.usedPercentage}%` - : "..."; + hostStatsReq.data?.usedPercentage != null ? `${hostStatsReq.data?.usedPercentage}%` : "..."; const versionDatas: { [name: string]: PackageVersionData | undefined } = { "dappmanager.dnp.dappnode.eth": versionData, @@ -29,8 +27,8 @@ export default function Report() { }; const coreDnpVersions = (dnpsReq.data || []) - .filter(dnp => dnp.isCore) - .map(dnp => ({ + .filter((dnp) => dnp.isCore) + .map((dnp) => ({ name: dnp.dnpName, version: versionDatas[dnp.dnpName] || dnp.version })); @@ -44,21 +42,20 @@ export default function Report() { const topicUrlWithData = formatTopicUrl(topicBody); const topicUrlNoData = topicBaseUrl; const reqs = [dnpsReq, systemInfoReq, diagnoseReq, hostStatsReq]; - const isLoading = reqs.some(req => req.isValidating); - const isLoaded = reqs.every(req => req.data); + const isLoading = reqs.some((req) => req.isValidating); + const isLoaded = reqs.every((req) => req.data); return ( <Card> <p> - To help the support team, the <strong>Report</strong> button will - prefill a new forum topic with the information shown below. If you don't - want to share any information, use the{" "} + To help the support team, the <strong>Report</strong> button will prefill a new forum topic with the information + shown below. If you don't want to share any information, use the{" "} <strong>Report without providing information</strong> button. </p> <p> - Before report, please, make sure that the topic does not already exits - in our <a href={dappnodeForumUrl}>forum</a> + Before report, please, make sure that the topic does not already exits in our{" "} + <a href={dappnodeForumUrl}>forum</a> </p> <div className="discourse-topic-header"> diff --git a/packages/admin-ui/src/pages/support/components/SupportRoot.tsx b/packages/admin-ui/src/pages/support/components/SupportRoot.tsx index 7d19b810f..99edb2fb3 100644 --- a/packages/admin-ui/src/pages/support/components/SupportRoot.tsx +++ b/packages/admin-ui/src/pages/support/components/SupportRoot.tsx @@ -39,13 +39,9 @@ const SupportRoot: React.FC = () => { <Title title={title} /> <div className="horizontal-navbar"> - {routes.map(route => ( + {routes.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -54,12 +50,8 @@ const SupportRoot: React.FC = () => { <div className="packages-content"> <Routes> - {routes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {routes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/support/formaters/autoDiagnoseTexts.ts b/packages/admin-ui/src/pages/support/formaters/autoDiagnoseTexts.ts index d1aa519bd..0541aa7ef 100644 --- a/packages/admin-ui/src/pages/support/formaters/autoDiagnoseTexts.ts +++ b/packages/admin-ui/src/pages/support/formaters/autoDiagnoseTexts.ts @@ -1,10 +1,5 @@ import { DiagnoseResult } from "../types"; -import { - SystemInfo, - InstalledPackageData, - HostStatDisk, - PublicIpResponse -} from "@dappnode/types"; +import { SystemInfo, InstalledPackageData, HostStatDisk, PublicIpResponse } from "@dappnode/types"; import { docsUrl, mandatoryCoreDnps } from "params"; import { responseInterface } from "swr"; @@ -26,13 +21,7 @@ type DiagnoseResultOrNull = DiagnoseResult | null; * can also return null, and that diagnose will be ignored */ -export function connection({ - isOpen, - error -}: { - isOpen: boolean; - error: string | null; -}): DiagnoseResultOrNull { +export function connection({ isOpen, error }: { isOpen: boolean; error: string | null }): DiagnoseResultOrNull { return { ok: isOpen, msg: isOpen ? "Session is open" : `Session is closed: ${error || ""}`, @@ -50,8 +39,7 @@ export function internetConnection( publicIpRes: responseInterface<PublicIpResponse, Error>, systemInfo: responseInterface<SystemInfo, Error> ): DiagnoseResultOrNull { - if (publicIpRes.isValidating) - return { loading: true, msg: "Fetching public IP..." }; + if (publicIpRes.isValidating) return { loading: true, msg: "Fetching public IP..." }; if (publicIpRes.data?.publicIp) { return { @@ -59,10 +47,7 @@ export function internetConnection( msg: "Has connected to the internet, and detected own public IP" }; } else { - const msgs: string[] = [ - "Cannot connect to the internet", - "Could not fetch own public IP" - ]; + const msgs: string[] = ["Cannot connect to the internet", "Could not fetch own public IP"]; if (systemInfo.data?.publicIp) { msgs.push("Was previously connected but got disconnected"); } @@ -117,20 +102,13 @@ export function noNatLoopback({ const { noNatLoopback, internalIp } = dappnodeParams; return { ok: !noNatLoopback, - msg: noNatLoopback - ? "No NAT loopback, external IP did not resolve" - : "NAT loopback enabled, external IP resolves", - solutions: [ - `Please use the internal IP: ${internalIp} when you are in the same network as your DAppNode` - ] + msg: noNatLoopback ? "No NAT loopback, external IP did not resolve" : "NAT loopback enabled, external IP resolves", + solutions: [`Please use the internal IP: ${internalIp} when you are in the same network as your DAppNode`] }; } -export function ipfs( - ipfsTestRes: responseInterface<void, Error> -): DiagnoseResultOrNull { - if (ipfsTestRes.isValidating) - return { loading: true, msg: "Checking if IPFS resolves..." }; +export function ipfs(ipfsTestRes: responseInterface<void, Error>): DiagnoseResultOrNull { + if (ipfsTestRes.isValidating) return { loading: true, msg: "Checking if IPFS resolves..." }; const error = ipfsTestRes.error; return { ok: !error, @@ -180,21 +158,14 @@ export function coreDnpsRunning({ const notFound = []; const notRunning = []; for (const coreDnpName of mandatoryCoreDnps) { - const coreDnp = dnpInstalled.find(dnp => dnp.dnpName === coreDnpName); + const coreDnp = dnpInstalled.find((dnp) => dnp.dnpName === coreDnpName); if (!coreDnp) notFound.push(coreDnpName); - else if (coreDnp.containers.some(container => !container.running)) - notRunning.push(coreDnpName); + else if (coreDnp.containers.some((container) => !container.running)) notRunning.push(coreDnpName); } const errorMsgs: string[] = []; - if (notFound.length > 0) - errorMsgs.push( - `Core DAppNode Packages ${notFound.join(", ")} are not found` - ); - if (notRunning.length > 0) - errorMsgs.push( - `Core DAppNode Packages ${notRunning.join(", ")} are not running` - ); + if (notFound.length > 0) errorMsgs.push(`Core DAppNode Packages ${notFound.join(", ")} are not found`); + if (notRunning.length > 0) errorMsgs.push(`Core DAppNode Packages ${notRunning.join(", ")} are not running`); const ok = notFound.length === 0 && notRunning.length === 0; return { ok, diff --git a/packages/admin-ui/src/pages/support/formaters/discourseTopic.ts b/packages/admin-ui/src/pages/support/formaters/discourseTopic.ts index 4182ed17b..72f00770e 100644 --- a/packages/admin-ui/src/pages/support/formaters/discourseTopic.ts +++ b/packages/admin-ui/src/pages/support/formaters/discourseTopic.ts @@ -44,8 +44,7 @@ export function formatTopicBody( items: coreDnpVersions .map(({ name, version }) => ({ name, - data: - typeof version === "object" ? printVersionData(version) : version + data: typeof version === "object" ? printVersionData(version) : version })) .sort((a, b) => a.name.localeCompare(b.name)) }, @@ -59,11 +58,7 @@ export function formatTopicBody( "*Before filing a new topic, please **provide the following information**.*", ...sections .filter(({ items }) => items.length) - .map( - ({ title, items }) => - `## ${title}\n` + - items.map(({ name, data }) => `- **${name}**: ${data}`).join("\n") - ) + .map(({ title, items }) => `## ${title}\n` + items.map(({ name, data }) => `- **${name}**: ${data}`).join("\n")) ].join("\n\n"); } @@ -92,11 +87,7 @@ export function formatTopicUrl(body: string) { */ function printVersionData(versionData: PackageVersionData): string { const { branch, commit, version } = versionData || {}; - return [ - version, - branch && branch !== "master" && `branch: ${branch}`, - commit && `commit: ${commit.slice(0, 8)}` - ] - .filter(data => data) + return [version, branch && branch !== "master" && `branch: ${branch}`, commit && `commit: ${commit.slice(0, 8)}`] + .filter((data) => data) .join(", "); } diff --git a/packages/admin-ui/src/pages/system/actions.ts b/packages/admin-ui/src/pages/system/actions.ts index 411e4c460..84582d2a0 100644 --- a/packages/admin-ui/src/pages/system/actions.ts +++ b/packages/admin-ui/src/pages/system/actions.ts @@ -4,10 +4,7 @@ import { prettyDnpName, prettyVolumeName } from "utils/format"; // External actions import { fetchPasswordIsSecure } from "services/dappnodeStatus/actions"; // Selectors -import { - getEthClientTarget, - getEthRemoteRpc -} from "services/dappnodeStatus/selectors"; +import { getEthClientTarget, getEthRemoteRpc } from "services/dappnodeStatus/selectors"; import { withToastNoThrow } from "components/toast/Toast"; import { AppThunk } from "store"; import { Eth2ClientTarget } from "@dappnode/types"; @@ -15,200 +12,190 @@ import { isEqual } from "lodash-es"; // Redux Thunk actions -export const changeEthClientTarget = ( - nextTarget: Eth2ClientTarget, - newEthRemoteRpc: string -): AppThunk => async (_, getState) => { - const prevTarget = getEthClientTarget(getState()); - const prevEthRemoteRpc = getEthRemoteRpc(getState()); - - // Make sure the target has changed or the call will error - if (isEqual(nextTarget, prevTarget) && prevEthRemoteRpc === newEthRemoteRpc) - return; - - // If the previous target is package, ask the user if deleteVolumes - let deletePrevExecClient = false; - let deletePrevExecClientVolumes = false; - let deletePrevConsClient = false; - let deletePrevConsClientVolumes = false; - if (prevTarget && prevTarget !== "remote") { - if ( - nextTarget === "remote" || - nextTarget.execClient !== prevTarget.execClient - ) { - await new Promise<void>(resolve => - confirm({ - title: `Remove ${prettyDnpName(prevTarget.execClient)}?`, - text: `Do you want to remove your current Execution Layer (EL) client? This action cannot be undone. You can keep the data volume to avoid needing to resync from scratch next time you install the same EL client. Keeping the data volume will NOT clear space in your hard drive.`, - buttons: [ - { - label: "Keep node running", - variant: "danger", - onClick: () => { - deletePrevExecClient = false; - deletePrevExecClientVolumes = false; - resolve(); - } - }, - { - label: "Remove and keep volumes", - variant: "warning", - onClick: () => { - deletePrevExecClient = true; - deletePrevExecClientVolumes = false; - resolve(); - } - }, - { - label: "Remove and delete volumes", - variant: "dappnode", - onClick: () => { - deletePrevExecClient = true; - deletePrevExecClientVolumes = true; - resolve(); - } - } - ] - }) - ); - } +export const changeEthClientTarget = + (nextTarget: Eth2ClientTarget, newEthRemoteRpc: string): AppThunk => + async (_, getState) => { + const prevTarget = getEthClientTarget(getState()); + const prevEthRemoteRpc = getEthRemoteRpc(getState()); + + // Make sure the target has changed or the call will error + if (isEqual(nextTarget, prevTarget) && prevEthRemoteRpc === newEthRemoteRpc) return; // If the previous target is package, ask the user if deleteVolumes - if ( - nextTarget === "remote" || - nextTarget.consClient !== prevTarget.consClient - ) { - await new Promise<void>(resolve => - confirm({ - title: `Remove ${prettyDnpName(prevTarget.consClient)}?`, - text: `Do you want to remove your current Consensus Layer (CL) client? This action cannot be undone. You can keep the volume data to avoid resyncing from scratch next time you install the same CL client. Keeping the volume will NOT clear space in your hard drive.`, - buttons: [ - { - label: "Keep node running", - variant: "danger", - onClick: () => { - deletePrevConsClient = false; - deletePrevConsClientVolumes = false; - resolve(); + let deletePrevExecClient = false; + let deletePrevExecClientVolumes = false; + let deletePrevConsClient = false; + let deletePrevConsClientVolumes = false; + if (prevTarget && prevTarget !== "remote") { + if (nextTarget === "remote" || nextTarget.execClient !== prevTarget.execClient) { + await new Promise<void>((resolve) => + confirm({ + title: `Remove ${prettyDnpName(prevTarget.execClient)}?`, + text: `Do you want to remove your current Execution Layer (EL) client? This action cannot be undone. You can keep the data volume to avoid needing to resync from scratch next time you install the same EL client. Keeping the data volume will NOT clear space in your hard drive.`, + buttons: [ + { + label: "Keep node running", + variant: "danger", + onClick: () => { + deletePrevExecClient = false; + deletePrevExecClientVolumes = false; + resolve(); + } + }, + { + label: "Remove and keep volumes", + variant: "warning", + onClick: () => { + deletePrevExecClient = true; + deletePrevExecClientVolumes = false; + resolve(); + } + }, + { + label: "Remove and delete volumes", + variant: "dappnode", + onClick: () => { + deletePrevExecClient = true; + deletePrevExecClientVolumes = true; + resolve(); + } } - }, - { - label: "Remove and keep volumes", - variant: "warning", - onClick: () => { - deletePrevConsClient = true; - deletePrevConsClientVolumes = false; - resolve(); + ] + }) + ); + } + + // If the previous target is package, ask the user if deleteVolumes + if (nextTarget === "remote" || nextTarget.consClient !== prevTarget.consClient) { + await new Promise<void>((resolve) => + confirm({ + title: `Remove ${prettyDnpName(prevTarget.consClient)}?`, + text: `Do you want to remove your current Consensus Layer (CL) client? This action cannot be undone. You can keep the volume data to avoid resyncing from scratch next time you install the same CL client. Keeping the volume will NOT clear space in your hard drive.`, + buttons: [ + { + label: "Keep node running", + variant: "danger", + onClick: () => { + deletePrevConsClient = false; + deletePrevConsClientVolumes = false; + resolve(); + } + }, + { + label: "Remove and keep volumes", + variant: "warning", + onClick: () => { + deletePrevConsClient = true; + deletePrevConsClientVolumes = false; + resolve(); + } + }, + { + label: "Remove and delete volumes", + variant: "dappnode", + onClick: () => { + deletePrevConsClient = true; + deletePrevConsClientVolumes = true; + resolve(); + } } - }, - { - label: "Remove and delete volumes", - variant: "dappnode", - onClick: () => { - deletePrevConsClient = true; - deletePrevConsClientVolumes = true; - resolve(); - } - } - ] - }) - ); - } - } - - await withToastNoThrow( - () => - api.ethClientTargetSet({ - target: nextTarget, - sync: false, - ethRemoteRpc: newEthRemoteRpc, - deletePrevExecClient, - deletePrevExecClientVolumes, - deletePrevConsClient, - deletePrevConsClientVolumes - }), - { - message: "Changing Ethereum client...", - onSuccess: `Changed Ethereum client` + ] + }) + ); + } } - ); -}; - -export const passwordChangeInBackground = ( - newPassword: string -): AppThunk => async dispatch => { - await api.passwordChange({ newPassword }).catch(console.error); - - dispatch(fetchPasswordIsSecure()); -}; - -export const passwordChange = ( - newPassword: string -): AppThunk => async dispatch => { - // Display a dialog to confirm the password change - await new Promise<void>(resolve => - confirm({ - title: `Changing host user password`, - text: `Make sure to safely store this password and keep a back up. \n\nYou will never be able to see this password again. If you lose it, you will not be able to recover it in any way.`, - label: "Change", - variant: "dappnode", - onClick: resolve - }) - ); - - await withToastNoThrow(() => api.passwordChange({ newPassword }), { - message: `Changing host user password...`, - onSuccess: `Changed host user password` - }); - - dispatch(fetchPasswordIsSecure()); -}; - -export const volumeRemove = (name: string): AppThunk => async () => { - // Display a dialog to confirm the password change - await new Promise<void>(resolve => - confirm({ - title: `Removing volume`, - text: `Are you sure you want to permanently remove volume ${name}?`, - label: "Remove", - variant: "danger", - onClick: resolve - }) - ); - - await withToastNoThrow(() => api.volumeRemove({ name }), { - message: `Removing volume...`, - onSuccess: `Removed volume` - }); -}; - -export const packageVolumeRemove = ( - dnpName: string, - volName: string -): AppThunk => async () => { - // Make sure there are no colliding volumes with this DNP - const prettyVolName = prettyVolumeName(volName, dnpName).name; - const prettyVolRef = `${prettyDnpName(dnpName)} ${prettyVolName} volume`; - - const warningsList: { title: string; body: string }[] = []; - - // If there are NOT conflicting volumes, - // Display a dialog to confirm volumes reset - await new Promise<void>(resolve => - confirm({ - title: `Removing ${prettyVolRef}`, - text: `Are you sure you want to permanently remove this volume? This action cannot be undone. If this DAppNode Package is a blockchain node, it will lose all the chain data and start syncing from scratch.`, - list: warningsList, - label: "Remove", - onClick: resolve - }) - ); - - await withToastNoThrow( - () => api.packageRestartVolumes({ dnpName, volumeId: volName }), - { + + await withToastNoThrow( + () => + api.ethClientTargetSet({ + target: nextTarget, + sync: false, + ethRemoteRpc: newEthRemoteRpc, + deletePrevExecClient, + deletePrevExecClientVolumes, + deletePrevConsClient, + deletePrevConsClientVolumes + }), + { + message: "Changing Ethereum client...", + onSuccess: `Changed Ethereum client` + } + ); + }; + +export const passwordChangeInBackground = + (newPassword: string): AppThunk => + async (dispatch) => { + await api.passwordChange({ newPassword }).catch(console.error); + + dispatch(fetchPasswordIsSecure()); + }; + +export const passwordChange = + (newPassword: string): AppThunk => + async (dispatch) => { + // Display a dialog to confirm the password change + await new Promise<void>((resolve) => + confirm({ + title: `Changing host user password`, + text: `Make sure to safely store this password and keep a back up. \n\nYou will never be able to see this password again. If you lose it, you will not be able to recover it in any way.`, + label: "Change", + variant: "dappnode", + onClick: resolve + }) + ); + + await withToastNoThrow(() => api.passwordChange({ newPassword }), { + message: `Changing host user password...`, + onSuccess: `Changed host user password` + }); + + dispatch(fetchPasswordIsSecure()); + }; + +export const volumeRemove = + (name: string): AppThunk => + async () => { + // Display a dialog to confirm the password change + await new Promise<void>((resolve) => + confirm({ + title: `Removing volume`, + text: `Are you sure you want to permanently remove volume ${name}?`, + label: "Remove", + variant: "danger", + onClick: resolve + }) + ); + + await withToastNoThrow(() => api.volumeRemove({ name }), { + message: `Removing volume...`, + onSuccess: `Removed volume` + }); + }; + +export const packageVolumeRemove = + (dnpName: string, volName: string): AppThunk => + async () => { + // Make sure there are no colliding volumes with this DNP + const prettyVolName = prettyVolumeName(volName, dnpName).name; + const prettyVolRef = `${prettyDnpName(dnpName)} ${prettyVolName} volume`; + + const warningsList: { title: string; body: string }[] = []; + + // If there are NOT conflicting volumes, + // Display a dialog to confirm volumes reset + await new Promise<void>((resolve) => + confirm({ + title: `Removing ${prettyVolRef}`, + text: `Are you sure you want to permanently remove this volume? This action cannot be undone. If this DAppNode Package is a blockchain node, it will lose all the chain data and start syncing from scratch.`, + list: warningsList, + label: "Remove", + onClick: resolve + }) + ); + + await withToastNoThrow(() => api.packageRestartVolumes({ dnpName, volumeId: volName }), { message: `Removing ${prettyVolRef}...`, onSuccess: `Removed ${prettyVolRef}` - } - ); -}; + }); + }; diff --git a/packages/admin-ui/src/pages/system/components/Advanced/ChangeDappnodeWebName.tsx b/packages/admin-ui/src/pages/system/components/Advanced/ChangeDappnodeWebName.tsx index 4f11cc0c3..d7afa74e3 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/ChangeDappnodeWebName.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/ChangeDappnodeWebName.tsx @@ -39,11 +39,7 @@ export function ChangeDappnodeWebName() { } ]} > - <Button - type="submit" - onClick={() => onChangeDappNodeWebName()} - variant="dappnode" - > + <Button type="submit" onClick={() => onChangeDappNodeWebName()} variant="dappnode"> Change Dappnode Name </Button> </InputForm> diff --git a/packages/admin-ui/src/pages/system/components/Advanced/ClearCacheDb.tsx b/packages/admin-ui/src/pages/system/components/Advanced/ClearCacheDb.tsx index 516f61ef0..946e1bc91 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/ClearCacheDb.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/ClearCacheDb.tsx @@ -7,7 +7,7 @@ import { withToastNoThrow } from "components/toast/Toast"; export function ClearCacheDb() { async function cleanCache() { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Deleting cache`, text: `This action cannot be undone. You should only delete the cache in response to a problem.`, @@ -25,9 +25,8 @@ export function ClearCacheDb() { return ( <Card spacing> <p> - Remove the local cache of Aragon Package Manager (APM) entries, - manifests, avatars. Also remove the user action logs shown in the - Activity tab. + Remove the local cache of Aragon Package Manager (APM) entries, manifests, avatars. Also remove the user action + logs shown in the Activity tab. </p> <Button variant="outline-danger" onClick={cleanCache}> diff --git a/packages/admin-ui/src/pages/system/components/Advanced/ClearMainDb.tsx b/packages/admin-ui/src/pages/system/components/Advanced/ClearMainDb.tsx index 4341117c9..f5da1ebfc 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/ClearMainDb.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/ClearMainDb.tsx @@ -7,7 +7,7 @@ import { withToastNoThrow } from "components/toast/Toast"; export function ClearMainDb() { async function cleanDb() { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Deleting main database`, text: `This action cannot be undone. You should only delete the database in response to a problem.`, @@ -25,9 +25,8 @@ export function ClearMainDb() { return ( <Card spacing> <p> - Remove the local database which contains critical information about your - DAppNode, such as the dyndns identity, Ips registry, telegram - configuration and more + Remove the local database which contains critical information about your DAppNode, such as the dyndns identity, + Ips registry, telegram configuration and more </p> <Button variant="outline-danger" onClick={cleanDb}> diff --git a/packages/admin-ui/src/pages/system/components/Advanced/DockerUpgrade.tsx b/packages/admin-ui/src/pages/system/components/Advanced/DockerUpgrade.tsx index 5392845a8..304c07c77 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/DockerUpgrade.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/DockerUpgrade.tsx @@ -50,25 +50,17 @@ function RequirementsList({ items }: { items: DockerUpgradeRequirements }) { export function DockerUpgrade() { const [updateReq, setUpdateReq] = useState<ReqStatus>({}); - const [checkReq, setCheckReq] = useState< - ReqStatus<DockerUpgradeRequirements> - >({}); + const [checkReq, setCheckReq] = useState<ReqStatus<DockerUpgradeRequirements>>({}); const [canUpdate, setCanUpdate] = useState<boolean>(false); useEffect(() => { if (checkReq.result) { - const { - isDockerInUnattendedUpgrades, - isDockerInstalledThroughApt, - dockerHostVersion, - dockerLatestVersion - } = checkReq.result; + const { isDockerInUnattendedUpgrades, isDockerInstalledThroughApt, dockerHostVersion, dockerLatestVersion } = + checkReq.result; const canUpdate = !isDockerInUnattendedUpgrades || !isDockerInstalledThroughApt || - Boolean( - dockerLatestVersion && lt(dockerHostVersion, dockerLatestVersion) - ); + Boolean(dockerLatestVersion && lt(dockerHostVersion, dockerLatestVersion)); setCanUpdate(canUpdate); } }, [checkReq.result]); @@ -85,7 +77,7 @@ export function DockerUpgrade() { async function dockerUpdate() { try { - await new Promise<void>(resolve => { + await new Promise<void>((resolve) => { confirm({ title: `Docker update`, text: `Warning, you are about to update Docker . It is possible that the system will need to reboot. Make sure you can sustain some minutes of downtime and backup your most important data.`, @@ -110,9 +102,8 @@ export function DockerUpgrade() { return ( <Card spacing> <p> - Update docker to latest version, make sure its installed through the - standard apt package manager and enable unattended upgrades for docker - so you do not worry about updating docker anymore + Update docker to latest version, make sure its installed through the standard apt package manager and enable + unattended upgrades for docker so you do not worry about updating docker anymore </p> {!canUpdate && ( diff --git a/packages/admin-ui/src/pages/system/components/Advanced/ReleaseTrustedKeysEditor.tsx b/packages/admin-ui/src/pages/system/components/Advanced/ReleaseTrustedKeysEditor.tsx index 7bb5e2aae..a41f78793 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/ReleaseTrustedKeysEditor.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/ReleaseTrustedKeysEditor.tsx @@ -7,11 +7,7 @@ import ErrorView from "components/ErrorView"; import Ok from "components/Ok"; import Card from "components/Card"; import { confirm } from "components/ConfirmDialog"; -import { - TrustedReleaseKey, - ReleaseSignatureProtocol, - releaseSignatureProtocols -} from "@dappnode/types"; +import { TrustedReleaseKey, ReleaseSignatureProtocol, releaseSignatureProtocols } from "@dappnode/types"; import "./releaseTrustedKeysEditor.scss"; import { MdClose } from "react-icons/md"; @@ -22,10 +18,7 @@ export function ReleaseTrustedKeysEditor() { return ( <Card spacing> {trustedKeys.data ? ( - <ReleaseTrustedKeysGrid - keys={trustedKeys.data} - onEdit={trustedKeys.revalidate} - /> + <ReleaseTrustedKeysGrid keys={trustedKeys.data} onEdit={trustedKeys.revalidate} /> ) : trustedKeys.error ? ( <ErrorView error={trustedKeys.error} hideIcon red /> ) : trustedKeys.isValidating ? ( @@ -46,19 +39,12 @@ export function ReleaseTrustedKeysEditor() { ); } -function ReleaseTrustedKeysGrid({ - keys, - onEdit -}: { - keys: TrustedReleaseKey[]; - onEdit: () => void; -}) { +function ReleaseTrustedKeysGrid({ keys, onEdit }: { keys: TrustedReleaseKey[]; onEdit: () => void }) { async function removeTrustedKey(keyName: string) { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Are you sure you want to remove the key ${keyName}?`, - text: - "Your DAppNode won't be to safely verify releases signed by this key.", + text: "Your DAppNode won't be to safely verify releases signed by this key.", label: "Remove", variant: "danger", onClick: resolve @@ -84,7 +70,7 @@ function ReleaseTrustedKeysGrid({ <hr /> - {keys.map(key => ( + {keys.map((key) => ( <React.Fragment key={key.name}> <span>{key.name}</span> <span>{key.dnpNameSuffix}</span> @@ -106,9 +92,7 @@ function ReleaseTrustedKeysGrid({ function ReleaseTrustedKeysAdder({ onEdit }: { onEdit: () => void }) { const [keyName, setKeyName] = useState(""); const [dnpNameSuffix, setDnpNameSuffix] = useState(""); - const [signatureProtocol, setSignatureProtocol] = useState<string>( - releaseSignatureProtocols[0] - ); + const [signatureProtocol, setSignatureProtocol] = useState<string>(releaseSignatureProtocols[0]); const [key, setKey] = useState(""); async function addTrustedKey() { diff --git a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangePort.tsx b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangePort.tsx index 63a1f5724..3c9ac5351 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangePort.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangePort.tsx @@ -37,8 +37,7 @@ export function SshManagerChangePort() { } const portError = validatePort(port); - const portIsSame = - reqGetStatus.result && port && String(reqGetStatus.result) === port; + const portIsSame = reqGetStatus.result && port && String(reqGetStatus.result) === port; return ( <> @@ -52,11 +51,7 @@ export function SshManagerChangePort() { <Button disabled={reqGetStatus.loading} onClick={fetchPort}> Fetch port </Button> - <Button - variant="dappnode" - disabled={!port || portIsSame || reqSetStatus.loading} - onClick={updatePort} - > + <Button variant="dappnode" disabled={!port || portIsSame || reqSetStatus.loading} onClick={updatePort}> Change </Button> </> @@ -69,15 +64,11 @@ export function SshManagerChangePort() { )} {reqGetStatus.loading && <Ok loading msg="Fetching SSH port..."></Ok>} - {reqGetStatus.error && ( - <ErrorView error={reqGetStatus.error} hideIcon red /> - )} + {reqGetStatus.error && <ErrorView error={reqGetStatus.error} hideIcon red />} {reqSetStatus.loading && <Ok loading msg="Changing SSH port..."></Ok>} {reqSetStatus.result && <Ok ok msg="Changed SSH port"></Ok>} - {reqSetStatus.error && ( - <ErrorView error={reqSetStatus.error} hideIcon red /> - )} + {reqSetStatus.error && <ErrorView error={reqSetStatus.error} hideIcon red />} </> ); } diff --git a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangeStatus.tsx b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangeStatus.tsx index f9cf9a7af..8a70dc78c 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangeStatus.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/ChangeStatus.tsx @@ -16,11 +16,10 @@ export function SshManagerChangeStatus() { async function changeSshStatus(status: ShhStatus) { if (status === "disabled") { - await new Promise<void>(resolve => { + await new Promise<void>((resolve) => { confirm({ title: `Disabling SSH service`, - text: - "Warning, you will loose SSH access to your DAppNode. Having direct access to your host machine may be necessary to fix bugs. Make sure to have an alternative way to access your DAppNode, such as physically with a screen and keyboard before disabling SSH access", + text: "Warning, you will loose SSH access to your DAppNode. Having direct access to your host machine may be necessary to fix bugs. Make sure to have an alternative way to access your DAppNode, such as physically with a screen and keyboard before disabling SSH access", label: "Disable", onClick: resolve }); @@ -67,32 +66,20 @@ export function SshManagerChangeStatus() { /> {reqGetStatus.loading && <Ok loading msg="Fetching SSH status..."></Ok>} - {reqGetStatus.error && ( - <ErrorView error={reqGetStatus.error} hideIcon red /> - )} + {reqGetStatus.error && <ErrorView error={reqGetStatus.error} hideIcon red />} <div className="ssh-status-manager-buttons"> - <Button - disabled={reqSetStatus.loading} - onClick={() => changeSshStatus("enabled")} - > + <Button disabled={reqSetStatus.loading} onClick={() => changeSshStatus("enabled")}> Enable </Button> - <Button - disabled={reqSetStatus.loading} - onClick={() => changeSshStatus("disabled")} - > + <Button disabled={reqSetStatus.loading} onClick={() => changeSshStatus("disabled")}> Disable </Button> </div> {reqSetStatus.loading && <Ok loading msg="Changing SSH status..."></Ok>} - {reqSetStatus.result && ( - <Ok ok msg={`Successfully ${reqSetStatus.result} SSH`}></Ok> - )} - {reqSetStatus.error && ( - <ErrorView error={reqSetStatus.error} hideIcon red /> - )} + {reqSetStatus.result && <Ok ok msg={`Successfully ${reqSetStatus.result} SSH`}></Ok>} + {reqSetStatus.error && <ErrorView error={reqSetStatus.error} hideIcon red />} </> ); } diff --git a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/index.tsx b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/index.tsx index 456b42c0a..8933ce225 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/SshManager/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/SshManager/index.tsx @@ -7,18 +7,13 @@ export function SshManager() { return ( <Card spacing> <div className="subtle-header">ENABLE, DISABLE SSH</div> - <p> - Enable and start or disable and stop the ssh.service of your DAppNode - </p> + <p>Enable and start or disable and stop the ssh.service of your DAppNode</p> <SshManagerChangeStatus /> <hr /> <div className="subtle-header">CHANGE SSH PORT</div> - <p> - Change SSH port of your DAppNode. Port number must be greater than 0 and - less than 65536 - </p> + <p>Change SSH port of your DAppNode. Port number must be greater than 0 and less than 65536</p> <SshManagerChangePort /> </Card> ); diff --git a/packages/admin-ui/src/pages/system/components/Advanced/UpdateUpgrade.tsx b/packages/admin-ui/src/pages/system/components/Advanced/UpdateUpgrade.tsx index 6c5e706c9..a6d27234a 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/UpdateUpgrade.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/UpdateUpgrade.tsx @@ -7,7 +7,7 @@ import { withToastNoThrow } from "components/toast/Toast"; export function UpdateUpgrade() { async function updateUpgrade() { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Updating and upgrading the host machine`, text: `This action might update docker among other packages, you might loose connectivity temporarily to the dappnode.`, @@ -24,9 +24,8 @@ export function UpdateUpgrade() { return ( <Card spacing> <p> - Update and upgrade the host machine. This action update and upgrade the - list of packages of the host machine. This action might require a reboot - of the host machine, you will receive a notification if so. + Update and upgrade the host machine. This action update and upgrade the list of packages of the host machine. + This action might require a reboot of the host machine, you will receive a notification if so. </p> <Button variant="outline-danger" onClick={updateUpgrade}> diff --git a/packages/admin-ui/src/pages/system/components/Advanced/index.tsx b/packages/admin-ui/src/pages/system/components/Advanced/index.tsx index b87bfbc8c..896df2be3 100644 --- a/packages/admin-ui/src/pages/system/components/Advanced/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Advanced/index.tsx @@ -15,8 +15,7 @@ export function Advanced() { <SubTitle>Change DappNode Name</SubTitle> <Card spacing> <div> - Dappnode name only affects to the User Web Interface. It's the name - appears on the top navigation bar. + Dappnode name only affects to the User Web Interface. It's the name appears on the top navigation bar. </div> <ChangeDappnodeWebName /> </Card> diff --git a/packages/admin-ui/src/pages/system/components/AutoUpdates/AutoUpdateRowItem.tsx b/packages/admin-ui/src/pages/system/components/AutoUpdates/AutoUpdateRowItem.tsx index cdccf40af..5df0602ef 100644 --- a/packages/admin-ui/src/pages/system/components/AutoUpdates/AutoUpdateRowItem.tsx +++ b/packages/admin-ui/src/pages/system/components/AutoUpdates/AutoUpdateRowItem.tsx @@ -5,10 +5,7 @@ import { parseStaticDate, parseDiffDates } from "utils/dates"; import { autoUpdateIds } from "params"; import { MdChevronRight } from "react-icons/md"; import { getInstallerPath } from "pages/installer"; -import { - pathName as systemPathName, - subPaths as systemSubPaths -} from "pages/system/data"; +import { pathName as systemPathName, subPaths as systemSubPaths } from "pages/system/data"; const { MY_PACKAGES, SYSTEM_PACKAGES } = autoUpdateIds; @@ -28,6 +25,7 @@ export function AutoUpdateRowItem({ id: string; displayName: string; enabled: boolean; + // eslint-disable-next-line @typescript-eslint/no-explicit-any feedback: any; isInstalling: boolean; isSinglePackage: boolean; @@ -37,7 +35,7 @@ export function AutoUpdateRowItem({ // Force a re-render every 15 seconds for the timeFrom to show up correctly const [, setClock] = useState(0); useEffect(() => { - const interval = setInterval(() => setClock(n => n + 1), 15 * 1000); + const interval = setInterval(() => setClock((n) => n + 1), 15 * 1000); return () => { clearInterval(interval); }; @@ -50,33 +48,28 @@ export function AutoUpdateRowItem({ id === MY_PACKAGES ? null : id === SYSTEM_PACKAGES - ? `${systemPathName}/${systemSubPaths.update}` - : `${getInstallerPath(id)}/${id}`; + ? `${systemPathName}/${systemSubPaths.update}` + : `${getInstallerPath(id)}/${id}`; const feedbackText = !enabled ? "-" : isInstalling - ? "Updating..." - : manuallyUpdated - ? "Manually updated" - : inQueue - ? "In queue..." - : scheduled - ? `Scheduled, in ${parseDiffDates(scheduled)}` - : updated - ? parseStaticDate(updated) - : "-"; + ? "Updating..." + : manuallyUpdated + ? "Manually updated" + : inQueue + ? "In queue..." + : scheduled + ? `Scheduled, in ${parseDiffDates(scheduled)}` + : updated + ? parseStaticDate(updated) + : "-"; const showUpdateLink = isInstalling || inQueue || scheduled; return ( <React.Fragment key={id}> - <span - className={`state-badge center badge-${ - enabled ? "success" : "secondary" - }`} - style={{ opacity: 0.85 }} - > + <span className={`state-badge center badge-${enabled ? "success" : "secondary"}`} style={{ opacity: 0.85 }}> <span className="content">{enabled ? "on" : "off"}</span> </span> @@ -100,11 +93,7 @@ export function AutoUpdateRowItem({ ) : null} </span> - <Switch - checked={enabled ? true : false} - onToggle={() => setUpdateSettings(id, !Boolean(enabled))} - label="" - /> + <Switch checked={enabled ? true : false} onToggle={() => setUpdateSettings(id, !enabled)} label="" /> {!collapsed && <div className="extra-info">{errorMessage}</div>} diff --git a/packages/admin-ui/src/pages/system/components/AutoUpdates/enableAutoUpdatesForPackageWithConfirm.ts b/packages/admin-ui/src/pages/system/components/AutoUpdates/enableAutoUpdatesForPackageWithConfirm.ts index 9bb598616..e3a15c61c 100644 --- a/packages/admin-ui/src/pages/system/components/AutoUpdates/enableAutoUpdatesForPackageWithConfirm.ts +++ b/packages/admin-ui/src/pages/system/components/AutoUpdates/enableAutoUpdatesForPackageWithConfirm.ts @@ -11,9 +11,7 @@ const { MY_PACKAGES } = autoUpdateIds; * while keeping auto-update related logic in this file * @param dnpName */ -export async function enableAutoUpdatesForPackageWithConfirm( - dnpName: string -): Promise<void> { +export async function enableAutoUpdatesForPackageWithConfirm(dnpName: string): Promise<void> { const { settings } = await api.autoUpdateDataGet(); const autoUpdatesEnabledForAllPackages = settings[MY_PACKAGES]?.enabled; const autoUpdatesEnabledForThisPackage = settings[dnpName]?.enabled; @@ -21,7 +19,7 @@ export async function enableAutoUpdatesForPackageWithConfirm( if (!autoUpdatesEnabledForAllPackages && !autoUpdatesEnabledForThisPackage) { // Allow user to enable for all packages or just this package - const enableForAll = await new Promise<boolean>(resolve => { + const enableForAll = await new Promise<boolean>((resolve) => { confirm({ title: "Enable auto-updates", text: `Do you want to enable auto-update for ${prettyName} so DAppNode to installs automatically the latest versions?`, @@ -42,12 +40,9 @@ export async function enableAutoUpdatesForPackageWithConfirm( const id = enableForAll ? MY_PACKAGES : dnpName; const logId = enableForAll ? "all packages" : prettyName; - await withToastNoThrow( - () => api.autoUpdateSettingsEdit({ id, enabled: true }), - { - message: `Enabling auto-updates for ${logId}`, - onSuccess: `Enabled auto-updates for ${logId}` - } - ); + await withToastNoThrow(() => api.autoUpdateSettingsEdit({ id, enabled: true }), { + message: `Enabling auto-updates for ${logId}`, + onSuccess: `Enabled auto-updates for ${logId}` + }); } } diff --git a/packages/admin-ui/src/pages/system/components/AutoUpdates/index.tsx b/packages/admin-ui/src/pages/system/components/AutoUpdates/index.tsx index c196472a3..6d0e81f4c 100644 --- a/packages/admin-ui/src/pages/system/components/AutoUpdates/index.tsx +++ b/packages/admin-ui/src/pages/system/components/AutoUpdates/index.tsx @@ -20,8 +20,7 @@ import { AutoUpdateRowItem } from "./AutoUpdateRowItem"; export * from "./enableAutoUpdatesForPackageWithConfirm"; const { MY_PACKAGES, SYSTEM_PACKAGES } = autoUpdateIds; -const getIsSinglePackage = (id: string) => - id !== MY_PACKAGES && id !== SYSTEM_PACKAGES; +const getIsSinglePackage = (id: string) => id !== MY_PACKAGES && id !== SYSTEM_PACKAGES; /** * Main auto-udpates view @@ -31,10 +30,7 @@ export default function AutoUpdates() { const progressLogsByDnp = useSelector(getProgressLogsByDnp); const ethClientWarning = useSelector(getEthClientWarning); - async function setUpdateSettings( - id: string, - enabled: boolean - ): Promise<void> { + async function setUpdateSettings(id: string, enabled: boolean): Promise<void> { try { const actioning = enabled ? "Enabling" : "Disabling"; const actioned = enabled ? "Enabled" : "Disabled"; @@ -48,66 +44,52 @@ export default function AutoUpdates() { } } - return renderResponse( - autoUpdateDataReq, - ["Loading auto-update data"], - autoUpdateData => { - const { dnpsToShow = [] } = autoUpdateData || {}; - const someAutoUpdateIsEnabled = - dnpsToShow.length > 0 && dnpsToShow.some(dnp => dnp.enabled); + return renderResponse(autoUpdateDataReq, ["Loading auto-update data"], (autoUpdateData) => { + const { dnpsToShow = [] } = autoUpdateData || {}; + const someAutoUpdateIsEnabled = dnpsToShow.length > 0 && dnpsToShow.some((dnp) => dnp.enabled); - return ( - <Card> - <div className="auto-updates-explanation"> - Enable auto-updates for DAppNode to install automatically the latest - versions. For major breaking updates, your approval will always be - required. - </div> + return ( + <Card> + <div className="auto-updates-explanation"> + Enable auto-updates for DAppNode to install automatically the latest versions. For major breaking updates, + your approval will always be required. + </div> - {ethClientWarning && someAutoUpdateIsEnabled && ( - <Alert variant="warning"> - Auto-updates will not work temporarily. Eth client not available:{" "} - {ethClientWarning} - <br /> - Enable the{" "} - <NavLink to={activateFallbackPath}> - repository source fallback - </NavLink>{" "} - to have auto-updates meanwhile - </Alert> - )} + {ethClientWarning && someAutoUpdateIsEnabled && ( + <Alert variant="warning"> + Auto-updates will not work temporarily. Eth client not available: {ethClientWarning} + <br /> + Enable the <NavLink to={activateFallbackPath}>repository source fallback</NavLink> to have auto-updates + meanwhile + </Alert> + )} - <div className="list-grid auto-updates"> - {/* Table header */} - <span className="state-badge" /> - <span className="name" /> - <span className="last-update header">Last auto-update</span> - <span className="header">Enabled</span> + <div className="list-grid auto-updates"> + {/* Table header */} + <span className="state-badge" /> + <span className="name" /> + <span className="last-update header">Last auto-update</span> + <span className="header">Enabled</span> - <hr /> - {/* Items of the table */} - {dnpsToShow.map(({ id, displayName, enabled, feedback }) => ( - <AutoUpdateRowItem - key={id} - {...{ - id, - displayName, - enabled, - feedback, - isInstalling: Boolean( - (progressLogsByDnp || {})[ - id === SYSTEM_PACKAGES ? coreDnpName : id - ] - ), - isSinglePackage: getIsSinglePackage(id), - // Actions - setUpdateSettings - }} - /> - ))} - </div> - </Card> - ); - } - ); + <hr /> + {/* Items of the table */} + {dnpsToShow.map(({ id, displayName, enabled, feedback }) => ( + <AutoUpdateRowItem + key={id} + {...{ + id, + displayName, + enabled, + feedback, + isInstalling: Boolean((progressLogsByDnp || {})[id === SYSTEM_PACKAGES ? coreDnpName : id]), + isSinglePackage: getIsSinglePackage(id), + // Actions + setUpdateSettings + }} + /> + ))} + </div> + </Card> + ); + }); } diff --git a/packages/admin-ui/src/pages/system/components/Hardware/Lvm.tsx b/packages/admin-ui/src/pages/system/components/Hardware/Lvm.tsx index 110a375b4..e86a6a513 100644 --- a/packages/admin-ui/src/pages/system/components/Hardware/Lvm.tsx +++ b/packages/admin-ui/src/pages/system/components/Hardware/Lvm.tsx @@ -1,9 +1,5 @@ import React, { useState } from "react"; -import { - HostLogicalVolume, - HostHardDisk, - HostVolumeGroup -} from "@dappnode/types"; +import { HostLogicalVolume, HostHardDisk, HostVolumeGroup } from "@dappnode/types"; import { api } from "api"; import Button from "components/Button"; import Ok from "components/Ok"; @@ -20,12 +16,8 @@ export default function Lvm() { const [automatic, setAutomatic] = useState(false); // Requests const [diskReq, setDiskReq] = useState<ReqStatus<HostHardDisk[]>>({}); - const [volumeGroupReq, setVolumeGroupReq] = useState< - ReqStatus<HostVolumeGroup[]> - >({}); - const [logicalVolumeReq, setLogicalVolumeReq] = useState< - ReqStatus<HostLogicalVolume[]> - >({}); + const [volumeGroupReq, setVolumeGroupReq] = useState<ReqStatus<HostVolumeGroup[]>>({}); + const [logicalVolumeReq, setLogicalVolumeReq] = useState<ReqStatus<HostLogicalVolume[]>>({}); const [expandDiskReq, setExpandDiskReq] = useState<ReqStatus<string>>({}); // Select options @@ -69,11 +61,7 @@ export default function Lvm() { } } - async function expandDisk( - disk: string, - volumeGroup: string, - logicalVolume: string - ) { + async function expandDisk(disk: string, volumeGroup: string, logicalVolume: string) { try { setExpandDiskReq({ loading: true }); const logicalVolumes = await api.lvmDiskSpaceExtend({ @@ -91,24 +79,14 @@ export default function Lvm() { async function getDappnodeDefaults() { try { const volumeGroups = await api.lvmVolumeGroupsGet(); - const defaultVg = volumeGroups.find( - vg => vg.vg_name === dappnodeVolumeGroup - )?.vg_name; + const defaultVg = volumeGroups.find((vg) => vg.vg_name === dappnodeVolumeGroup)?.vg_name; if (defaultVg) setVolumeGroup(defaultVg); - else - throw Error( - `Dappnode default volume group ${dappnodeVolumeGroup} not found` - ); + else throw Error(`Dappnode default volume group ${dappnodeVolumeGroup} not found`); const logicalVolumes = await api.lvmLogicalVolumesGet(); - const defaultLv = logicalVolumes.find( - lv => lv.lv_name === dappnodeLogicalVolume - )?.lv_name; + const defaultLv = logicalVolumes.find((lv) => lv.lv_name === dappnodeLogicalVolume)?.lv_name; if (defaultLv) setLogicalVolume(defaultLv); - else - throw Error( - `Dappnode default logical volume ${dappnodeLogicalVolume} not found` - ); + else throw Error(`Dappnode default logical volume ${dappnodeLogicalVolume} not found`); } catch (e) { setExpandDiskReq({ error: e }); console.error("Not possible to expand the disk space", e); @@ -126,7 +104,7 @@ export default function Lvm() { } async function disclaimer(automatic: boolean) { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Are you sure you want to extend the host filesystem with another storage device?`, text: `Extending the filesystem is a dangerous operation that cannot be undone. You must very well know what you are doing. @@ -163,11 +141,8 @@ You must read the DAppNode documentation about extending the filesystem with LVM <Card spacing> <div> <p> - Expand your DAppNode filesystem with another storage device. More - information at:{" "} - <LinkDocs href={forumUrl.expandFileSystemHowTo}> - How to expand your DAppNode filesystem - </LinkDocs> + Expand your DAppNode filesystem with another storage device. More information at:{" "} + <LinkDocs href={forumUrl.expandFileSystemHowTo}>How to expand your DAppNode filesystem</LinkDocs> </p> <div style={{ display: "flex", justifyContent: "space-around" }}> <Button onClick={() => disclaimer(true)} variant="dappnode"> @@ -189,9 +164,7 @@ You must read the DAppNode documentation about extending the filesystem with LVM {diskReq.result ? ( <Select value={undefined} - options={diskReq.result.map( - disk => `${disk.name} (${disk.size})` - )} + options={diskReq.result.map((disk) => `${disk.name} (${disk.size})`)} onValueChange={(value: string) => setDisk(value.split(/\s+/)[0])} /> ) : diskReq.loading ? ( @@ -226,12 +199,8 @@ You must read the DAppNode documentation about extending the filesystem with LVM {volumeGroupReq.result ? ( <Select value={undefined} - options={volumeGroupReq.result.map( - vg => `${vg.vg_name} (${vg.vg_size})` - )} - onValueChange={(value: string) => - setVolumeGroup(value.split(/\s+/)[0]) - } + options={volumeGroupReq.result.map((vg) => `${vg.vg_name} (${vg.vg_size})`)} + onValueChange={(value: string) => setVolumeGroup(value.split(/\s+/)[0])} /> ) : volumeGroupReq.loading ? ( <Ok msg="Getting volumes groups" loading={true} /> @@ -253,12 +222,8 @@ You must read the DAppNode documentation about extending the filesystem with LVM {logicalVolumeReq.result ? ( <Select value={undefined} - options={logicalVolumeReq.result.map( - lv => `${lv.lv_name} (${lv.lv_size}) (${lv.vg_name})` - )} - onValueChange={(value: string) => - setLogicalVolume(value.split(/\s+/)[0]) - } + options={logicalVolumeReq.result.map((lv) => `${lv.lv_name} (${lv.lv_size}) (${lv.vg_name})`)} + onValueChange={(value: string) => setLogicalVolume(value.split(/\s+/)[0])} /> ) : logicalVolumeReq.loading ? ( <Ok msg="Getting logical volumes" loading={true} /> @@ -284,11 +249,7 @@ You must read the DAppNode documentation about extending the filesystem with LVM <li key={volumeGroup}>Logical Volume: {logicalVolume}</li> </ul> </p> - <Button - onClick={() => expandDisk(disk, volumeGroup, logicalVolume)} - > - Expand host filesystem - </Button> + <Button onClick={() => expandDisk(disk, volumeGroup, logicalVolume)}>Expand host filesystem</Button> </> ) : null} </> diff --git a/packages/admin-ui/src/pages/system/components/Network/HttpsMappings.tsx b/packages/admin-ui/src/pages/system/components/Network/HttpsMappings.tsx index a1a80ce11..cea8c2631 100644 --- a/packages/admin-ui/src/pages/system/components/Network/HttpsMappings.tsx +++ b/packages/admin-ui/src/pages/system/components/Network/HttpsMappings.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ import React, { useState } from "react"; import { api, useApi } from "api"; import { useSelector } from "react-redux"; @@ -34,8 +33,7 @@ export function HttpsMappings() { try { await confirmPromise({ title: "Recreate HTTPs mappings", - text: - "You are about to recreate the HTTPs mappings. You should execute this action only in response to an error", + text: "You are about to recreate the HTTPs mappings. You should execute this action only in response to an error", label: "Recreate", variant: "dappnode" }); @@ -61,20 +59,16 @@ export function HttpsMappings() { try { await confirmPromise({ title: "Exposing service", - text: - "Are you sure you want to expose this service to the public internet?", + text: "Are you sure you want to expose this service to the public internet?", label: "Expose", variant: "dappnode" }); setReqStatus({ loading: true }); - await withToast( - () => api.httpsPortalMappingAdd({ mapping: mappingInfo }), - { - message: "Adding HTTPs mapping...", - onSuccess: "Added HTTPs mapping" - } - ); + await withToast(() => api.httpsPortalMappingAdd({ mapping: mappingInfo }), { + message: "Adding HTTPs mapping...", + onSuccess: "Added HTTPs mapping" + }); setReqStatus({ result: true }); } catch (e) { setReqStatus({ error: e.message }); @@ -110,13 +104,9 @@ export function HttpsMappings() { // Helper UI in case the HTTPs Portal is bad if (dnpsRequest.data) { - const httpsPortalDnp = dnpsRequest.data.find( - dnp => dnp.dnpName === httpsPortalDnpName - ); + const httpsPortalDnp = dnpsRequest.data.find((dnp) => dnp.dnpName === httpsPortalDnpName); if (!httpsPortalDnp) { - const url = `${getInstallerPath( - httpsPortalDnpName - )}/${httpsPortalDnpName}`; + const url = `${getInstallerPath(httpsPortalDnpName)}/${httpsPortalDnpName}`; return ( <Alert variant="secondary"> You must{" "} @@ -142,9 +132,7 @@ export function HttpsMappings() { <hr /> - {mappings.data.length === 0 && ( - <span className="no-mappings">No exposable services available</span> - )} + {mappings.data.length === 0 && <span className="no-mappings">No exposable services available</span>} {mappings.data.map((mapping, i) => ( <React.Fragment key={i}> @@ -160,10 +148,7 @@ export function HttpsMappings() { </span> <span className="subdomain"> {mapping.exposed ? ( - <a - href={`https://${mapping.fromSubdomain}.${dappnodeIdentity.domain}`} - {...newTabProps} - > + <a href={`https://${mapping.fromSubdomain}.${dappnodeIdentity.domain}`} {...newTabProps}> {mapping.fromSubdomain} <wbr />.{dappnodeIdentity.domain} </a> @@ -174,9 +159,7 @@ export function HttpsMappings() { <Switch checked={mapping.exposed} - onToggle={() => - mapping.exposed ? removeMapping(mapping) : addMapping(mapping) - } + onToggle={() => (mapping.exposed ? removeMapping(mapping) : addMapping(mapping))} /> </React.Fragment> ))} @@ -193,12 +176,10 @@ export function HttpsMappings() { ); } - if (dnpsRequest.error) - return <ErrorView error={dnpsRequest.error} hideIcon red />; + if (dnpsRequest.error) return <ErrorView error={dnpsRequest.error} hideIcon red />; if (mappings.error) return <ErrorView error={mappings.error} hideIcon red />; - if (dnpsRequest.isValidating) - return <Ok loading msg="Loading HTTPS portal" />; + if (dnpsRequest.isValidating) return <Ok loading msg="Loading HTTPS portal" />; if (mappings.isValidating) return <Ok loading msg="Loading mappings" />; return <ErrorView error={"No data"} hideIcon red />; diff --git a/packages/admin-ui/src/pages/system/components/Network/StaticIp.tsx b/packages/admin-ui/src/pages/system/components/Network/StaticIp.tsx index 40d41bee2..c88cdddb6 100644 --- a/packages/admin-ui/src/pages/system/components/Network/StaticIp.tsx +++ b/packages/admin-ui/src/pages/system/components/Network/StaticIp.tsx @@ -48,10 +48,7 @@ export function StaticIp() { {staticIp ? "Update" : "Enable"} </Button> {staticIp && ( - <Button - variant="outline-dappnode" - onClick={() => updateStaticIp("")} - > + <Button variant="outline-dappnode" onClick={() => updateStaticIp("")}> Disable </Button> )} diff --git a/packages/admin-ui/src/pages/system/components/Network/index.tsx b/packages/admin-ui/src/pages/system/components/Network/index.tsx index 842091d01..2999cc782 100644 --- a/packages/admin-ui/src/pages/system/components/Network/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Network/index.tsx @@ -12,9 +12,8 @@ export function Network() { <SubTitle>HTTPs Portal</SubTitle> <Card spacing className="network-editor"> <div> - HTTPs portal allows you to expose services to the external internet - with a valid TLS/SSL certificate. Only the services that are safe to - be exposed will show up here. Learn more about HTTPs portal at:{" "} + HTTPs portal allows you to expose services to the external internet with a valid TLS/SSL certificate. Only the + services that are safe to be exposed will show up here. Learn more about HTTPs portal at:{" "} <LinkDocs href={docsUrl.httpsExplanation}>What is HTTPs</LinkDocs> </div> <HttpsMappings /> @@ -23,9 +22,8 @@ export function Network() { <SubTitle>Static IP</SubTitle> <Card spacing className="network-editor"> <div> - You can set a static IP for this DAppNode instead of using a dyndns. - Only set a static IP if you are sure it is static, otherwise you may - not be able to connect to its VPN. + You can set a static IP for this DAppNode instead of using a dyndns. Only set a static IP if you are sure it + is static, otherwise you may not be able to connect to its VPN. </div> <StaticIp /> </Card> diff --git a/packages/admin-ui/src/pages/system/components/Notifications/EthicalMetrics.tsx b/packages/admin-ui/src/pages/system/components/Notifications/EthicalMetrics.tsx index 8b5880167..b53f08725 100644 --- a/packages/admin-ui/src/pages/system/components/Notifications/EthicalMetrics.tsx +++ b/packages/admin-ui/src/pages/system/components/Notifications/EthicalMetrics.tsx @@ -82,8 +82,8 @@ export default function EthicalMetrics() { mailValue && tgChannelIdValue ? "telegram channel and email" : mailValue - ? "email" - : tgChannelId && "telegram channel" + ? "email" + : tgChannelId && "telegram channel" }`, onSuccess: `Enabled ethical metrics` } @@ -130,23 +130,18 @@ export default function EthicalMetrics() { <Card spacing> <div> <p> - Receive notifications if your{" "} - <strong>dappnode remains offline</strong> for at least 3 hours, sent - to either your Telegram or email. Telemetry is collected anonymously - to ensure no personal data is retained. + Receive notifications if your <strong>dappnode remains offline</strong> for at least 3 hours, sent to either + your Telegram or email. Telemetry is collected anonymously to ensure no personal data is retained. </p> </div> <div> <p> <span style={{ fontWeight: "bold" }}>Advice: </span> - We highly recommend using the Telegram channel option (or both) rather - than relying only on email notifications. Email notifications may be - categorized as spam, potentially causing you to miss important + We highly recommend using the Telegram channel option (or both) rather than relying only on email + notifications. Email notifications may be categorized as spam, potentially causing you to miss important notifications! </p> - <LinkDocs href={docsUrl.ethicalMetricsOverview}> - Learn more about Ethical metrics in our Documentation - </LinkDocs> + <LinkDocs href={docsUrl.ethicalMetricsOverview}>Learn more about Ethical metrics in our Documentation</LinkDocs> </div> {ethicalMetricsConfig.data ? ( @@ -169,8 +164,7 @@ export default function EthicalMetrics() { : () => enableEthicalMetricsSync({ mailValue: mail && !mailError ? mail : null, - tgChannelIdValue: - tgChannelId && !tgChannelIdError ? tgChannelId : null + tgChannelIdValue: tgChannelId && !tgChannelIdError ? tgChannelId : null }) } label={""} @@ -188,17 +182,14 @@ export default function EthicalMetrics() { color: "var(--dappnode-strong-main-color)" }} > - You must provide a Telegram channel ID or an email to enable - ethical metrics notifications + You must provide a Telegram channel ID or an email to enable ethical metrics notifications </span> </> )} <br /> <br /> - <Form.Label> - Ethical metrics notifications by telegram channel - </Form.Label> + <Form.Label>Ethical metrics notifications by telegram channel</Form.Label> <Input placeholder="Telegram Channel ID" isInvalid={tgChannelIdError} @@ -209,14 +200,10 @@ export default function EthicalMetrics() { <Button type="submit" className="register-button" - onClick={() => - enableEthicalMetricsSync({ tgChannelIdValue: tgChannelId }) - } + onClick={() => enableEthicalMetricsSync({ tgChannelIdValue: tgChannelId })} variant="dappnode" disabled={ - tgChannelId === "" || - tgChannelId === ethicalMetricsConfig.data.tgChannelId || - tgChannelIdError + tgChannelId === "" || tgChannelId === ethicalMetricsConfig.data.tgChannelId || tgChannelIdError } > Update @@ -234,12 +221,8 @@ export default function EthicalMetrics() { className="accordion-notifications" > <div className="header"> - <BsInfoCircleFill - className="links-icon" - style={{ fontSize: "14px" }} - /> - How can I get a Telegram channel ID?{" "} - {tgAccordionOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} + <BsInfoCircleFill className="links-icon" style={{ fontSize: "14px" }} /> + How can I get a Telegram channel ID? {tgAccordionOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} </div> </Accordion.Toggle> <Accordion.Collapse eventKey="0"> @@ -247,60 +230,37 @@ export default function EthicalMetrics() { <ol> <li> Open{" "} - <a - href="https://web.telegram.org/a/" - target="_blank" - rel="noopener noreferrer" - > + <a href="https://web.telegram.org/a/" target="_blank" rel="noopener noreferrer"> Telegram web </a> . <ul> <li> - Ensure the URL ends with{" "} - <span className={theme === "dark" ? "dark" : "light"}> - /a/ - </span> - . If not, manually add{" "} - <span className={theme === "dark" ? "dark" : "light"}> - /a/ - </span>{" "} - after{" "} - <span className={theme === "dark" ? "dark" : "light"}> - https://web.telegram.org - </span> - .{" "} + Ensure the URL ends with <span className={theme === "dark" ? "dark" : "light"}>/a/</span>. If + not, manually add <span className={theme === "dark" ? "dark" : "light"}>/a/</span> after{" "} + <span className={theme === "dark" ? "dark" : "light"}>https://web.telegram.org</span>.{" "} </li> </ul> </li> <li>Create a private channel.</li> <li> - Add{" "} - <span className={theme === "dark" ? "dark" : "light"}> - @ethicalMetricsAlerts_bot - </span>{" "} - as an administrator in the channel. + Add <span className={theme === "dark" ? "dark" : "light"}>@ethicalMetricsAlerts_bot</span> as an + administrator in the channel. </li> <li> Go to your channel and copy the 13-digit ID from the URL. <ul> <li> The channel ID always starts with{" "} - <span className={theme === "dark" ? "dark" : "light"}> - -100 - </span> - . Ensure to include the{" "} - <span className={theme === "dark" ? "dark" : "light"}> - - - </span>{" "} - when coping it. + <span className={theme === "dark" ? "dark" : "light"}>-100</span>. Ensure to include the{" "} + <span className={theme === "dark" ? "dark" : "light"}>-</span> when coping it. </li> </ul> </li> <li> - Paste the ID into the Telegram Channel ID field and enable - Ethical Metrics to receive notifications. + Paste the ID into the Telegram Channel ID field and enable Ethical Metrics to receive + notifications. </li> </ol> </div> @@ -308,9 +268,7 @@ export default function EthicalMetrics() { </div> </Accordion> {tgChannelIdError && ( - <span style={{ fontSize: "12px", color: "red" }}> - Telegram channel ID format is incorrect - </span> + <span style={{ fontSize: "12px", color: "red" }}>Telegram channel ID format is incorrect</span> )} <br /> <Form.Label>Ethical metrics notifications by email</Form.Label> @@ -326,11 +284,7 @@ export default function EthicalMetrics() { className="register-button" onClick={() => enableEthicalMetricsSync({ mailValue: mail })} variant="dappnode" - disabled={ - mail === "" || - mail === ethicalMetricsConfig.data.mail || - mailError - } + disabled={mail === "" || mail === ethicalMetricsConfig.data.mail || mailError} > Update </Button> @@ -339,28 +293,16 @@ export default function EthicalMetrics() { ) } /> - {mailError && ( - <span style={{ fontSize: "12px", color: "red" }}> - Email format is incorrect - </span> - )} + {mailError && <span style={{ fontSize: "12px", color: "red" }}>Email format is incorrect</span>} </Form.Group> ) : ethicalMetricsConfig.error ? ( <Ok msg={"Error getting status"} style={{ margin: "auto" }} /> ) : ( - <Ok - msg={"Loading status..."} - loading={true} - style={{ margin: "auto" }} - /> + <Ok msg={"Loading status..."} loading={true} style={{ margin: "auto" }} /> )} - {reqStatusDisable.error && ( - <ErrorView error={reqStatusDisable.error} hideIcon red /> - )} - {reqStatusEnable.error && ( - <ErrorView error={reqStatusEnable.error} hideIcon red /> - )} + {reqStatusDisable.error && <ErrorView error={reqStatusDisable.error} hideIcon red />} + {reqStatusEnable.error && <ErrorView error={reqStatusEnable.error} hideIcon red />} </Card> ); } diff --git a/packages/admin-ui/src/pages/system/components/Notifications/Telegram.tsx b/packages/admin-ui/src/pages/system/components/Notifications/Telegram.tsx index 2fef31324..0bb16812a 100644 --- a/packages/admin-ui/src/pages/system/components/Notifications/Telegram.tsx +++ b/packages/admin-ui/src/pages/system/components/Notifications/Telegram.tsx @@ -66,13 +66,10 @@ export function TelegramNotifications() { async function updateTelegramStatus(newStatus: boolean) { try { setReqStatusStatus({ loading: true }); - await withToast( - () => api.telegramStatusSet({ telegramStatus: newStatus }), - { - message: newStatus ? "Enabling telegram..." : "Disabling telegram...", - onSuccess: newStatus ? "Telegram ON" : "Telegram OFF" - } - ); + await withToast(() => api.telegramStatusSet({ telegramStatus: newStatus }), { + message: newStatus ? "Enabling telegram..." : "Disabling telegram...", + onSuccess: newStatus ? "Telegram ON" : "Telegram OFF" + }); await telegramStatus.revalidate(); setReqStatusStatus({ result: true }); } catch (e) { @@ -99,16 +96,15 @@ export function TelegramNotifications() { return ( <Card spacing> <div> - Receive important notifications directly to your telegram account. To - get your own token from Telegram botfather follow{" "} - <a href={forumUrl.telegramHowTo}>this guide</a> + Receive important notifications directly to your telegram account. To get your own token from Telegram botfather + follow <a href={forumUrl.telegramHowTo}>this guide</a> </div> <div> Available commands in to start your bot chat <ul> <li> - <strong>/start</strong>: Send after starting a conversation - (channel) with your bot. You subscribe to future notifications + <strong>/start</strong>: Send after starting a conversation (channel) with your bot. You subscribe to future + notifications </li> <li> <strong>/help</strong>: Display all available commands @@ -136,11 +132,7 @@ export function TelegramNotifications() { ) : telegramStatus.error ? ( <Ok msg={"Error getting status"} style={{ margin: "auto" }} /> ) : ( - <Ok - msg={"Loading status..."} - loading={true} - style={{ margin: "auto" }} - /> + <Ok msg={"Loading status..."} loading={true} style={{ margin: "auto" }} /> )} <Form.Group> @@ -156,19 +148,13 @@ export function TelegramNotifications() { className="register-button" onClick={updateTelegramConfig} variant="dappnode" - disabled={ - !token || token === telegramConfig.data?.token || tokenError - } + disabled={!token || token === telegramConfig.data?.token || tokenError} > Submit </Button> } /> - {tokenError && ( - <span style={{ fontSize: "12px", color: "red" }}> - Telegram token format is incorrect - </span> - )} + {tokenError && <span style={{ fontSize: "12px", color: "red" }}>Telegram token format is incorrect</span>} <br /> <Form.Label>Telegram user ID</Form.Label> <Input @@ -182,9 +168,7 @@ export function TelegramNotifications() { className="register-button" onClick={updateTelegramConfig} variant="dappnode" - disabled={ - !userId || userId === telegramConfig.data?.userId || userIdError - } + disabled={!userId || userId === telegramConfig.data?.userId || userIdError} > Submit </Button> @@ -198,12 +182,8 @@ export function TelegramNotifications() { className="accordion-notifications" > <div className="header"> - <BsInfoCircleFill - className="links-icon" - style={{ fontSize: "14px" }} - /> - How can I get my telegram user Id?{" "} - {tgAccordionOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} + <BsInfoCircleFill className="links-icon" style={{ fontSize: "14px" }} /> + How can I get my telegram user Id? {tgAccordionOpen ? <IoIosArrowUp /> : <IoIosArrowDown />}{" "} </div> </Accordion.Toggle> <Accordion.Collapse eventKey="0"> @@ -211,11 +191,7 @@ export function TelegramNotifications() { <ol> <li> Open{" "} - <a - href="https://web.telegram.org/a/" - target="_blank" - rel="noopener noreferrer" - > + <a href="https://web.telegram.org/a/" target="_blank" rel="noopener noreferrer"> Telegram web </a> . @@ -224,32 +200,22 @@ export function TelegramNotifications() { Search for the bot <span>@raw_data_bot</span>. </li> <li> - Write the command <span>/start</span> and copy the user ID - returned. + Write the command <span>/start</span> and copy the user ID returned. </li> <li> - Paste the user ID into the user ID field and enable Telegram - to secure your dappnode telegram bot and ensure only you are - the only one allowed to write authenticated commands to it. + Paste the user ID into the user ID field and enable Telegram to secure your dappnode telegram bot + and ensure only you are the only one allowed to write authenticated commands to it. </li> </ol> </div> </Accordion.Collapse> </div> </Accordion> - {userIdError && ( - <span style={{ fontSize: "12px", color: "red" }}> - Telegram user ID format is incorrect - </span> - )} + {userIdError && <span style={{ fontSize: "12px", color: "red" }}>Telegram user ID format is incorrect</span>} </Form.Group> - {reqStatusConfig.error && ( - <ErrorView error={reqStatusConfig.error} hideIcon red /> - )} - {reqStatusStatus.error && ( - <ErrorView error={reqStatusStatus.error} hideIcon red /> - )} + {reqStatusConfig.error && <ErrorView error={reqStatusConfig.error} hideIcon red />} + {reqStatusStatus.error && <ErrorView error={reqStatusStatus.error} hideIcon red />} <hr /> diff --git a/packages/admin-ui/src/pages/system/components/Peers/AddIpfsPeer.tsx b/packages/admin-ui/src/pages/system/components/Peers/AddIpfsPeer.tsx index 69e28cdf8..953666155 100644 --- a/packages/admin-ui/src/pages/system/components/Peers/AddIpfsPeer.tsx +++ b/packages/admin-ui/src/pages/system/components/Peers/AddIpfsPeer.tsx @@ -71,16 +71,13 @@ export default function AddIpfsPeer({ peerFromUrl }: { peerFromUrl?: string }) { return ( <> <Card spacing> - <div> - Add an IPFS peer to your own boostrap list and immediately connect to - it. - </div> + <div>Add an IPFS peer to your own boostrap list and immediately connect to it.</div> <Input placeholder="Peer address /ip4/85.200.85.20/tcp/4001/ipfs/QmWas..." value={peerInput} // Ensure id contains only alphanumeric characters - onValueChange={value => { + onValueChange={(value) => { setAddStat({}); setPeerInput(value); }} @@ -88,23 +85,14 @@ export default function AddIpfsPeer({ peerFromUrl }: { peerFromUrl?: string }) { if (!addStat.loading) addIpfsPeer(peerInput); }} append={ - <Button - variant="dappnode" - onClick={() => addIpfsPeer(peerInput)} - disabled={addStat.loading || !peerInput} - > + <Button variant="dappnode" onClick={() => addIpfsPeer(peerInput)} disabled={addStat.loading || !peerInput}> Add peer </Button> } /> {addStat.msg && ( - <Ok - msg={addStat.msg} - ok={addStat.ok} - loading={addStat.loading} - style={{ marginTop: "1rem" }} - /> + <Ok msg={addStat.msg} ok={addStat.ok} loading={addStat.loading} style={{ marginTop: "1rem" }} /> )} </Card> </> diff --git a/packages/admin-ui/src/pages/system/components/Peers/ShareIpfsPeer.tsx b/packages/admin-ui/src/pages/system/components/Peers/ShareIpfsPeer.tsx index 770eef2b9..c59a8b78d 100644 --- a/packages/admin-ui/src/pages/system/components/Peers/ShareIpfsPeer.tsx +++ b/packages/admin-ui/src/pages/system/components/Peers/ShareIpfsPeer.tsx @@ -43,12 +43,10 @@ const ErrMsg = styled.div` `; export default function ShareIpfsPeer({ matchUrl }: { matchUrl: string }) { - const staticIp = useSelector( - (state: any) => (getDappnodeParams(state) || {}).staticIp - ); - const domain = useSelector( - (state: any) => (getDappnodeParams(state) || {}).domain - ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const staticIp = useSelector((state: any) => (getDappnodeParams(state) || {}).staticIp); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const domain = useSelector((state: any) => (getDappnodeParams(state) || {}).domain); const [peerId, setPeerId] = useState(""); const [loading, setLoading] = useState(false); @@ -75,15 +73,8 @@ export default function ShareIpfsPeer({ matchUrl }: { matchUrl: string }) { new ClipboardJS(".copy-input-copy"); }, []); - const origin = staticIp - ? `/ip4/${staticIp}` - : domain - ? `/dns4/${domain}` - : ""; - const peerMultiAddressEncoded = - origin && peerId - ? encodeURIComponent(`${origin}/tcp/4001/ipfs/${peerId}`) - : ""; + const origin = staticIp ? `/ip4/${staticIp}` : domain ? `/dns4/${domain}` : ""; + const peerMultiAddressEncoded = origin && peerId ? encodeURIComponent(`${origin}/tcp/4001/ipfs/${peerId}`) : ""; // http://my.dappnode/system/add-ipfs-peer/%2Fip4%2F1.9.207.246%2Ftcp%2F4001%2Fipfs%2FQmQnwHU6nj1v47mZQWeej4rBtYYTPrMJft88vKp9BAV38L const addMyPeerUrl = `http://my.dappnode/${matchUrl}/${peerMultiAddressEncoded}`; @@ -91,9 +82,8 @@ export default function ShareIpfsPeer({ matchUrl }: { matchUrl: string }) { return ( <Card spacing> <div> - Share this link with another DAppNode admin to automatically - peer-connect your two IPFS nodes. Use this resource to mitigate slow - IPFS propagation. + Share this link with another DAppNode admin to automatically peer-connect your two IPFS nodes. Use this resource + to mitigate slow IPFS propagation. </div> {peerId ? ( @@ -105,29 +95,20 @@ export default function ShareIpfsPeer({ matchUrl }: { matchUrl: string }) { onValueChange={() => {}} className="copy-input" append={ - <Button - className="copy-input-copy" - data-clipboard-text={addMyPeerUrl} - > + <Button className="copy-input-copy" data-clipboard-text={addMyPeerUrl}> <GoCopy /> </Button> } /> ) : null} - {!origin ? ( - <ErrMsg>Could not fetch domain or static IP</ErrMsg> - ) : null} + {!origin ? <ErrMsg>Could not fetch domain or static IP</ErrMsg> : null} {!peerId ? <ErrMsg>Could not fetch peer ID</ErrMsg> : null} </> ) : ( <Ok loading={loading} ok={Boolean(peerId)} - msg={ - loading - ? "Fetching peer ID..." - : `Error getting your peer multiaddress: ${errorMessage}` - } + msg={loading ? "Fetching peer ID..." : `Error getting your peer multiaddress: ${errorMessage}`} /> )} </Card> diff --git a/packages/admin-ui/src/pages/system/components/Peers/index.tsx b/packages/admin-ui/src/pages/system/components/Peers/index.tsx index 8350e6e70..0bb41b2af 100644 --- a/packages/admin-ui/src/pages/system/components/Peers/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Peers/index.tsx @@ -17,8 +17,7 @@ const Peers: React.FC = () => { return ( <> <p> - Learn more about IPFS peers at:{" "} - <LinkDocs href={docsUrl.ipfsPeersExplanation}>What is IPFS</LinkDocs> + Learn more about IPFS peers at: <LinkDocs href={docsUrl.ipfsPeersExplanation}>What is IPFS</LinkDocs> </p> <SubTitle>Share IPFS peer</SubTitle> <ShareIpfsPeer matchUrl={"system/" + subPaths.peers} /> diff --git a/packages/admin-ui/src/pages/system/components/PowerManagment.tsx b/packages/admin-ui/src/pages/system/components/PowerManagment.tsx index 210d77d95..1acaf2771 100644 --- a/packages/admin-ui/src/pages/system/components/PowerManagment.tsx +++ b/packages/admin-ui/src/pages/system/components/PowerManagment.tsx @@ -10,7 +10,7 @@ import { withToast } from "components/toast/Toast"; function PowerManagment() { async function reboot() { try { - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Rebooting host`, text: `Are you sure you want to reboot the host machine? Only do this if it’s strictly necessary.`, @@ -32,7 +32,7 @@ function PowerManagment() { async function powerOff() { try { // Since there are two consecutive modals, the async form must be used - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Powering off host`, text: `WARNING! Your machine will power off and you will not be able to turn it back on without physical access or a remote way to switch on the power.`, @@ -42,7 +42,7 @@ function PowerManagment() { }) ); - await new Promise<void>(resolve => + await new Promise<void>((resolve) => confirm({ title: `Are you sure?`, text: `Please make sure you have a way of turning the host machine’s power back on.`, @@ -68,8 +68,7 @@ function PowerManagment() { <div> <div className="subtle-header">REBOOT HOST</div> <p> - Only use this functionality as last resort and when all other - troubleshooting options have been exhausted. + Only use this functionality as last resort and when all other troubleshooting options have been exhausted. </p> <Button onClick={reboot} @@ -83,10 +82,7 @@ function PowerManagment() { {/* Restore backup */} <div> <div className="subtle-header">POWER OFF HOST</div> - <p> - Your machine will power off and you will not be able to access the - Admin UI until you turn it back on. - </p> + <p>Your machine will power off and you will not be able to access the Admin UI until you turn it back on.</p> <Button onClick={powerOff} // disabled={isOnProgress} diff --git a/packages/admin-ui/src/pages/system/components/Profile/ChangePassword.tsx b/packages/admin-ui/src/pages/system/components/Profile/ChangePassword.tsx index f2107d494..0c27aa78f 100644 --- a/packages/admin-ui/src/pages/system/components/Profile/ChangePassword.tsx +++ b/packages/admin-ui/src/pages/system/components/Profile/ChangePassword.tsx @@ -4,10 +4,7 @@ import ErrorView from "components/ErrorView"; import { apiAuth } from "api"; import { ReqStatus } from "types"; import Ok from "components/Ok"; -import { - validatePasswordsMatch, - validateStrongPassword -} from "utils/validation"; +import { validatePasswordsMatch, validateStrongPassword } from "utils/validation"; import { InputForm } from "components/InputForm"; export function ChangePassword() { @@ -18,12 +15,7 @@ export function ChangePassword() { const passwordError = validateStrongPassword(newPassword); const password2Error = validatePasswordsMatch(newPassword, newPassword2); - const isValid = - oldPassword && - newPassword && - newPassword2 && - !passwordError && - !password2Error; + const isValid = oldPassword && newPassword && newPassword2 && !passwordError && !password2Error; async function onChangePassword() { if (isValid) @@ -77,12 +69,7 @@ export function ChangePassword() { } ]} > - <Button - type="submit" - onClick={onChangePassword} - variant="dappnode" - disabled={reqStatus.loading} - > + <Button type="submit" onClick={onChangePassword} variant="dappnode" disabled={reqStatus.loading}> Change UI password </Button> </InputForm> diff --git a/packages/admin-ui/src/pages/system/components/Profile/SignOut.tsx b/packages/admin-ui/src/pages/system/components/Profile/SignOut.tsx index 25595c68a..a0e19c9b0 100644 --- a/packages/admin-ui/src/pages/system/components/Profile/SignOut.tsx +++ b/packages/admin-ui/src/pages/system/components/Profile/SignOut.tsx @@ -20,12 +20,7 @@ export function SignOut() { return ( <> - <Button - className="register-button" - onClick={onLogout} - variant="outline-danger" - disabled={reqStatus.loading} - > + <Button className="register-button" onClick={onLogout} variant="outline-danger" disabled={reqStatus.loading}> Sign out </Button> diff --git a/packages/admin-ui/src/pages/system/components/Profile/index.tsx b/packages/admin-ui/src/pages/system/components/Profile/index.tsx index 01f6e7f57..2d099f681 100644 --- a/packages/admin-ui/src/pages/system/components/Profile/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Profile/index.tsx @@ -10,9 +10,8 @@ export default function Profile() { <SubTitle>Change UI password</SubTitle> <Card spacing> <div> - This password is used to authorize admin access to this UI. It - protects you from Cross Site Scripting (XSS) attacks, and un-wanted - access from other users in the DAppNodeWIFI network. + This password is used to authorize admin access to this UI. It protects you from Cross Site Scripting (XSS) + attacks, and un-wanted access from other users in the DAppNodeWIFI network. </div> <ChangePassword /> diff --git a/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeHostUserPassword.tsx b/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeHostUserPassword.tsx index 7db9338ee..0a65b0169 100644 --- a/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeHostUserPassword.tsx +++ b/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeHostUserPassword.tsx @@ -1,10 +1,7 @@ import React, { useState } from "react"; import { useDispatch } from "react-redux"; import * as a from "../../../actions"; -import { - validatePasswordsMatch, - validateStrongPasswordAsDockerEnv -} from "utils/validation"; +import { validatePasswordsMatch, validateStrongPasswordAsDockerEnv } from "utils/validation"; // Components import Card from "components/Card"; import Button from "components/Button"; @@ -25,9 +22,8 @@ export default function ChangeHostUserPassword() { return ( <Card spacing> <div> - Please change the host user password. The current password is the - factory insecure default. Changing it to a strong password will protect - your DAppNode from external attackers. + Please change the host user password. The current password is the factory insecure default. Changing it to a + strong password will protect your DAppNode from external attackers. </div> <InputForm @@ -54,12 +50,7 @@ export default function ChangeHostUserPassword() { } ]} > - <Button - type="submit" - variant="dappnode" - disabled={!isValid} - onClick={onChangePassword} - > + <Button type="submit" variant="dappnode" disabled={!isValid} onClick={onChangePassword}> Change password </Button> </InputForm> diff --git a/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeWifiPassword.tsx b/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeWifiPassword.tsx index fc31f3006..f320dfb19 100644 --- a/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeWifiPassword.tsx +++ b/packages/admin-ui/src/pages/system/components/Security/securityIssues/ChangeWifiPassword.tsx @@ -27,17 +27,10 @@ export default function ChangeWifiPassword() { if (prevSsid) setSsid(prevSsid); }, [prevSsid]); - const ssidError = - validateDockerEnv(ssid, "SSID") || validateMinLength(ssid, "SSID"); + const ssidError = validateDockerEnv(ssid, "SSID") || validateMinLength(ssid, "SSID"); const passwordError = validateStrongPasswordAsDockerEnv(password); const password2Error = validatePasswordsMatch(password, password2); - const isValid = - ssid && - password && - password2 && - !ssidError && - !passwordError && - !password2Error; + const isValid = ssid && password && password2 && !ssidError && !passwordError && !password2Error; function onChangePassword() { const envs = { @@ -61,9 +54,8 @@ export default function ChangeWifiPassword() { return ( <Card spacing> <div> - Please change the WIFI credentials. The current password is the factory - insecure default. Changing it to a strong password will protect your - DAppNode from external attackers. + Please change the WIFI credentials. The current password is the factory insecure default. Changing it to a + strong password will protect your DAppNode from external attackers. </div> <InputForm @@ -99,12 +91,7 @@ export default function ChangeWifiPassword() { } ]} > - <Button - type="submit" - variant="dappnode" - disabled={!isValid} - onClick={onChangePassword} - > + <Button type="submit" variant="dappnode" disabled={!isValid} onClick={onChangePassword}> Change password </Button> </InputForm> diff --git a/packages/admin-ui/src/pages/system/components/Security/securityIssues/SeverityBadge.tsx b/packages/admin-ui/src/pages/system/components/Security/securityIssues/SeverityBadge.tsx index b23d25b59..37b10c964 100644 --- a/packages/admin-ui/src/pages/system/components/Security/securityIssues/SeverityBadge.tsx +++ b/packages/admin-ui/src/pages/system/components/Security/securityIssues/SeverityBadge.tsx @@ -12,13 +12,8 @@ const CriticalSeverity = styled.span` border-radius: 2px; `; -export default function SecurityBadge({ - severity -}: { - severity: SeverityLevel; -}) { - if (severity === "critical") - return <CriticalSeverity>Address immediately</CriticalSeverity>; +export default function SecurityBadge({ severity }: { severity: SeverityLevel }) { + if (severity === "critical") return <CriticalSeverity>Address immediately</CriticalSeverity>; // Develop other levels as they become necessary else return <CriticalSeverity>Address immediately</CriticalSeverity>; } diff --git a/packages/admin-ui/src/pages/system/components/Security/securityIssues/index.tsx b/packages/admin-ui/src/pages/system/components/Security/securityIssues/index.tsx index 2ead3789a..18237e93b 100644 --- a/packages/admin-ui/src/pages/system/components/Security/securityIssues/index.tsx +++ b/packages/admin-ui/src/pages/system/components/Security/securityIssues/index.tsx @@ -9,10 +9,7 @@ import ChangeHostUserPassword from "./ChangeHostUserPassword"; import ChangeWifiPassword from "./ChangeWifiPassword"; import Ok from "components/Ok"; // External -import { - getPasswordIsSecure, - getWifiStatus -} from "services/dappnodeStatus/selectors"; +import { getPasswordIsSecure, getWifiStatus } from "services/dappnodeStatus/selectors"; // Style import "./securityIssues.scss"; @@ -40,16 +37,12 @@ export default function SecurityIssues() { name: "Change WIFI default password", severity: "critical", component: ChangeWifiPassword, - isActive: Boolean( - wifiStatus?.isDefaultPassphrase && wifiStatus?.isRunning - ), - okMessage: wifiStatus?.isRunning - ? "WIFI credentials changed" - : "WIFI is disabled" + isActive: Boolean(wifiStatus?.isDefaultPassphrase && wifiStatus?.isRunning), + okMessage: wifiStatus?.isRunning ? "WIFI credentials changed" : "WIFI is disabled" } ]; - const issuesToShow = securityIssues.filter(issue => issue.isActive); + const issuesToShow = securityIssues.filter((issue) => issue.isActive); const areActiveIssues = issuesToShow.length > 0; return ( @@ -57,25 +50,17 @@ export default function SecurityIssues() { <Card spacing> <StatusIcon success={!areActiveIssues} - message={ - areActiveIssues - ? "Some issues require your attention" - : "Issues addressed" - } + message={areActiveIssues ? "Some issues require your attention" : "Issues addressed"} /> <hr /> <div> - {securityIssues.map(issue => ( - <Ok - key={issue.name} - msg={issue.isActive ? issue.name : issue.okMessage} - ok={!issue.isActive} - /> + {securityIssues.map((issue) => ( + <Ok key={issue.name} msg={issue.isActive ? issue.name : issue.okMessage} ok={!issue.isActive} /> ))} </div> </Card> - {issuesToShow.map(issue => ( + {issuesToShow.map((issue) => ( <React.Fragment key={issue.name}> <div className="security-issue-header"> <SubTitle>{issue.name}</SubTitle> diff --git a/packages/admin-ui/src/pages/system/components/SystemRoot.tsx b/packages/admin-ui/src/pages/system/components/SystemRoot.tsx index 98281bfcf..2d8034fee 100644 --- a/packages/admin-ui/src/pages/system/components/SystemRoot.tsx +++ b/packages/admin-ui/src/pages/system/components/SystemRoot.tsx @@ -20,6 +20,7 @@ const SystemRoot: React.FC = () => { name: string; subLink: string; subPath: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any component: React.ComponentType<any>; hideFromMenu?: boolean; }[] = [ @@ -98,14 +99,10 @@ const SystemRoot: React.FC = () => { <div className="horizontal-navbar"> {availableRoutes - .filter(route => !route.hideFromMenu) - .map(route => ( + .filter((route) => !route.hideFromMenu) + .map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subLink} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subLink} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -114,12 +111,8 @@ const SystemRoot: React.FC = () => { <div className="section-spacing"> <Routes> - {availableRoutes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {availableRoutes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/system/components/SystemUpdate/SystemUpdateDetails.tsx b/packages/admin-ui/src/pages/system/components/SystemUpdate/SystemUpdateDetails.tsx index 65db158e2..0be952424 100644 --- a/packages/admin-ui/src/pages/system/components/SystemUpdate/SystemUpdateDetails.tsx +++ b/packages/admin-ui/src/pages/system/components/SystemUpdate/SystemUpdateDetails.tsx @@ -30,11 +30,7 @@ export default function SystemUpdateDetails() { {coreChangelog && <RenderMarkdown source={coreChangelog} />} {updateAlerts.map(({ from, to, message }) => ( - <div - key={from + to} - className="alert alert-warning" - style={{ margin: "12px 0 6px 0" }} - > + <div key={from + to} className="alert alert-warning" style={{ margin: "12px 0 6px 0" }}> {/* If there are multiple alerts, display the update jump */} {updateAlerts.length > 1 && ( <div style={{ fontWeight: "bold" }}> @@ -59,14 +55,10 @@ export default function SystemUpdateDetails() { * Returns core dependencies, * unless the core package is the only one, then returns it */ -export function getCoreDeps( - corePackages: DependencyListItem[] -): DependencyListItem[] { - const coreDeps = corePackages.filter( - dnp => !(dnp.name || "").includes("core") - ); +export function getCoreDeps(corePackages: DependencyListItem[]): DependencyListItem[] { + const coreDeps = corePackages.filter((dnp) => !(dnp.name || "").includes("core")); if (coreDeps.length) return coreDeps; - const coreDnp = corePackages.find(dnp => (dnp.name || "").includes("core")); + const coreDnp = corePackages.find((dnp) => (dnp.name || "").includes("core")); return coreDnp ? [coreDnp] : []; } diff --git a/packages/admin-ui/src/pages/system/components/SystemUpdate/index.tsx b/packages/admin-ui/src/pages/system/components/SystemUpdate/index.tsx index f2c2caad4..8fcba5096 100644 --- a/packages/admin-ui/src/pages/system/components/SystemUpdate/index.tsx +++ b/packages/admin-ui/src/pages/system/components/SystemUpdate/index.tsx @@ -3,10 +3,7 @@ import { useSelector } from "react-redux"; import { coreDnpName } from "params"; // Selectors import { getProgressLogsOfDnp } from "services/isInstallingLogs/selectors"; -import { - getCoreUpdateAvailable, - getCoreRequestStatus -} from "services/coreUpdate/selectors"; +import { getCoreUpdateAvailable, getCoreRequestStatus } from "services/coreUpdate/selectors"; // Components import Card from "components/Card"; import StatusIcon from "components/StatusIcon"; @@ -17,9 +14,8 @@ import ErrorView from "components/ErrorView"; import { ProgressLogsView } from "pages/installer/components/InstallCardComponents/ProgressLogsView"; export default function SystemUpdate() { - const coreProgressLogs = useSelector((state: any) => - getProgressLogsOfDnp(state, coreDnpName) - ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const coreProgressLogs = useSelector((state: any) => getProgressLogsOfDnp(state, coreDnpName)); const { loading, success, error } = useSelector(getCoreRequestStatus); const coreUpdateAvailable = useSelector(getCoreUpdateAvailable); diff --git a/packages/admin-ui/src/pages/system/components/VolumesGrid.tsx b/packages/admin-ui/src/pages/system/components/VolumesGrid.tsx index a9416deac..ffdf39dd0 100644 --- a/packages/admin-ui/src/pages/system/components/VolumesGrid.tsx +++ b/packages/admin-ui/src/pages/system/components/VolumesGrid.tsx @@ -8,11 +8,7 @@ import Badge from "react-bootstrap/Badge"; import { MdExpandMore, MdExpandLess, MdDelete } from "react-icons/md"; import { MountpointDataView } from "components/SetupWizard/SelectMountpoint"; import { rootPath as packagesRootPath } from "pages/packages/data"; -import { - getPrettyVolumeName, - getPrettyVolumeOwner, - prettyBytes -} from "utils/format"; +import { getPrettyVolumeName, getPrettyVolumeOwner, prettyBytes } from "utils/format"; import { parseStaticDate } from "utils/dates"; import { joinCssClass } from "utils/css"; import { VolumeData } from "@dappnode/types"; @@ -36,34 +32,30 @@ export default function VolumesGrid() { const volumesFiltered = [...volumes] .sort((v1, v2) => getSize(v2) - getSize(v1)) .sort((v1, v2) => (v1.isOrphan && !v2.isOrphan ? -1 : 1)) - .filter(v => showAll || getSize(v) > minSize) + .filter((v) => showAll || getSize(v) > minSize) .slice(0, showAll ? volumes.length : shortLength); // Optimize the view hidding features when no element is using them - const showRemove = showAll || volumesFiltered.some(v => v.isOrphan); - const showMountpoint = showAll || volumesFiltered.some(v => v.mountpoint); + const showRemove = showAll || volumesFiltered.some((v) => v.isOrphan); + const showMountpoint = showAll || volumesFiltered.some((v) => v.mountpoint); return ( - <Card - className={ - "list-grid volumes " + joinCssClass({ showRemove, showMountpoint }) - } - > + <Card className={"list-grid volumes " + joinCssClass({ showRemove, showMountpoint })}> <header>Name</header> <header className="center">Size</header> {showMountpoint && <header className="center">Mountpoint</header>} <header className="center">Created at</header> {showRemove && <header>Remove</header>} - {volumesFiltered.map(volData => { + {volumesFiltered.map((volData) => { const { name, owner, size, createdAt, isOrphan, fileSystem } = volData; const ownerPretty = getPrettyVolumeOwner(volData); const namePretty = getPrettyVolumeName(volData); const onDelete = isOrphan ? () => dispatch(volumeRemove(name)) : owner - ? () => dispatch(packageVolumeRemove(owner, name)) - : () => {}; + ? () => dispatch(packageVolumeRemove(owner, name)) + : () => {}; const isDeletable = Boolean(isOrphan || owner); return ( @@ -71,10 +63,7 @@ export default function VolumesGrid() { <div className="name"> <span className="text"> {owner ? ( - <NavLink - className="owner" - to={`${packagesRootPath}/${owner}`} - > + <NavLink className="owner" to={`${packagesRootPath}/${owner}`}> {ownerPretty} </NavLink> ) : ownerPretty ? ( @@ -95,10 +84,10 @@ export default function VolumesGrid() { {!size && fileSystem ? ( <OverlayTrigger placement="right" + // eslint-disable-next-line @typescript-eslint/no-explicit-any overlay={(props: any) => ( <Tooltip {...props}> - Can't get the exact volume size, use the mountpoint total - size as an approximate upper reference + Can't get the exact volume size, use the mountpoint total size as an approximate upper reference </Tooltip> )} > @@ -109,25 +98,14 @@ export default function VolumesGrid() { )} </div> {showMountpoint && - (fileSystem ? ( - <MountpointDataView - fileSystem={fileSystem} - ></MountpointDataView> - ) : ( - "Docker volume" - ))} + (fileSystem ? <MountpointDataView fileSystem={fileSystem}></MountpointDataView> : "Docker volume")} <div className="created-at">{parseStaticDate(createdAt, true)}</div> - {showRemove && ( - <MdDelete - className={isDeletable ? "" : "disabled"} - onClick={onDelete} - /> - )} + {showRemove && <MdDelete className={isDeletable ? "" : "disabled"} onClick={onDelete} />} <hr /> </React.Fragment> ); })} - <div className="subtle-header" onClick={() => setShowAll(x => !x)}> + <div className="subtle-header" onClick={() => setShowAll((x) => !x)}> {showAll ? <MdExpandLess /> : <MdExpandMore />} <span>Show {showAll ? "less" : "all"}</span> </div> diff --git a/packages/admin-ui/src/pages/system/index.ts b/packages/admin-ui/src/pages/system/index.ts index ed9f8f2ee..f70d19a68 100644 --- a/packages/admin-ui/src/pages/system/index.ts +++ b/packages/admin-ui/src/pages/system/index.ts @@ -1,4 +1,4 @@ import System from "./components/SystemRoot"; -export { rootPath, relativePath, pathName } from "./data"; +export { rootPath, relativePath, pathName } from "./data"; export const RootComponent = System; diff --git a/packages/admin-ui/src/pages/vpn/components/VpnHome.tsx b/packages/admin-ui/src/pages/vpn/components/VpnHome.tsx index 5dab748f6..b28551721 100644 --- a/packages/admin-ui/src/pages/vpn/components/VpnHome.tsx +++ b/packages/admin-ui/src/pages/vpn/components/VpnHome.tsx @@ -12,14 +12,13 @@ export function VpnHome() { const dnpsRequest = useApi.packagesGet(); const availableRoutes = useMemo(() => { - const dnpsSet = dnpsRequest.data - ? new Set(dnpsRequest.data.map(dnp => dnp.dnpName)) - : new Set<string>(); + const dnpsSet = dnpsRequest.data ? new Set(dnpsRequest.data.map((dnp) => dnp.dnpName)) : new Set<string>(); const routes: { name: string; subPath: string; subLink: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any component: React.ComponentType<any>; installed: boolean; }[] = [ @@ -39,22 +38,16 @@ export function VpnHome() { } ]; - return routes.sort((a, b) => - a.installed && !b.installed ? -1 : !a.installed && b.installed ? 1 : 0 - ); + return routes.sort((a, b) => (a.installed && !b.installed ? -1 : !a.installed && b.installed ? 1 : 0)); }, [dnpsRequest.data]); return ( <> <Title title={title} /> <div className="horizontal-navbar"> - {availableRoutes.map(route => ( + {availableRoutes.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subLink} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subLink} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -62,21 +55,15 @@ export function VpnHome() { </div> <p> - Create a VPN profile for each of your devices (laptop, phone) so you can - access your Dappnode from an external network. Learn more about VPN at:{" "} - <LinkDocs href={docsUrl.connectVpn}> - How to connect to your Dappnode VPN - </LinkDocs> + Create a VPN profile for each of your devices (laptop, phone) so you can access your Dappnode from an external + network. Learn more about VPN at:{" "} + <LinkDocs href={docsUrl.connectVpn}>How to connect to your Dappnode VPN</LinkDocs> </p> <div className="section-spacing"> <Routes> - {availableRoutes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {availableRoutes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDeviceDetails.tsx b/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDeviceDetails.tsx index a6e676e8b..c48a069e3 100755 --- a/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDeviceDetails.tsx +++ b/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDeviceDetails.tsx @@ -21,11 +21,7 @@ import { GoCopy } from "react-icons/go"; import { urlJoin } from "utils/url"; import { VpnDeviceCredentials } from "@dappnode/types"; -function OpenVpnDeviceDetailsLoaded({ - device -}: { - device: VpnDeviceCredentials; -}) { +function OpenVpnDeviceDetailsLoaded({ device }: { device: VpnDeviceCredentials }) { const [showQr, setShowQr] = useState(false); const { id, url } = device; @@ -66,15 +62,12 @@ function OpenVpnDeviceDetailsLoaded({ /> </Form.Group> - <Button onClick={() => setShowQr(!showQr)}> - {showQr ? "Hide" : "Show"} VPN credentials URL QR code - </Button> + <Button onClick={() => setShowQr(!showQr)}>{showQr ? "Hide" : "Show"} VPN credentials URL QR code</Button> {device.admin ? ( device.hasChangedPassword ? ( <Alert variant="info"> - This admin user has already changed the password. Only the initial - auto-generated password is visible + This admin user has already changed the password. Only the initial auto-generated password is visible </Alert> ) : ( <> @@ -87,10 +80,7 @@ function OpenVpnDeviceDetailsLoaded({ className="copy-input" append={ <> - <Button - className="copy-input-copy" - data-clipboard-text={device.id} - > + <Button className="copy-input-copy" data-clipboard-text={device.id}> <GoCopy /> </Button> </> @@ -106,10 +96,7 @@ function OpenVpnDeviceDetailsLoaded({ className="copy-input" append={ <> - <Button - className="copy-input-copy" - data-clipboard-text={device.password} - > + <Button className="copy-input-copy" data-clipboard-text={device.password}> <GoCopy /> </Button> </> @@ -123,8 +110,7 @@ function OpenVpnDeviceDetailsLoaded({ {showQr && url && <QrCode url={url} width={"400px"} />} <div className="alert alert-secondary" role="alert"> - Beware of shoulder surfing attacks (unsolicited observers), This data - grants admin access to your DAppNode + Beware of shoulder surfing attacks (unsolicited observers), This data grants admin access to your DAppNode </div> </Card> ); diff --git a/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDevicesHome.tsx b/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDevicesHome.tsx index cd794d57e..61430d890 100755 --- a/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDevicesHome.tsx +++ b/packages/admin-ui/src/pages/vpn/components/openvpn/OpenVpnDevicesHome.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ import React, { useState } from "react"; import { api, useApi } from "api"; import { NavLink, useNavigate } from "react-router-dom"; @@ -52,9 +51,7 @@ export default function OpenVpnDevicesHome() { function resetDevice(id: string) { const isMainAdmin = id === MAIN_ADMIN_NAME; confirm({ - title: isMainAdmin - ? `WARNING! Reseting main admin` - : `Reseting ${id} device`, + title: isMainAdmin ? `WARNING! Reseting main admin` : `Reseting ${id} device`, text: isMainAdmin ? "You should only reset the credentials of the main admin if you suspect an unwanted party gained access to this credentials. If that is the case, reset the credentials, BUT download and install the new credentials IMMEDIATELY. Otherwise, you will lose access to your DAppNode when this connection stops" : "All profiles and links pointing to this device will no longer be valid", @@ -76,12 +73,11 @@ export default function OpenVpnDevicesHome() { // Input errors const errors: string[] = []; - if (input.length > maxIdLength) - errors.push(`Device name must be shorter than {maxIdLength} characters`); + if (input.length > maxIdLength) errors.push(`Device name must be shorter than {maxIdLength} characters`); // If the OpenVPN package (known as vpn) is not installed, invite the user to install it if (dnpsRequest.data) { - const vpnDnp = dnpsRequest.data.find(dnp => dnp.dnpName === vpnDnpName); + const vpnDnp = dnpsRequest.data.find((dnp) => dnp.dnpName === vpnDnpName); if (!vpnDnp) { const url = `${getInstallerPath(vpnDnpName)}/${vpnDnpName}`; return ( @@ -102,27 +98,23 @@ export default function OpenVpnDevicesHome() { placeholder="Device's unique name" value={input} // Ensure id contains only alphanumeric characters - onValueChange={value => setInput(coerceDeviceName(value))} + onValueChange={(value) => setInput(coerceDeviceName(value))} onEnterPress={() => { addDevice(input); setInput(""); }} append={ - <Button - variant="dappnode" - onClick={() => addDevice(input)} - disabled={errors.length > 0} - > + <Button variant="dappnode" onClick={() => addDevice(input)} disabled={errors.length > 0}> Add device </Button> } /> - {errors.map(error => ( + {errors.map((error) => ( <div className="color-danger">{error}</div> ))} - {renderResponse(devicesReq, ["Loading devices"], data => ( + {renderResponse(devicesReq, ["Loading devices"], (data) => ( <Card className="list-grid devices"> <header>Name</header> <header className="center">Credentials</header> @@ -131,7 +123,7 @@ export default function OpenVpnDevicesHome() { <header>Remove</header> {[...data] // Sort main admin device as first - .sort(d1 => (d1.id === MAIN_ADMIN_NAME ? -1 : 0)) + .sort((d1) => (d1.id === MAIN_ADMIN_NAME ? -1 : 0)) .map(({ id, admin }) => ( <React.Fragment key={id}> <div className="name">{id}</div> @@ -139,18 +131,9 @@ export default function OpenVpnDevicesHome() { <Button className="get-link">Get</Button> </NavLink> - <Switch - checked={admin} - onToggle={() => toggleAdmin(id, !admin)} - /> - <MdRefresh - style={{ fontSize: "1.05rem" }} - onClick={() => resetDevice(id)} - /> - <MdDelete - className={admin ? "disabled" : ""} - onClick={() => (admin ? null : removeDevice(id))} - /> + <Switch checked={admin} onToggle={() => toggleAdmin(id, !admin)} /> + <MdRefresh style={{ fontSize: "1.05rem" }} onClick={() => resetDevice(id)} /> + <MdDelete className={admin ? "disabled" : ""} onClick={() => (admin ? null : removeDevice(id))} /> <hr /> </React.Fragment> ))} diff --git a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDeviceDetails.tsx b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDeviceDetails.tsx index 10108bbdf..acdd78b8e 100755 --- a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDeviceDetails.tsx +++ b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDeviceDetails.tsx @@ -21,13 +21,7 @@ import { WireguardDeviceCredentials } from "@dappnode/types"; // Utils import { urlJoin } from "utils/url"; -function WireguardDeviceDetailsLoaded({ - id, - device -}: { - id: string; - device: WireguardDeviceCredentials; -}) { +function WireguardDeviceDetailsLoaded({ id, device }: { id: string; device: WireguardDeviceCredentials }) { const [showQr, setShowQr] = useState(false); const [showLocalCreds, setShowLocalCreds] = useState(false); const config = showLocalCreds ? device.configLocal : device.configRemote; @@ -51,15 +45,9 @@ function WireguardDeviceDetailsLoaded({ <div className="help-text"> Add the following VPN configuration in your Wireguard client. <br /> <br /> - In case you experience issues connecting from the same network as your - dappnode, use the local credentials.{" "} - <span - className="show-local-credentials" - onClick={() => setShowLocalCreds(x => !x)} - > - {showLocalCreds - ? "Go back to showing remote credentials" - : "Show local credentials"} + In case you experience issues connecting from the same network as your dappnode, use the local credentials.{" "} + <span className="show-local-credentials" onClick={() => setShowLocalCreds((x) => !x)}> + {showLocalCreds ? "Go back to showing remote credentials" : "Show local credentials"} </span> </div> @@ -103,8 +91,7 @@ function WireguardDeviceDetailsLoaded({ {showQr && config && <QrCode url={config} width={"400px"} />} <div className="alert alert-secondary" role="alert"> - Beware of shoulder surfing attacks (unsolicited observers), This data - grants access to your DAppNode + Beware of shoulder surfing attacks (unsolicited observers), This data grants access to your DAppNode </div> </Card> ); diff --git a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesHome.tsx b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesHome.tsx index e27fb7d99..fdae09750 100755 --- a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesHome.tsx +++ b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesHome.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ import React, { useState } from "react"; import { api, useApi } from "api"; import { NavLink, useNavigate } from "react-router-dom"; @@ -50,26 +49,16 @@ export function WireguardDevicesHome() { // Input errors const errors: string[] = []; - if (input.length > maxIdLength) - errors.push(`Device name must be shorter than {maxIdLength} characters`); + if (input.length > maxIdLength) errors.push(`Device name must be shorter than {maxIdLength} characters`); // If the wireguard package is not installed, invite the user to install it if (dnpsRequest.data) { - const wireguardDnp = dnpsRequest.data.find( - dnp => dnp.dnpName === wireguardDnpName - ); + const wireguardDnp = dnpsRequest.data.find((dnp) => dnp.dnpName === wireguardDnpName); if (!wireguardDnp) { return ( <Alert variant="secondary"> You must{" "} - <a - href="#" - onClick={() => - navigate( - `${getInstallerPath(wireguardDnpName)}/${wireguardDnpName}` - ) - } - > + <a href="#" onClick={() => navigate(`${getInstallerPath(wireguardDnpName)}/${wireguardDnpName}`)}> install the Wireguard package </a>{" "} to use this feature @@ -84,35 +73,31 @@ export function WireguardDevicesHome() { placeholder="Device's unique name" value={input} // Ensure id contains only alphanumeric characters - onValueChange={value => setInput(coerceDeviceName(value))} + onValueChange={(value) => setInput(coerceDeviceName(value))} onEnterPress={() => { addDevice(input); setInput(""); }} append={ - <Button - variant="dappnode" - onClick={() => addDevice(input)} - disabled={errors.length > 0} - > + <Button variant="dappnode" onClick={() => addDevice(input)} disabled={errors.length > 0}> Add device </Button> } /> - {errors.map(error => ( + {errors.map((error) => ( <div className="color-danger">{error}</div> ))} - {renderResponse(devicesReq, ["Loading devices"], data => ( + {renderResponse(devicesReq, ["Loading devices"], (data) => ( <Card className="list-grid wireguard"> <header>Name</header> <header className="center">Credentials</header> <header>Remove</header> {[...data] // Sort main admin device as first - .sort(d1 => (d1 === MAIN_ADMIN_NAME ? -1 : 0)) - .map(id => ( + .sort((d1) => (d1 === MAIN_ADMIN_NAME ? -1 : 0)) + .map((id) => ( <React.Fragment key={id}> <div className="name">{id}</div> <NavLink to={id} className="no-a-style"> diff --git a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesRoot.tsx b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesRoot.tsx index 5d8bd2f46..f12f8c90e 100755 --- a/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesRoot.tsx +++ b/packages/admin-ui/src/pages/vpn/components/wireguard/WireguardDevicesRoot.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ import React from "react"; import { useApi } from "api"; import { useNavigate, Route, Routes } from "react-router-dom"; @@ -18,39 +17,28 @@ export const WireguardDevicesRoot: React.FC = () => { const dnpsRequest = useApi.packagesGet(); const navigate = useNavigate(); - return renderResponse( - dnpsRequest, - ["Loading installed DAppNode Packages"], - dnps => { - const wireguardDnp = dnps.find(dnp => dnp.dnpName === wireguardDnpName); - if (!wireguardDnp) { - return ( - <> - <Title title={title} /> - <Alert variant="secondary"> - You must{" "} - <a - href="#" - onClick={() => - navigate( - `${getInstallerPath(wireguardDnpName)}/${wireguardDnpName}` - ) - } - > - install the Wireguard package - </a>{" "} - to use this feature - </Alert> - </> - ); - } - + return renderResponse(dnpsRequest, ["Loading installed DAppNode Packages"], (dnps) => { + const wireguardDnp = dnps.find((dnp) => dnp.dnpName === wireguardDnpName); + if (!wireguardDnp) { return ( - <Routes> - <Route path={"/"} element={<WireguardDevicesHome />} /> - <Route path=":id" element={<WireguardDeviceDetails />} /> - </Routes> + <> + <Title title={title} /> + <Alert variant="secondary"> + You must{" "} + <a href="#" onClick={() => navigate(`${getInstallerPath(wireguardDnpName)}/${wireguardDnpName}`)}> + install the Wireguard package + </a>{" "} + to use this feature + </Alert> + </> ); } - ); + + return ( + <Routes> + <Route path={"/"} element={<WireguardDevicesHome />} /> + <Route path=":id" element={<WireguardDeviceDetails />} /> + </Routes> + ); + }); }; diff --git a/packages/admin-ui/src/pages/wifi/components/WifiLocalHome.tsx b/packages/admin-ui/src/pages/wifi/components/WifiLocalHome.tsx index 8ad55cd9b..e9a69760e 100644 --- a/packages/admin-ui/src/pages/wifi/components/WifiLocalHome.tsx +++ b/packages/admin-ui/src/pages/wifi/components/WifiLocalHome.tsx @@ -13,6 +13,7 @@ export const WifiLocalHome: React.FC = () => { const availableRoutes: { name: string; subPath: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any component: React.ComponentType<any>; }[] = [ { @@ -31,13 +32,9 @@ export const WifiLocalHome: React.FC = () => { <> <Title title={title} /> <div className="horizontal-navbar"> - {availableRoutes.map(route => ( + {availableRoutes.map((route) => ( <button key={route.subPath} className="item-container"> - <NavLink - to={route.subPath} - className="item no-a-style" - style={{ whiteSpace: "nowrap" }} - > + <NavLink to={route.subPath} className="item no-a-style" style={{ whiteSpace: "nowrap" }}> {route.name} </NavLink> </button> @@ -46,12 +43,8 @@ export const WifiLocalHome: React.FC = () => { <div className="section-spacing"> <Routes> - {availableRoutes.map(route => ( - <Route - key={route.subPath} - path={route.subPath} - element={<route.component />} - /> + {availableRoutes.map((route) => ( + <Route key={route.subPath} path={route.subPath} element={<route.component />} /> ))} </Routes> </div> diff --git a/packages/admin-ui/src/pages/wifi/components/localProxying/LocalProxying.tsx b/packages/admin-ui/src/pages/wifi/components/localProxying/LocalProxying.tsx index 5b252a7e5..787610837 100644 --- a/packages/admin-ui/src/pages/wifi/components/localProxying/LocalProxying.tsx +++ b/packages/admin-ui/src/pages/wifi/components/localProxying/LocalProxying.tsx @@ -1,4 +1,3 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ // React import React, { useState } from "react"; import { useSelector } from "react-redux"; @@ -36,7 +35,7 @@ export function LocalProxying() { const isLocalProxyingRunning = localProxyingStatus.data === "running"; if (isLocalProxyingRunning) - await new Promise<void>(resolve => { + await new Promise<void>((resolve) => { confirm({ title: `Stopping Local Network Proxy`, text: `Warning, if you are connected to your DAppNode through Local Network Proxy you may lose access to your DAppNode. Make sure to have an alternative way to connect to it, like WiFi or a VPN connection.`, @@ -46,17 +45,10 @@ export function LocalProxying() { }); setReqStatus({ loading: true }); - await withToast( - () => api.localProxyingEnableDisable(!isLocalProxyingRunning), - { - message: isLocalProxyingRunning - ? "Stopping Local Network Proxy..." - : "Starting Local Network Proxy", - onSuccess: isLocalProxyingRunning - ? "Stopped Local Network Proxy..." - : "Started Local Network Proxy" - } - ); + await withToast(() => api.localProxyingEnableDisable(!isLocalProxyingRunning), { + message: isLocalProxyingRunning ? "Stopping Local Network Proxy..." : "Starting Local Network Proxy", + onSuccess: isLocalProxyingRunning ? "Stopped Local Network Proxy..." : "Started Local Network Proxy" + }); setReqStatus({ result: true }); localProxyingStatus.revalidate(); @@ -70,20 +62,10 @@ export function LocalProxying() { return ( <Alert variant="secondary"> You must{" "} - <a - href="#" - onClick={() => - navigate( - `${getInstallerPath(httpsPortalDnpName)}/${httpsPortalDnpName}` - ) - } - > + <a href="#" onClick={() => navigate(`${getInstallerPath(httpsPortalDnpName)}/${httpsPortalDnpName}`)}> install the HTTPs Portal </a>{" "} - to use this feature.{" "} - <LinkDocs href={docsUrl.connectLocalProxy}> - Learn more about Local Network - </LinkDocs> + to use this feature. <LinkDocs href={docsUrl.connectLocalProxy}>Learn more about Local Network</LinkDocs> </Alert> ); } @@ -93,31 +75,23 @@ export function LocalProxying() { {localProxyingStatus.data ? ( <Card spacing> <p> - If you are connected to the same router as your DAppNode you can use - this page at <a href={adminUiLocalDomain}>{adminUiLocalDomain}</a>. - Learn more about the Local Network Proxy at:{" "} - <LinkDocs href={docsUrl.connectLocalProxy}> - How to connect to DAppNode Local Network Proxy - </LinkDocs> + If you are connected to the same router as your DAppNode you can use this page at{" "} + <a href={adminUiLocalDomain}>{adminUiLocalDomain}</a>. Learn more about the Local Network Proxy at:{" "} + <LinkDocs href={docsUrl.connectLocalProxy}>How to connect to DAppNode Local Network Proxy</LinkDocs> </p> {dappnodeIdentity.internalIp === dappnodeIdentity.ip && ( <p> - Local and public IPs are equal. This may be due to dappnode is - running on a remote machine and does not require Local Network - Proxy. + Local and public IPs are equal. This may be due to dappnode is running on a remote machine and does not + require Local Network Proxy. </p> )} <hr /> <div className="wifi-local-status-actions-row"> <div className="wifi-local-status-container"> - <StateBadge - {...parseAvahiPublishCmdState(localProxyingStatus.data)} - /> + <StateBadge {...parseAvahiPublishCmdState(localProxyingStatus.data)} /> <MdWifi className="wifi-local-status-icon" /> - <span className="wifi-local-status-name"> - Local Network Proxy - </span> + <span className="wifi-local-status-name">Local Network Proxy</span> </div> <div className="wifi-local-actions"> diff --git a/packages/admin-ui/src/pages/wifi/components/wifi/WifiCredentials.tsx b/packages/admin-ui/src/pages/wifi/components/wifi/WifiCredentials.tsx index 1b66cf502..ca3f4da26 100644 --- a/packages/admin-ui/src/pages/wifi/components/wifi/WifiCredentials.tsx +++ b/packages/admin-ui/src/pages/wifi/components/wifi/WifiCredentials.tsx @@ -25,21 +25,13 @@ export default function WifiCredentials(): JSX.Element { useEffect(() => { if (wifiCredentials.data?.ssid) setSsid(wifiCredentials.data.ssid); - if (wifiCredentials.data?.password) - setPassword(wifiCredentials.data.password); + if (wifiCredentials.data?.password) setPassword(wifiCredentials.data.password); }, [wifiCredentials.data]); - const ssidError = - validateDockerEnv(ssid, "SSID") || validateMinLength(ssid, "SSID"); + const ssidError = validateDockerEnv(ssid, "SSID") || validateMinLength(ssid, "SSID"); const passwordError = validateStrongPasswordAsDockerEnv(password); const password2Error = validatePasswordsMatch(password, password2); - const isValid = - ssid && - password && - password2 && - !ssidError && - !passwordError && - !password2Error; + const isValid = ssid && password && password2 && !ssidError && !passwordError && !password2Error; async function onChangeCredentials() { const envs = { @@ -100,12 +92,7 @@ export default function WifiCredentials(): JSX.Element { } ]} > - <Button - type="submit" - variant="dappnode" - disabled={!isValid} - onClick={() => onChangeCredentials()} - > + <Button type="submit" variant="dappnode" disabled={!isValid} onClick={() => onChangeCredentials()}> Change credentials </Button> </InputForm> diff --git a/packages/admin-ui/src/pages/wifi/components/wifi/WifiStatus.tsx b/packages/admin-ui/src/pages/wifi/components/wifi/WifiStatus.tsx index b43f6e18f..d9c4d9e14 100644 --- a/packages/admin-ui/src/pages/wifi/components/wifi/WifiStatus.tsx +++ b/packages/admin-ui/src/pages/wifi/components/wifi/WifiStatus.tsx @@ -27,13 +27,9 @@ function WifiInfo({ wifiStatus }: { wifiStatus: ContainerState }) { const dappnodeIdentity = useSelector(getDappnodeIdentityClean); return ( <p> - Connect to the Wi-Fi hotspot exposed by your DAppNode using your - credentials. More information at:{" "} - <LinkDocs href={docsUrl.connectWifi}> - How to connect to DAppNode WiFi - </LinkDocs> - {dappnodeIdentity.internalIp === dappnodeIdentity.ip && - wifiStatus !== "running" + Connect to the Wi-Fi hotspot exposed by your DAppNode using your credentials. More information at:{" "} + <LinkDocs href={docsUrl.connectWifi}>How to connect to DAppNode WiFi</LinkDocs> + {dappnodeIdentity.internalIp === dappnodeIdentity.ip && wifiStatus !== "running" ? "Local and public IPs are equal. This may be due to dappnode is running on a remote machine and does not require Wi-Fi." : null} </p> @@ -47,9 +43,7 @@ function WifiLog({ wifiReport }: { wifiReport: WifiReport }) { <p>{wifiReport.info}</p> {wifiReport.report ? ( - <div className="error-stack"> - {`${wifiReport.report.lastLog}. Exit code: ${wifiReport.report.exitCode}`} - </div> + <div className="error-stack">{`${wifiReport.report.lastLog}. Exit code: ${wifiReport.report.exitCode}`}</div> ) : null} </> ); @@ -72,7 +66,7 @@ export default function WifiStatus(): JSX.Element { try { if (wifiDnp.data) { if (wifiDnp.data.containers[0].state === "running") - await new Promise<void>(resolve => { + await new Promise<void>((resolve) => { confirm({ title: `Pause wifi service`, text: `Warning, if you are connected to your DAppNode's WIFI you may lose access to your DAppNode. Make sure to have an alternative way to connect to it, like a VPN connection.`, @@ -82,26 +76,17 @@ export default function WifiStatus(): JSX.Element { }); await withToast( - continueIfCalleDisconnected( - () => api.packageStartStop({ dnpName: wifiDnpName }), - wifiDnpName - ), + continueIfCalleDisconnected(() => api.packageStartStop({ dnpName: wifiDnpName }), wifiDnpName), { - message: - wifiDnp.data.containers[0].state === "running" - ? "Pausing wifi" - : "Starting wifi", - onSuccess: - wifiDnp.data.containers[0].state === "running" - ? "Paused wifi" - : "Started wifi" + message: wifiDnp.data.containers[0].state === "running" ? "Pausing wifi" : "Starting wifi", + onSuccess: wifiDnp.data.containers[0].state === "running" ? "Paused wifi" : "Started wifi" } ); wifiReport.revalidate(); } } catch (e) { - console.error("Error on start/stop wifi package"); + console.error(`Error on start/stop wifi package: ${e}`); } } @@ -115,10 +100,7 @@ export default function WifiStatus(): JSX.Element { <div className="wifi-local-status-container"> <StateBadgeContainer container={wifiDnp.data.containers[0]} /> <MdWifi className="wifi-local-status-icon" /> - <NavLink - className="wifi-status-name" - to="http://my.dappnode/packages/wifi.dnp.dappnode.eth" - > + <NavLink className="wifi-status-name" to="http://my.dappnode/packages/wifi.dnp.dappnode.eth"> {prettyDnpName(wifiDnpName)} </NavLink> </div> @@ -126,9 +108,7 @@ export default function WifiStatus(): JSX.Element { <Switch checked={wifiDnp.data.containers[0].state === "running"} onToggle={pauseWifi} - label={ - wifiDnp.data.containers[0].state === "running" ? "On" : "Off" - } + label={wifiDnp.data.containers[0].state === "running" ? "On" : "Off"} ></Switch> </div> </div> diff --git a/packages/admin-ui/src/params.ts b/packages/admin-ui/src/params.ts index aff869a0d..dcf623071 100755 --- a/packages/admin-ui/src/params.ts +++ b/packages/admin-ui/src/params.ts @@ -72,8 +72,7 @@ export const zkevmUiUrl = "http://ui.zkevm-tokens-withdrawal.dappnode/"; export const sdkPublishAppUrl = "https://dappnode.github.io/sdk-publish/"; export const sdkGuideUrl = "https://github.com/dappnode/DAppNodeSDK"; -export const githubNewIssueDappnodeUrl = - "https://github.com/dappnode/DAppNode/issues/new"; +export const githubNewIssueDappnodeUrl = "https://github.com/dappnode/DAppNode/issues/new"; export const surveyUrl = "https://goo.gl/forms/DSy1J1OlQGpdyhD22"; export const packageSurveyLink = "https://goo.gl/forms/EjVTHu6UBWBk60Z62"; @@ -100,16 +99,12 @@ export const docsUrl = { }; export const forumUrl = { - telegramHowTo: - "https://forum.dappnode.io/t/set-up-your-dappnode-telegram-bot/816/4", - ipfsRemoteHowTo: - "https://forum.dappnode.io/t/how-to-use-dappnode-ipfs-remote/1295", - expandFileSystemHowTo: - "https://forum.dappnode.io/t/how-to-expand-your-dappnode-filesystem-space/1296" + telegramHowTo: "https://forum.dappnode.io/t/set-up-your-dappnode-telegram-bot/816/4", + ipfsRemoteHowTo: "https://forum.dappnode.io/t/how-to-use-dappnode-ipfs-remote/1295", + expandFileSystemHowTo: "https://forum.dappnode.io/t/how-to-expand-your-dappnode-filesystem-space/1296" }; -export const troubleShootMountpointsGuideUrl = - "https://docs.dappnode.io/developers/package-dev/wizard#target"; +export const troubleShootMountpointsGuideUrl = "https://docs.dappnode.io/developers/package-dev/wizard#target"; export const dappnodeUserGuideUrl = "https://docs.dappnode.io/user/faq/general"; export const explorerGitcoinUrl = "https://explorer.gitcoin.co/#/round/1/0xdf22a2c8f6ba9376ff17ee13e6154b784ee92094/0xdf22a2c8f6ba9376ff17ee13e6154b784ee92094-17"; @@ -129,8 +124,7 @@ export const dappnodeLogicalVolume = "root"; // IPFS export const IPFS_DAPPNODE_GATEWAY = "https://gateway.ipfs.dappnode.io"; -export const IPFS_GATEWAY_CHECKER = - "https://ipfs.github.io/public-gateway-checker/"; +export const IPFS_GATEWAY_CHECKER = "https://ipfs.github.io/public-gateway-checker/"; // VPN export const MAIN_ADMIN_NAME = "dappnode_admin"; diff --git a/packages/admin-ui/src/registerServiceWorker.js b/packages/admin-ui/src/registerServiceWorker.js index 6a9669723..35178649f 100644 --- a/packages/admin-ui/src/registerServiceWorker.js +++ b/packages/admin-ui/src/registerServiceWorker.js @@ -1,3 +1,5 @@ +/* eslint-disable no-undef */ + // In production, we register a service worker to serve assets from local cache. // This lets the app load faster on subsequent visits in production, and gives @@ -13,9 +15,7 @@ const isLocalhost = Boolean( // [::1] is the IPv6 localhost address. window.location.hostname === "[::1]" || // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) ); export default function register() { @@ -39,7 +39,6 @@ export default function register() { // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { - /* eslint-disable-next-line no-console */ console.log( "This web app is being served cache-first by a service " + "worker. To learn more, visit https://goo.gl/SC7cgQ" @@ -56,7 +55,7 @@ export default function register() { function registerValidSW(swUrl) { navigator.serviceWorker .register(swUrl) - .then(registration => { + .then((registration) => { registration.onupdatefound = () => { const installingWorker = registration.installing; installingWorker.onstatechange = () => { @@ -66,20 +65,20 @@ function registerValidSW(swUrl) { // the fresh content will have been added to the cache. // It's the perfect time to display a "New content is // available; please refresh." message in your web app. - /* eslint-disable-next-line no-console */ + console.log("New content is available; please refresh."); } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - /* eslint-disable-next-line no-console */ + console.log("Content is cached for offline use."); } } }; }; }) - .catch(error => { + .catch((error) => { console.error("Error during service worker registration:", error); }); } @@ -87,14 +86,11 @@ function registerValidSW(swUrl) { function checkValidServiceWorker(swUrl) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl) - .then(response => { + .then((response) => { // Ensure service worker exists, and that we really are getting a JS file. - if ( - response.status === 404 || - response.headers.get("content-type").indexOf("javascript") === -1 - ) { + if (response.status === 404 || response.headers.get("content-type").indexOf("javascript") === -1) { // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { + navigator.serviceWorker.ready.then((registration) => { registration.unregister().then(() => { window.location.reload(); }); @@ -105,16 +101,13 @@ function checkValidServiceWorker(swUrl) { } }) .catch(() => { - /* eslint-disable-next-line no-console */ - console.log( - "No internet connection found. App is running in offline mode." - ); + console.log("No internet connection found. App is running in offline mode."); }); } export function unregister() { if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready.then(registration => { + navigator.serviceWorker.ready.then((registration) => { registration.unregister(); }); } diff --git a/packages/admin-ui/src/services/coreUpdate/actions.ts b/packages/admin-ui/src/services/coreUpdate/actions.ts index 5e2341ab1..e1e0ea4cd 100644 --- a/packages/admin-ui/src/services/coreUpdate/actions.ts +++ b/packages/admin-ui/src/services/coreUpdate/actions.ts @@ -50,7 +50,7 @@ const updateCoreRequestStatus = coreUpdate.actions.requestStatus; * to know if there is an update available. If so, it fetches the manifests * of the core DNP and all the necessary dependencies */ -export const fetchCoreUpdateData = (): AppThunk => async dispatch => { +export const fetchCoreUpdateData = (): AppThunk => async (dispatch) => { try { dispatch(updateCoreRequestStatus({ loading: true })); const coreUpdateData = await api.fetchCoreUpdateData({ version }); @@ -58,13 +58,8 @@ export const fetchCoreUpdateData = (): AppThunk => async dispatch => { dispatch(updateCoreUpdateData(coreUpdateData)); if (coreUpdateData.available) { - /* eslint-disable-next-line no-console */ - console.log( - `DAppNode ${coreDnpName} (${coreUpdateData.versionId})`, - coreUpdateData - ); + console.log(`DAppNode ${coreDnpName} (${coreUpdateData.versionId})`, coreUpdateData); } else { - /* eslint-disable-next-line no-console */ console.log(`DAppNode is updated`); } } catch (e) { @@ -82,8 +77,7 @@ export const fetchCoreUpdateData = (): AppThunk => async dispatch => { export const updateCore = (): AppThunk => async (dispatch, getState) => { try { // Prevent double installations - if (getUpdatingCore(getState())) - return console.error("Error: DAppNode core is already updating"); + if (getUpdatingCore(getState())) return console.error("Error: DAppNode core is already updating"); // blacklist the current package dispatch(updateUpdatingCore(true)); diff --git a/packages/admin-ui/src/services/coreUpdate/reducer.ts b/packages/admin-ui/src/services/coreUpdate/reducer.ts index 8904c39ab..eaeb50da2 100644 --- a/packages/admin-ui/src/services/coreUpdate/reducer.ts +++ b/packages/admin-ui/src/services/coreUpdate/reducer.ts @@ -21,10 +21,10 @@ export const coreUpdate = createSlice({ initialState, reducers: mapValues( initialState, - (data, key) => ( - state: typeof initialState, - action: PayloadAction<typeof data> - ) => ({ ...state, [key]: action.payload }) + (data, key) => (state: typeof initialState, action: PayloadAction<typeof data>) => ({ + ...state, + [key]: action.payload + }) ) as { [K in keyof CoreUpdateState]: ( state: CoreUpdateState, diff --git a/packages/admin-ui/src/services/coreUpdate/selectors.ts b/packages/admin-ui/src/services/coreUpdate/selectors.ts index 655c30bc8..5f49afdec 100644 --- a/packages/admin-ui/src/services/coreUpdate/selectors.ts +++ b/packages/admin-ui/src/services/coreUpdate/selectors.ts @@ -3,10 +3,8 @@ import { RootState } from "rootReducer"; // Service > coreUpdate export const getCoreUpdateData = (state: RootState) => state.coreUpdate.data; -export const getUpdatingCore = (state: RootState) => - state.coreUpdate.updatingCore; -export const getCoreRequestStatus = (state: RootState) => - state.coreUpdate.requestStatus; +export const getUpdatingCore = (state: RootState) => state.coreUpdate.updatingCore; +export const getCoreRequestStatus = (state: RootState) => state.coreUpdate.requestStatus; export const getCoreUpdateAvailable = (state: RootState): boolean => { const coreUpdateData = getCoreUpdateData(state); @@ -15,9 +13,5 @@ export const getCoreUpdateAvailable = (state: RootState): boolean => { export const getIsCoreUpdateTypePatch = (state: RootState): boolean => { const coreUpdateData = getCoreUpdateData(state); - return ( - coreUpdateData !== null && - coreUpdateData.available && - coreUpdateData.type === "patch" - ); + return coreUpdateData !== null && coreUpdateData.available && coreUpdateData.type === "patch"; }; diff --git a/packages/admin-ui/src/services/dappnodeStatus/actions.ts b/packages/admin-ui/src/services/dappnodeStatus/actions.ts index 38bcc7411..468541a18 100644 --- a/packages/admin-ui/src/services/dappnodeStatus/actions.ts +++ b/packages/admin-ui/src/services/dappnodeStatus/actions.ts @@ -1,55 +1,48 @@ import { api } from "api"; import { dappnodeStatus } from "./reducer"; import { AppThunk } from "store"; -import { - wifiDnpName, - wifiEnvWPA_PASSPHRASE, - wifiEnvSSID, - wifiDefaultWPA_PASSPHRASE -} from "params"; +import { wifiDnpName, wifiEnvWPA_PASSPHRASE, wifiEnvSSID, wifiDefaultWPA_PASSPHRASE } from "params"; // Service > dappnodeStatus // Update -export const setIsConnectedToInternet = - dappnodeStatus.actions.isConnectedToInternet; +export const setIsConnectedToInternet = dappnodeStatus.actions.isConnectedToInternet; export const setSystemInfo = dappnodeStatus.actions.systemInfo; export const updateVolumes = dappnodeStatus.actions.volumes; -export const setRebootHostIsRequired = - dappnodeStatus.actions.rebootRequiredScript; +export const setRebootHostIsRequired = dappnodeStatus.actions.rebootRequiredScript; const updateWifiCredentials = dappnodeStatus.actions.wifiCredentials; const updatePasswordIsSecure = dappnodeStatus.actions.passwordIsSecure; const updateShouldShowSmooth = dappnodeStatus.actions.shouldShowSmooth; // Fetch -export const fetchShouldShowSmooth = (): AppThunk => async dispatch => +export const fetchShouldShowSmooth = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(updateShouldShowSmooth(await api.getShouldShowSmooth())); }, "getShouldShowSmooth"); -export const fetchIsConnectedToInternet = (): AppThunk => async dispatch => +export const fetchIsConnectedToInternet = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(setIsConnectedToInternet(await api.getIsConnectedToInternet())); }, "getIsConnectedToInternet"); -export const fetchRebootIsRequired = (): AppThunk => async dispatch => +export const fetchRebootIsRequired = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(setRebootHostIsRequired(await api.rebootHostIsRequiredGet())); }, "rebootHostIsRequiredGet"); -export const fetchPasswordIsSecure = (): AppThunk => async dispatch => +export const fetchPasswordIsSecure = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(updatePasswordIsSecure(await api.passwordIsSecure())); }, "passwordIsSecure"); -export const fetchVolumes = (): AppThunk => async dispatch => +export const fetchVolumes = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(updateVolumes(await api.volumesGet())); }, "volumesGet"); -export const fetchSystemInfo = (): AppThunk => async dispatch => +export const fetchSystemInfo = (): AppThunk => async (dispatch) => withTryCatch(async () => { dispatch(setSystemInfo(await api.systemInfoGet())); }, "systemInfoGet"); @@ -58,11 +51,10 @@ export const fetchSystemInfo = (): AppThunk => async dispatch => * Check if the wifi DNP has the same credentials as the default ones * @returns credentials are the same as the default ones */ -export const fetchWifiCredentials = (): AppThunk => async dispatch => +export const fetchWifiCredentials = (): AppThunk => async (dispatch) => withTryCatch(async () => { const wifiDnp = await api.packageGet({ dnpName: wifiDnpName }); - const environment = - (wifiDnp.userSettings?.environment || {})[wifiDnpName] || {}; + const environment = (wifiDnp.userSettings?.environment || {})[wifiDnpName] || {}; const ssid: string = environment[wifiEnvSSID]; const pass: string = environment[wifiEnvWPA_PASSPHRASE]; const isDefaultPassphrase = pass === wifiDefaultWPA_PASSPHRASE; diff --git a/packages/admin-ui/src/services/dappnodeStatus/reducer.ts b/packages/admin-ui/src/services/dappnodeStatus/reducer.ts index 1e5b78d72..553a2b623 100644 --- a/packages/admin-ui/src/services/dappnodeStatus/reducer.ts +++ b/packages/admin-ui/src/services/dappnodeStatus/reducer.ts @@ -34,10 +34,10 @@ export const dappnodeStatus = createSlice({ initialState, reducers: mapValues( initialState, - (data, key) => ( - state: typeof initialState, - action: PayloadAction<typeof data> - ) => ({ ...state, [key]: action.payload }) + (data, key) => (state: typeof initialState, action: PayloadAction<typeof data>) => ({ + ...state, + [key]: action.payload + }) ) as { [K in keyof DappnodeStatusState]: ( state: DappnodeStatusState, diff --git a/packages/admin-ui/src/services/dappnodeStatus/selectors.ts b/packages/admin-ui/src/services/dappnodeStatus/selectors.ts index f34d0169a..19dfa9fb3 100644 --- a/packages/admin-ui/src/services/dappnodeStatus/selectors.ts +++ b/packages/admin-ui/src/services/dappnodeStatus/selectors.ts @@ -1,8 +1,5 @@ import { RootState } from "rootReducer"; -import { - getEthClientPrettyStatusError, - getEthClientType -} from "components/EthMultiClient"; +import { getEthClientPrettyStatusError, getEthClientType } from "components/EthMultiClient"; import { ChainData } from "@dappnode/types"; import { activateFallbackPath } from "pages/system/data"; import { getDnpInstalled } from "services/dnpInstalled/selectors"; @@ -13,27 +10,18 @@ import { wifiDnpName } from "params"; // Sub-local properties const getSystemInfo = (state: RootState) => state.dappnodeStatus.systemInfo; export const getDappnodeParams = (state: RootState) => getSystemInfo(state); -export const getPasswordIsSecure = (state: RootState) => - state.dappnodeStatus.passwordIsSecure; -export const getRebootIsRequired = (state: RootState) => - state.dappnodeStatus.rebootRequiredScript; +export const getPasswordIsSecure = (state: RootState) => state.dappnodeStatus.passwordIsSecure; +export const getRebootIsRequired = (state: RootState) => state.dappnodeStatus.rebootRequiredScript; export const getVolumes = (state: RootState) => state.dappnodeStatus.volumes; -export const getShouldShowSmooth = (state: RootState) => - state.dappnodeStatus.shouldShowSmooth; -export const getIsConnectedToInternet = (state: RootState) => - state.dappnodeStatus.isConnectedToInternet; +export const getShouldShowSmooth = (state: RootState) => state.dappnodeStatus.shouldShowSmooth; +export const getIsConnectedToInternet = (state: RootState) => state.dappnodeStatus.isConnectedToInternet; // Sub-sub local properties -export const getEthRemoteRpc = (state: RootState) => - (getSystemInfo(state) || {}).ethRemoteRpc; -export const getEthClientTarget = (state: RootState) => - (getSystemInfo(state) || {}).eth2ClientTarget; -export const getEthClientFallback = (state: RootState) => - (getSystemInfo(state) || {}).ethClientFallback; -export const getEthClientStatus = (state: RootState) => - (getSystemInfo(state) || {}).ethClientStatus; -export const getNewFeatureIds = (state: RootState) => - (getSystemInfo(state) || {}).newFeatureIds; +export const getEthRemoteRpc = (state: RootState) => (getSystemInfo(state) || {}).ethRemoteRpc; +export const getEthClientTarget = (state: RootState) => (getSystemInfo(state) || {}).eth2ClientTarget; +export const getEthClientFallback = (state: RootState) => (getSystemInfo(state) || {}).ethClientFallback; +export const getEthClientStatus = (state: RootState) => (getSystemInfo(state) || {}).ethClientStatus; +export const getNewFeatureIds = (state: RootState) => (getSystemInfo(state) || {}).newFeatureIds; /** * Returns a pretty warning about the eth client only if the user has to see it @@ -72,15 +60,13 @@ export const getDappnodeIdentityClean = (state: RootState) => { } }; -export const getDappnodeName = (state: RootState) => - (getSystemInfo(state) || {}).dappnodeWebName || ""; +export const getDappnodeName = (state: RootState) => (getSystemInfo(state) || {}).dappnodeWebName || ""; -export const getStaticIp = (state: RootState) => - (getSystemInfo(state) || {}).staticIp || ""; +export const getStaticIp = (state: RootState) => (getSystemInfo(state) || {}).staticIp || ""; function isWifiFirstContainerRunning(state: RootState): boolean { const installedPackages = getDnpInstalled(state); - const wifiDnp = installedPackages.find(dnp => dnp.dnpName === wifiDnpName); + const wifiDnp = installedPackages.find((dnp) => dnp.dnpName === wifiDnpName); if (!wifiDnp) return false; const wifiContainer = wifiDnp.containers[0]; @@ -90,8 +76,7 @@ function isWifiFirstContainerRunning(state: RootState): boolean { } export const getWifiStatus = (state: RootState) => ({ - isDefaultPassphrase: - state.dappnodeStatus.wifiCredentials?.isDefaultPassphrase, + isDefaultPassphrase: state.dappnodeStatus.wifiCredentials?.isDefaultPassphrase, isRunning: isWifiFirstContainerRunning(state), ssid: state.dappnodeStatus.wifiCredentials?.ssid }); @@ -101,9 +86,7 @@ export const getWifiStatus = (state: RootState) => ({ * To be shown alongside other chain data * @param state */ -export function getRepositorySourceChainItem( - state: RootState -): ChainData | null { +export function getRepositorySourceChainItem(state: RootState): ChainData | null { const repositoryResult = _getRepositorySourceChainItem(state); return repositoryResult ? { @@ -115,9 +98,7 @@ export function getRepositorySourceChainItem( : null; } -function _getRepositorySourceChainItem( - state: RootState -): Omit<ChainData, "dnpName"> | null { +function _getRepositorySourceChainItem(state: RootState): Omit<ChainData, "dnpName"> | null { const target = getEthClientTarget(state); const fallback = getEthClientFallback(state); const status = getEthClientStatus(state); diff --git a/packages/admin-ui/src/services/dnpDirectory/actions.ts b/packages/admin-ui/src/services/dnpDirectory/actions.ts index 6dcdecbf5..e9881f700 100644 --- a/packages/admin-ui/src/services/dnpDirectory/actions.ts +++ b/packages/admin-ui/src/services/dnpDirectory/actions.ts @@ -5,21 +5,15 @@ import { AppThunk } from "store"; // Service > dnpDirectory -export const setDnpDirectory = createAction<DirectoryItem[]>( - "dnpDirectory/set" -); +export const setDnpDirectory = createAction<DirectoryItem[]>("dnpDirectory/set"); -export const updateDnpDirectory = createAction<DirectoryItem[]>( - "dnpDirectory/update" -); +export const updateDnpDirectory = createAction<DirectoryItem[]>("dnpDirectory/update"); -export const updateStatus = createAction<RequestStatus>( - "dnpDirectory/updateStatus" -); +export const updateStatus = createAction<RequestStatus>("dnpDirectory/updateStatus"); // Redux-thunk actions -export const fetchDnpDirectory = (): AppThunk => async dispatch => { +export const fetchDnpDirectory = (): AppThunk => async (dispatch) => { try { dispatch(updateStatus({ loading: true })); const directory = await api.fetchDirectory(); diff --git a/packages/admin-ui/src/services/dnpDirectory/reducer.ts b/packages/admin-ui/src/services/dnpDirectory/reducer.ts index 98dbd8a36..8eaceccbe 100644 --- a/packages/admin-ui/src/services/dnpDirectory/reducer.ts +++ b/packages/admin-ui/src/services/dnpDirectory/reducer.ts @@ -8,7 +8,7 @@ import { DirectoryItem, RequestStatus } from "@dappnode/types"; export const reducer = createReducer<{ directory: DirectoryItem[]; requestStatus: RequestStatus; -}>({ directory: [], requestStatus: {} }, builder => { +}>({ directory: [], requestStatus: {} }, (builder) => { builder.addCase(setDnpDirectory, (state, action) => ({ ...state, directory: action.payload @@ -17,8 +17,8 @@ export const reducer = createReducer<{ builder.addCase(updateDnpDirectory, (state, action) => ({ ...state, directory: Object.values({ - ...keyBy(state.directory, dnp => dnp.name), - ...keyBy(action.payload, dnp => dnp.name) + ...keyBy(state.directory, (dnp) => dnp.name), + ...keyBy(action.payload, (dnp) => dnp.name) }) })); diff --git a/packages/admin-ui/src/services/dnpDirectory/selectors.ts b/packages/admin-ui/src/services/dnpDirectory/selectors.ts index c9e5f9f04..799b10e01 100644 --- a/packages/admin-ui/src/services/dnpDirectory/selectors.ts +++ b/packages/admin-ui/src/services/dnpDirectory/selectors.ts @@ -4,6 +4,5 @@ import { orderBy } from "lodash-es"; // Service > dnpDirectory export const getDnpDirectory = (state: RootState) => - orderBy(state.dnpDirectory.directory, item => item.index, ["asc"]); -export const getDirectoryRequestStatus = (state: RootState) => - state.dnpDirectory.requestStatus || {}; + orderBy(state.dnpDirectory.directory, (item) => item.index, ["asc"]); +export const getDirectoryRequestStatus = (state: RootState) => state.dnpDirectory.requestStatus || {}; diff --git a/packages/admin-ui/src/services/dnpInstalled/actions.ts b/packages/admin-ui/src/services/dnpInstalled/actions.ts index a0a629176..0db4533fc 100644 --- a/packages/admin-ui/src/services/dnpInstalled/actions.ts +++ b/packages/admin-ui/src/services/dnpInstalled/actions.ts @@ -8,7 +8,7 @@ export const setDnpInstalled = dnpInstalledSlice.actions.setDnpInstalled; // Redux-thunk actions -export const fetchDnpInstalled = (): AppThunk => async dispatch => { +export const fetchDnpInstalled = (): AppThunk => async (dispatch) => { try { dispatch(setDnpInstalled(await api.packagesGet())); } catch (e) { diff --git a/packages/admin-ui/src/services/dnpInstalled/reducer.ts b/packages/admin-ui/src/services/dnpInstalled/reducer.ts index 2f7f0d57a..e786b62df 100644 --- a/packages/admin-ui/src/services/dnpInstalled/reducer.ts +++ b/packages/admin-ui/src/services/dnpInstalled/reducer.ts @@ -11,10 +11,7 @@ export const dnpInstalledSlice = createSlice({ dnpInstalled: InstalledPackageData[]; }, reducers: { - setDnpInstalled: ( - state, - action: PayloadAction<InstalledPackageData[]> - ) => ({ + setDnpInstalled: (state, action: PayloadAction<InstalledPackageData[]>) => ({ ...state, dnpInstalled: action.payload }) diff --git a/packages/admin-ui/src/services/dnpInstalled/selectors.ts b/packages/admin-ui/src/services/dnpInstalled/selectors.ts index 4503db079..c61ddf76e 100644 --- a/packages/admin-ui/src/services/dnpInstalled/selectors.ts +++ b/packages/admin-ui/src/services/dnpInstalled/selectors.ts @@ -3,5 +3,4 @@ import { InstalledPackageData } from "@dappnode/types"; // Service > dnpInstalled -export const getDnpInstalled = (state: RootState): InstalledPackageData[] => - state.dnpInstalled.dnpInstalled; +export const getDnpInstalled = (state: RootState): InstalledPackageData[] => state.dnpInstalled.dnpInstalled; diff --git a/packages/admin-ui/src/services/dnpRegistry/actions.ts b/packages/admin-ui/src/services/dnpRegistry/actions.ts index c8e520917..af341f44f 100644 --- a/packages/admin-ui/src/services/dnpRegistry/actions.ts +++ b/packages/admin-ui/src/services/dnpRegistry/actions.ts @@ -7,17 +7,13 @@ import { AppThunk } from "store"; export const setDnpRegistry = createAction<DirectoryItem[]>("dnpRegistry/set"); -export const updateDnpRegistry = createAction<DirectoryItem[]>( - "dnpRegistry/update" -); +export const updateDnpRegistry = createAction<DirectoryItem[]>("dnpRegistry/update"); -export const updateStatus = createAction<RequestStatus>( - "dnpRegistry/updateStatus" -); +export const updateStatus = createAction<RequestStatus>("dnpRegistry/updateStatus"); // Redux-thunk actions -export const fetchDnpRegistry = (): AppThunk => async dispatch => { +export const fetchDnpRegistry = (): AppThunk => async (dispatch) => { try { dispatch(updateStatus({ loading: true })); const registry = await api.fetchRegistry(); diff --git a/packages/admin-ui/src/services/dnpRegistry/reducer.ts b/packages/admin-ui/src/services/dnpRegistry/reducer.ts index 7a0703daf..ac57abcd3 100644 --- a/packages/admin-ui/src/services/dnpRegistry/reducer.ts +++ b/packages/admin-ui/src/services/dnpRegistry/reducer.ts @@ -8,7 +8,7 @@ import { DirectoryItem, RequestStatus } from "@dappnode/types"; export const reducer = createReducer<{ registry: DirectoryItem[]; requestStatus: RequestStatus; -}>({ registry: [], requestStatus: {} }, builder => { +}>({ registry: [], requestStatus: {} }, (builder) => { builder.addCase(setDnpRegistry, (state, action) => ({ ...state, registry: action.payload @@ -17,8 +17,8 @@ export const reducer = createReducer<{ builder.addCase(updateDnpRegistry, (state, action) => ({ ...state, registry: Object.values({ - ...keyBy(state.registry, dnp => dnp.name), - ...keyBy(action.payload, dnp => dnp.name) + ...keyBy(state.registry, (dnp) => dnp.name), + ...keyBy(action.payload, (dnp) => dnp.name) }) })); diff --git a/packages/admin-ui/src/services/dnpRegistry/selectors.ts b/packages/admin-ui/src/services/dnpRegistry/selectors.ts index fc540c209..a5594cdb7 100644 --- a/packages/admin-ui/src/services/dnpRegistry/selectors.ts +++ b/packages/admin-ui/src/services/dnpRegistry/selectors.ts @@ -3,7 +3,5 @@ import { orderBy } from "lodash-es"; // Service > dnpRegistry -export const getDnpRegistry = (state: RootState) => - orderBy(state.dnpRegistry.registry, item => item.index, ["asc"]); -export const getRegistryRequestStatus = (state: RootState) => - state.dnpRegistry.requestStatus || {}; +export const getDnpRegistry = (state: RootState) => orderBy(state.dnpRegistry.registry, (item) => item.index, ["asc"]); +export const getRegistryRequestStatus = (state: RootState) => state.dnpRegistry.requestStatus || {}; diff --git a/packages/admin-ui/src/services/isInstallingLogs/actions.ts b/packages/admin-ui/src/services/isInstallingLogs/actions.ts index d21548939..baa60a396 100644 --- a/packages/admin-ui/src/services/isInstallingLogs/actions.ts +++ b/packages/admin-ui/src/services/isInstallingLogs/actions.ts @@ -2,8 +2,6 @@ import { isInstallingLogsSlice } from "./reducer"; // Service > isInstallingLogs -export const updateIsInstallingLog = - isInstallingLogsSlice.actions.updateIsInstallingLog; +export const updateIsInstallingLog = isInstallingLogsSlice.actions.updateIsInstallingLog; -export const clearIsInstallingLog = - isInstallingLogsSlice.actions.clearIsInstallingLog; +export const clearIsInstallingLog = isInstallingLogsSlice.actions.clearIsInstallingLog; diff --git a/packages/admin-ui/src/services/isInstallingLogs/reducer.ts b/packages/admin-ui/src/services/isInstallingLogs/reducer.ts index bbfe98046..18372be86 100644 --- a/packages/admin-ui/src/services/isInstallingLogs/reducer.ts +++ b/packages/admin-ui/src/services/isInstallingLogs/reducer.ts @@ -19,10 +19,7 @@ export const isInstallingLogsSlice = createSlice({ name: "isInstallingLogs", initialState: { logs: {}, dnpNameToLogId: {} } as IsInstallingLogsState, reducers: { - updateIsInstallingLog: ( - state, - action: PayloadAction<{ id: string; dnpName: string; log: string }> - ) => { + updateIsInstallingLog: (state, action: PayloadAction<{ id: string; dnpName: string; log: string }>) => { const id = stripVersion(action.payload.id); const dnpName = stripVersion(action.payload.dnpName); const log = action.payload.log; @@ -45,7 +42,7 @@ export const isInstallingLogsSlice = createSlice({ return { ...state, logs: omit(state.logs, id), - dnpNameToLogId: omitBy(state.dnpNameToLogId, _id => _id === id) + dnpNameToLogId: omitBy(state.dnpNameToLogId, (_id) => _id === id) }; } } diff --git a/packages/admin-ui/src/services/isInstallingLogs/selectors.ts b/packages/admin-ui/src/services/isInstallingLogs/selectors.ts index a4391977f..1aa84b116 100644 --- a/packages/admin-ui/src/services/isInstallingLogs/selectors.ts +++ b/packages/admin-ui/src/services/isInstallingLogs/selectors.ts @@ -12,15 +12,12 @@ import { ProgressLogsByDnp, ProgressLogs } from "types"; export const getProgressLogsByDnp = (state: RootState): ProgressLogsByDnp => { const isInstallingLogs = state.isInstallingLogs; return pickBy( - mapValues(isInstallingLogs.dnpNameToLogId, id => isInstallingLogs.logs[id]), - progressLogs => progressLogs + mapValues(isInstallingLogs.dnpNameToLogId, (id) => isInstallingLogs.logs[id]), + (progressLogs) => progressLogs ); }; -export const getProgressLogsOfDnp = ( - state: RootState, - dnpName: string -): ProgressLogs | undefined => { +export const getProgressLogsOfDnp = (state: RootState, dnpName: string): ProgressLogs | undefined => { const progressLogsByDnp = getProgressLogsByDnp(state); return progressLogsByDnp[dnpName]; }; diff --git a/packages/admin-ui/src/services/notifications/actions.ts b/packages/admin-ui/src/services/notifications/actions.ts index 32eb23e6b..19dc159b9 100644 --- a/packages/admin-ui/src/services/notifications/actions.ts +++ b/packages/admin-ui/src/services/notifications/actions.ts @@ -10,28 +10,24 @@ import { getNotifications } from "./selectors"; */ export const pushNotification = notificationsSlice.actions.pushNotification; -export const viewedNotifications = (): AppThunk => async ( - dispatch, - getState -) => { +export const viewedNotifications = (): AppThunk => async (dispatch, getState) => { // Mark notifications as viewed immediately dispatch(notificationsSlice.actions.viewedNotifications()); // Load notifications const notifications = getNotifications(getState()); // Check the ones that came from the dappmanager - const ids = Object.values(notifications).map(notification => notification.id); + const ids = Object.values(notifications).map((notification) => notification.id); if (ids.length) { // Send the ids to the dappmanager await api.notificationsRemove({ ids }); } }; -export const fetchNotifications = (): AppThunk => async dispatch => { +export const fetchNotifications = (): AppThunk => async (dispatch) => { try { const notifications = await api.notificationsGet(); - for (const notification of notifications) - dispatch(pushNotification(notification)); + for (const notification of notifications) dispatch(pushNotification(notification)); } catch (e) { console.error("Error on notificationsGet", e); } diff --git a/packages/admin-ui/src/services/notifications/reducer.ts b/packages/admin-ui/src/services/notifications/reducer.ts index 54364dd6a..04083c9ed 100644 --- a/packages/admin-ui/src/services/notifications/reducer.ts +++ b/packages/admin-ui/src/services/notifications/reducer.ts @@ -8,13 +8,9 @@ export const notificationsSlice = createSlice({ [notificationId: string]: PackageNotificationDb; }, reducers: { - viewedNotifications: state => - mapValues(state, n => ({ ...n, viewed: true })), + viewedNotifications: (state) => mapValues(state, (n) => ({ ...n, viewed: true })), - pushNotification: ( - state, - action: PayloadAction<PackageNotificationDb | PackageNotification> - ) => ({ + pushNotification: (state, action: PayloadAction<PackageNotificationDb | PackageNotification>) => ({ ...state, [action.payload.id]: { timestamp: Date.now(), diff --git a/packages/admin-ui/src/services/notifications/selectors.ts b/packages/admin-ui/src/services/notifications/selectors.ts index ad09c6d38..eb643d175 100644 --- a/packages/admin-ui/src/services/notifications/selectors.ts +++ b/packages/admin-ui/src/services/notifications/selectors.ts @@ -2,5 +2,4 @@ import { RootState } from "rootReducer"; // Service > notifications -export const getNotifications = (state: RootState) => - Object.values(state.notifications); +export const getNotifications = (state: RootState) => Object.values(state.notifications); diff --git a/packages/admin-ui/src/start-pages/Login.tsx b/packages/admin-ui/src/start-pages/Login.tsx index 31842a228..e1117b3e7 100644 --- a/packages/admin-ui/src/start-pages/Login.tsx +++ b/packages/admin-ui/src/start-pages/Login.tsx @@ -14,11 +14,7 @@ import "./login.scss"; const loginRootPath = "/"; const forgotPasswordPath = "/forgot-password"; -export function Login({ - refetchStatus -}: { - refetchStatus: () => Promise<void>; -}) { +export function Login({ refetchStatus }: { refetchStatus: () => Promise<void> }) { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [reqStatus, setReqStatus] = useState<ReqStatus>({}); @@ -57,7 +53,7 @@ export function Login({ } async function onSuccessfulReset() { - await refetchStatus()?.catch(() => { }); + await refetchStatus()?.catch(() => {}); navigate(loginRootPath); } diff --git a/packages/admin-ui/src/start-pages/NoConnection.tsx b/packages/admin-ui/src/start-pages/NoConnection.tsx index 2544b53b9..deb0b9eef 100644 --- a/packages/admin-ui/src/start-pages/NoConnection.tsx +++ b/packages/admin-ui/src/start-pages/NoConnection.tsx @@ -7,11 +7,9 @@ import { StandaloneContainer } from "./StandaloneContainer"; export const NoConnection = ({ error }: { error?: Error | string }) => ( <StandaloneContainer TopIcon={FiWifiOff} title="No connection"> <div className="text"> - Could not connect to Dappnode. Please make sure your VPN connection is - still active. Otherwise, stop the connection and reconnect and try - accessing this page again. If the problems persist, please reach us via{" "} - <a href={discordInviteUrl}>Discord</a> or{" "} - <a href={githubNewIssueDappnodeUrl}>opening a Github issue</a>. + Could not connect to Dappnode. Please make sure your VPN connection is still active. Otherwise, stop the + connection and reconnect and try accessing this page again. If the problems persist, please reach us via{" "} + <a href={discordInviteUrl}>Discord</a> or <a href={githubNewIssueDappnodeUrl}>opening a Github issue</a>. </div> {error && <ErrorView error={error} hideIcon />} diff --git a/packages/admin-ui/src/start-pages/Register.tsx b/packages/admin-ui/src/start-pages/Register.tsx index 4755b5265..fe274bcb6 100644 --- a/packages/admin-ui/src/start-pages/Register.tsx +++ b/packages/admin-ui/src/start-pages/Register.tsx @@ -7,18 +7,11 @@ import { ReqStatus } from "types"; import Button from "components/Button"; import ErrorView from "components/ErrorView"; import { InputForm } from "components/InputForm"; -import { - validatePasswordsMatch, - validateStrongPassword -} from "utils/validation"; +import { validatePasswordsMatch, validateStrongPassword } from "utils/validation"; import "./register.scss"; import Ok from "components/Ok"; -export function Register({ - refetchStatus -}: { - refetchStatus: () => Promise<void>; -}) { +export function Register({ refetchStatus }: { refetchStatus: () => Promise<void> }) { const [username, setUsername] = useState("admin"); const [password, setPassword] = useState(""); const [password2, setPassword2] = useState(""); @@ -59,8 +52,8 @@ export function Register({ return ( <StandaloneContainer TopIcon={BsShieldLock} title="Register"> <div className="text"> - Welcome! To protect your Dappnode register an admin password. It is - recommended to use a password manager to set a strong password + Welcome! To protect your Dappnode register an admin password. It is recommended to use a password manager to set + a strong password </div> <InputForm @@ -123,22 +116,17 @@ function CopyRecoveryToken({ return ( <StandaloneContainer TopIcon={BsShieldLock} title="Recovery token"> <div className="text"> - Store the recovery token in a safe place. If you lose your password it - will allow you to reset the admin account and register again + Store the recovery token in a safe place. If you lose your password it will allow you to reset the admin account + and register again </div> <div className="recovery-token-box">{recoveryToken}</div> <Alert variant="warning"> - Warning! If you also lose your recovery token you will have to directly - access your machine + Warning! If you also lose your recovery token you will have to directly access your machine </Alert> - <Button - className="register-button" - onClick={onCopiedRecoveryToken} - variant="dappnode" - > + <Button className="register-button" onClick={onCopiedRecoveryToken} variant="dappnode"> I've copied the recovery token </Button> </StandaloneContainer> diff --git a/packages/admin-ui/src/start-pages/ResetPassword.tsx b/packages/admin-ui/src/start-pages/ResetPassword.tsx index c353478e3..88d0c2f2f 100644 --- a/packages/admin-ui/src/start-pages/ResetPassword.tsx +++ b/packages/admin-ui/src/start-pages/ResetPassword.tsx @@ -11,11 +11,7 @@ import Ok from "components/Ok"; import { docsUrl } from "params"; import LinkDocs from "components/LinkDocs"; -export function ResetPassword({ - onSuccessfulReset -}: { - onSuccessfulReset: () => void; -}) { +export function ResetPassword({ onSuccessfulReset }: { onSuccessfulReset: () => void }) { const [token, setToken] = useState(""); const [reqStatus, setReqStatus] = useState<ReqStatus>({}); @@ -32,18 +28,13 @@ export function ResetPassword({ return ( <StandaloneContainer TopIcon={BsLock} title="Reset"> - <div className="text"> - Use your recovery token to reset the admin password and register again - </div> + <div className="text">Use your recovery token to reset the admin password and register again</div> <Alert variant="warning"> - If you have lost your password and recovery token you have to directly access your - machine via SSH or by connecting a keyboard and screen and follow this - guide + If you have lost your password and recovery token you have to directly access your machine via SSH or by + connecting a keyboard and screen and follow this guide <br /> - <LinkDocs href={docsUrl.recoverPasswordGuide}> - Reset your Dappnode admin password - </LinkDocs> + <LinkDocs href={docsUrl.recoverPasswordGuide}>Reset your Dappnode admin password</LinkDocs> </Alert> <InputForm diff --git a/packages/admin-ui/src/store.ts b/packages/admin-ui/src/store.ts index 09634756b..f0c0b7b21 100644 --- a/packages/admin-ui/src/store.ts +++ b/packages/admin-ui/src/store.ts @@ -8,12 +8,7 @@ import { configureStore } from "@reduxjs/toolkit"; * type once, in your store file, and then use that type whenever * you write a thunk: */ -export type AppThunk<ReturnType = void> = ThunkAction< - ReturnType, - RootState, - unknown, - Action<string> ->; +export type AppThunk<ReturnType = void> = ThunkAction<ReturnType, RootState, unknown, Action<string>>; export const store = configureStore({ // ### Todo: Fix type bug: 'state !== state', because state can be undefined diff --git a/packages/admin-ui/src/types.ts b/packages/admin-ui/src/types.ts index 219b7c704..2b5c2ebe8 100644 --- a/packages/admin-ui/src/types.ts +++ b/packages/admin-ui/src/types.ts @@ -23,6 +23,7 @@ declare global { /** * Autobahn session.call */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any call: (event: string, args?: any[], kwargs?: any) => any; } } @@ -59,8 +60,5 @@ export interface AppContextIface { export type ModulesContext = Pick< AppContextIface, - | "stakersModuleStatus" - | "rollupsModuleStatus" - | "toggleStakersModuleStatus" - | "toggleRollupsModuleStatus" + "stakersModuleStatus" | "rollupsModuleStatus" | "toggleStakersModuleStatus" | "toggleRollupsModuleStatus" >; diff --git a/packages/admin-ui/src/utils/css.ts b/packages/admin-ui/src/utils/css.ts index 9b613b1d6..096d696ea 100644 --- a/packages/admin-ui/src/utils/css.ts +++ b/packages/admin-ui/src/utils/css.ts @@ -1,8 +1,4 @@ -type CssClass = - | { [className: string]: string | undefined | null | boolean } - | string - | undefined - | null; +type CssClass = { [className: string]: string | undefined | null | boolean } | string | undefined | null; /** * @@ -12,9 +8,7 @@ export function joinCssClass(...args: CssClass[]): string { return args .reduce((classNames, arg) => { if (typeof arg === "string") classNames.push(arg); - if (typeof arg === "object") - for (const [key, val] of Object.entries(arg || {})) - if (val) classNames.push(key); + if (typeof arg === "object") for (const [key, val] of Object.entries(arg || {})) if (val) classNames.push(key); return classNames; }, [] as string[]) .join(" "); diff --git a/packages/admin-ui/src/utils/dataUriToBlob.ts b/packages/admin-ui/src/utils/dataUriToBlob.ts index 67fd8670a..d8ee9618f 100644 --- a/packages/admin-ui/src/utils/dataUriToBlob.ts +++ b/packages/admin-ui/src/utils/dataUriToBlob.ts @@ -8,8 +8,7 @@ * saveAs(blob, file.name); */ export default function dataUriToBlob(dataURI: string): Blob { - if (!dataURI || typeof dataURI !== "string") - throw Error("dataUri must be a string"); + if (!dataURI || typeof dataURI !== "string") throw Error("dataUri must be a string"); // Credit: https://stackoverflow.com/questions/12168909/blob-from-dataurl // convert base64 to raw binary data held in a string @@ -17,10 +16,7 @@ export default function dataUriToBlob(dataURI: string): Blob { const byteString = atob(dataURI.split(",")[1]); // separate out the mime component // dataURI = data:application/zip;base64,UEsDBBQAAAg... - const mimeString = dataURI - .split(",")[0] - .split(":")[1] - .split(";")[0]; + const mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0]; // write the bytes of the string to an ArrayBuffer const ab = new ArrayBuffer(byteString.length); // create a view into the buffer diff --git a/packages/admin-ui/src/utils/dates.ts b/packages/admin-ui/src/utils/dates.ts index 0ebffe20a..d463ae226 100644 --- a/packages/admin-ui/src/utils/dates.ts +++ b/packages/admin-ui/src/utils/dates.ts @@ -3,10 +3,7 @@ * @param [hideTime] * @returns Today, 15 min ago */ -export function parseStaticDate( - rawDate: string | number, - hideTime = false -): string { +export function parseStaticDate(rawDate: string | number, hideTime = false): string { if (!rawDate) return ""; const date = new Date(rawDate); @@ -37,11 +34,7 @@ export function parseStaticDate( * @returns isSameDay */ function sameDay(d1: Date, d2: Date): boolean { - return ( - d1.getFullYear() === d2.getFullYear() && - d1.getMonth() === d2.getMonth() && - d1.getDate() === d2.getDate() - ); + return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate(); } /** @@ -49,10 +42,7 @@ function sameDay(d1: Date, d2: Date): boolean { * @param rawDateNext 1563728142 * @returns Today, 15 min ago */ -export function parseDiffDates( - prevRaw: string | number, - nextRaw: string | number = Date.now() -) { +export function parseDiffDates(prevRaw: string | number, nextRaw: string | number = Date.now()) { const prev = typeof prevRaw === "string" ? parseInt(prevRaw) : prevRaw; const next = typeof nextRaw === "string" ? parseInt(nextRaw) : nextRaw; diff --git a/packages/admin-ui/src/utils/fileToDataUri.ts b/packages/admin-ui/src/utils/fileToDataUri.ts index ed1f38fc6..fd6581b8f 100644 --- a/packages/admin-ui/src/utils/fileToDataUri.ts +++ b/packages/admin-ui/src/utils/fileToDataUri.ts @@ -8,16 +8,11 @@ export default function fileToDataUri(file: File): Promise<string> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); - reader.onload = e => { + reader.onload = (e) => { // fileContent is a base64 URI = data:application/zip;base64,UEsDBBQAAAg... - if (!e || !e.target || !e.target.result) - return reject(Error("e.target fileContent is not defined")); + if (!e || !e.target || !e.target.result) return reject(Error("e.target fileContent is not defined")); const fileContent = e.target.result; - resolve( - fileContent instanceof ArrayBuffer - ? fileContent.toString() - : fileContent - ); + resolve(fileContent instanceof ArrayBuffer ? fileContent.toString() : fileContent); }; }); } diff --git a/packages/admin-ui/src/utils/format.ts b/packages/admin-ui/src/utils/format.ts index cd29842e4..c8e8a6d62 100644 --- a/packages/admin-ui/src/utils/format.ts +++ b/packages/admin-ui/src/utils/format.ts @@ -3,13 +3,7 @@ import { stringSplit } from "./strings"; import prettyBytesLib from "pretty-bytes"; import { VolumeData } from "@dappnode/types"; -export function prettyFullName({ - dnpName, - serviceName -}: { - dnpName: string; - serviceName: string; -}): string { +export function prettyFullName({ dnpName, serviceName }: { dnpName: string; serviceName: string }): string { if (dnpName === serviceName) { return prettyDnpName(dnpName); } else { @@ -72,19 +66,15 @@ const coreString = "dncore_"; * @param dnpName "geth-user.dnp.dappnode.eth" * @returns res = { name: "Data", "owner": "Geth User" } */ -export function prettyVolumeName( - volName: string, - dnpName = "" -): { name: string; owner?: string } { +export function prettyVolumeName(volName: string, dnpName = ""): { name: string; owner?: string } { if (!volName) return { name: volName }; if (!dnpName) { volName = volName.replace(/^dncore_/, ""); for (const separator of [dnpString, publicString, "_"]) { if (volName.includes(separator)) { - let [dnpName, prettyVolName] = volName.split(separator); - if (dnpName === prettyVolName) prettyVolName = "data"; - return { name: capitalize(prettyVolName), owner: capitalize(dnpName) }; + const [dnpName, prettyVolName] = volName.split(separator); + return { name: capitalize(dnpName === prettyVolName ? "data" : prettyVolName), owner: capitalize(dnpName) }; } } @@ -119,9 +109,7 @@ export function getPrettyVolumeName(volData: VolumeData): string { * @returns "Geth" */ export function getPrettyVolumeOwner(volData: VolumeData): string | undefined { - return volData.owner - ? prettyDnpName(volData.owner) - : prettyVolumeName(volData.name).owner; + return volData.owner ? prettyDnpName(volData.owner) : prettyVolumeName(volData.name).owner; } /** diff --git a/packages/admin-ui/src/utils/humanFileSize.ts b/packages/admin-ui/src/utils/humanFileSize.ts index d23ee184a..ed91b58f0 100644 --- a/packages/admin-ui/src/utils/humanFileSize.ts +++ b/packages/admin-ui/src/utils/humanFileSize.ts @@ -1,9 +1,5 @@ export default function humanFileSize(size = 0) { if (!size) return 0; const i = Math.floor(Math.log(size) / Math.log(1024)); - return ( - parseFloat((size / Math.pow(1024, i)).toFixed(2)) * 1 + - " " + - ["B", "kB", "MB", "GB", "TB"][i] - ); + return parseFloat((size / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["B", "kB", "MB", "GB", "TB"][i]; } diff --git a/packages/admin-ui/src/utils/ipfs.ts b/packages/admin-ui/src/utils/ipfs.ts index a7c60c6e1..aa093010a 100644 --- a/packages/admin-ui/src/utils/ipfs.ts +++ b/packages/admin-ui/src/utils/ipfs.ts @@ -5,15 +5,11 @@ import { stringIncludes } from "./strings"; * @param peer = "/dns4/1bc3641738cbe2b1.dyndns.dappnode.io/tcp/4001/ipfs/QmWAcZZCvqVnJ6J9946qxEMaAbkUj6FiiVWakizVKfnfDL" */ export async function addSwarmConnection(peer: string) { - const res = await ipfsApi<{ Type: string; Message: string }>( - `swarm/connect?arg=${peer}` - ); + const res = await ipfsApi<{ Type: string; Message: string }>(`swarm/connect?arg=${peer}`); if (res.Type === "error") { console.error(`Error on addSwarmConnection:`, res); - if (stringIncludes(res.Message, "dial attempt failed")) - throw Error("Can't connect to peer"); - else if (stringIncludes(res.Message, "dial to self attempt")) - throw Error("You can't add yourself"); + if (stringIncludes(res.Message, "dial attempt failed")) throw Error("Can't connect to peer"); + else if (stringIncludes(res.Message, "dial to self attempt")) throw Error("You can't add yourself"); else throw Error(res.Message); } } diff --git a/packages/admin-ui/src/utils/isDnpDomain.ts b/packages/admin-ui/src/utils/isDnpDomain.ts index 374ad6a33..3446161c2 100644 --- a/packages/admin-ui/src/utils/isDnpDomain.ts +++ b/packages/admin-ui/src/utils/isDnpDomain.ts @@ -6,10 +6,5 @@ export default function isDnpDomain(id: string): boolean { if (!id || typeof id !== "string") return false; if (!id.includes(".")) return false; const [, dnpTag, , extension] = id.split("."); - return Boolean( - dnpTag && - (dnpTag === "dnp" || dnpTag === "public") && - extension && - extension === "eth" - ); + return Boolean(dnpTag && (dnpTag === "dnp" || dnpTag === "public") && extension && extension === "eth"); } diff --git a/packages/admin-ui/src/utils/isIpv4.ts b/packages/admin-ui/src/utils/isIpv4.ts index 304d08c3e..648517a75 100644 --- a/packages/admin-ui/src/utils/isIpv4.ts +++ b/packages/admin-ui/src/utils/isIpv4.ts @@ -3,8 +3,7 @@ * Credit: regex from ip-regex npm package. */ -const v4 = - "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}"; +const v4 = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}"; const ipv4RegExp = new RegExp(`(?:^${v4}$)`); export default function isIpv4(ip: string): boolean { diff --git a/packages/admin-ui/src/utils/lodashExtended.ts b/packages/admin-ui/src/utils/lodashExtended.ts index 73a4e9fc1..8e8387908 100644 --- a/packages/admin-ui/src/utils/lodashExtended.ts +++ b/packages/admin-ui/src/utils/lodashExtended.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { transform, isEqual, isObject, isEmpty } from "lodash-es"; export function difference<T>(base: T, object: T): T { @@ -6,10 +7,7 @@ export function difference<T>(base: T, object: T): T { object, (result: any, value, key) => { if (!isEqual(value, base[key])) { - result[key] = - isObject(value) && isObject(base[key]) - ? changes(base[key], value) - : value; + result[key] = isObject(value) && isObject(base[key]) ? changes(base[key], value) : value; } }, {} @@ -25,7 +23,7 @@ export function difference<T>(base: T, object: T): T { */ export function isDeepEmpty(value: any) { function areValuesEmpty(object: any): boolean { - return Object.values(object).every(val => { + return Object.values(object).every((val) => { if (!isObject(val)) return false; if (isEmpty(val)) return true; return areValuesEmpty(val); diff --git a/packages/admin-ui/src/utils/markdown.ts b/packages/admin-ui/src/utils/markdown.ts index 646311aac..9cac51d29 100644 --- a/packages/admin-ui/src/utils/markdown.ts +++ b/packages/admin-ui/src/utils/markdown.ts @@ -1,3 +1,3 @@ export function markdownList(items: string[]): string { - return items.map(item => `- ${item}`).join("\n"); + return items.map((item) => `- ${item}`).join("\n"); } diff --git a/packages/admin-ui/src/utils/objects.ts b/packages/admin-ui/src/utils/objects.ts index ba8ffaada..9fe521de8 100644 --- a/packages/admin-ui/src/utils/objects.ts +++ b/packages/admin-ui/src/utils/objects.ts @@ -4,9 +4,8 @@ import { pickBy } from "lodash-es"; * Safe version of JSON.stringify. On error returns an error string * @param obj */ -export function stringifyObjSafe<T extends { [key: string]: any }>( - obj: T -): string { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function stringifyObjSafe<T extends { [key: string]: any }>(obj: T): string { if (!obj) return ""; try { return JSON.stringify(obj, null, 2); @@ -20,6 +19,7 @@ export function stringifyObjSafe<T extends { [key: string]: any }>( * @param obj * @returns */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function cleanObj<T extends { [key: string]: any }>(obj: T) { - return pickBy(obj, value => typeof value !== "undefined"); + return pickBy(obj, (value) => typeof value !== "undefined"); } diff --git a/packages/admin-ui/src/utils/strings.ts b/packages/admin-ui/src/utils/strings.ts index ab3c59bdd..b5f0f719e 100644 --- a/packages/admin-ui/src/utils/strings.ts +++ b/packages/admin-ui/src/utils/strings.ts @@ -53,10 +53,7 @@ export const stringEndsWith = (s: string, content: string): boolean => { * @param separator = ".", /\.(.+)/ * @returns ["vpn", "eth"] */ -export const stringSplit = ( - s: string, - separator: string | RegExp -): string[] => { +export const stringSplit = (s: string, separator: string | RegExp): string[] => { if (!s || typeof s !== "string") return [""]; if (!separator) return [""]; return s.split(separator); diff --git a/packages/admin-ui/src/utils/typescript.ts b/packages/admin-ui/src/utils/typescript.ts index 698815d50..648dc74cf 100644 --- a/packages/admin-ui/src/utils/typescript.ts +++ b/packages/admin-ui/src/utils/typescript.ts @@ -6,8 +6,6 @@ * ``` * @param value */ -export function notEmpty<TValue>( - value: TValue | null | undefined -): value is TValue { +export function notEmpty<TValue>(value: TValue | null | undefined): value is TValue { return value !== null && value !== undefined; } diff --git a/packages/admin-ui/src/utils/validation.ts b/packages/admin-ui/src/utils/validation.ts index bcfb0dbdd..f6df64f06 100644 --- a/packages/admin-ui/src/utils/validation.ts +++ b/packages/admin-ui/src/utils/validation.ts @@ -1,10 +1,7 @@ const argMinLen = 8; const argMaxLen = 63; -export function validateDockerEnv( - value: string, - argName: string -): string | null { +export function validateDockerEnv(value: string, argName: string): string | null { if (value.includes("'")) { return `${argName} must not include the quotes`; } @@ -17,20 +14,14 @@ export function validateDockerEnv( return null; } -export function validateMinLength( - value: string, - argName: string -): string | null { +export function validateMinLength(value: string, argName: string): string | null { if (value.length < argMinLen) { return `${argName} must be at least ${argMinLen} characters long`; } return null; } -export function validateMaxLength( - value: string, - argName: string -): string | null { +export function validateMaxLength(value: string, argName: string): string | null { if (value.length > argMaxLen) { return `${argName} must be at less than ${argMaxLen} characters long`; } @@ -41,7 +32,7 @@ export function validateStrongPassword(password: string): string | null { if (password.length < argMinLen) { return `Password must be at least ${argMinLen} characters long`; } - if (password.length > argMaxLen) { + if (password.length > argMaxLen) { return `Password must not exceed ${argMaxLen} characters long`; } if (!/\d+/.test(password)) { @@ -53,30 +44,17 @@ export function validateStrongPassword(password: string): string | null { return null; } -export function validatePasswordsMatch( - password: string, - password2: string -): string | null { +export function validatePasswordsMatch(password: string, password2: string): string | null { if (password2 && password !== password2) { return "Passwords do not match"; } return null; } -export function validateStrongPasswordConfirm( - password: string, - password2: string -): string | null { - return ( - validateStrongPassword(password) || - validatePasswordsMatch(password, password2) - ); +export function validateStrongPasswordConfirm(password: string, password2: string): string | null { + return validateStrongPassword(password) || validatePasswordsMatch(password, password2); } -export function validateStrongPasswordAsDockerEnv( - password: string -): string | null { - return ( - validateDockerEnv(password, "Password") || validateStrongPassword(password) - ); +export function validateStrongPasswordAsDockerEnv(password: string): string | null { + return validateDockerEnv(password, "Password") || validateStrongPassword(password); } diff --git a/packages/chains/.eslintignore b/packages/chains/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/chains/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/chains/.eslintrc.cjs b/packages/chains/.eslintrc.cjs deleted file mode 100644 index 130b10028..000000000 --- a/packages/chains/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - ignorePatterns: [ - "/src/drivers/bitcoin.ts", - "src/drivers/monero.ts", - ] -} \ No newline at end of file diff --git a/packages/chains/package.json b/packages/chains/package.json index 3f736b864..3e8b5db12 100644 --- a/packages/chains/package.json +++ b/packages/chains/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/dockerapi": "workspace:^0.1.0", diff --git a/packages/chains/src/drivers/bitcoin.ts b/packages/chains/src/drivers/bitcoin.ts index be2ddd09e..8bea60ae6 100644 --- a/packages/chains/src/drivers/bitcoin.ts +++ b/packages/chains/src/drivers/bitcoin.ts @@ -15,6 +15,7 @@ function getMinBlockDiffSync(dnpName: string): number { } // Cache the block data to prevent unnecessary calls +// eslint-disable-next-line @typescript-eslint/no-explicit-any const blockCache = new Map<string, { block: any; blockIndex: number }>(); /** @@ -31,7 +32,9 @@ async function rpcCall( username: string, password: string, method: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any[] = [] + // eslint-disable-next-line @typescript-eslint/no-explicit-any ): Promise<any> { return new Promise((resolve, reject) => { const url = new URL(rpcUrl); @@ -40,7 +43,7 @@ async function rpcCall( jsonrpc: "1.0", id: "dappnode_monitoring", method, - params, + params }); const auth = Buffer.from(`${username}:${password}`).toString("base64"); @@ -53,8 +56,8 @@ async function rpcCall( headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData), - Authorization: `Basic ${auth}`, - }, + Authorization: `Basic ${auth}` + } }; const req = request(options, (res) => { @@ -99,9 +102,7 @@ async function rpcCall( * - message: string * - error: boolean */ -export async function bitcoin( - dnp: InstalledPackageData -): Promise<ChainDataResult> { +export async function bitcoin(dnp: InstalledPackageData): Promise<ChainDataResult> { try { const container = dnp.containers[0]; if (!container) throw new Error("No container found"); @@ -111,15 +112,13 @@ export async function bitcoin( const containerDomain = buildNetworkAlias({ dnpName, serviceName, - isMainOrMonoservice: true, + isMainOrMonoservice: true }); // Retrieve RPC credentials from container environment variables const containerName = container.containerName; const containerData = await dockerContainerInspect(containerName); - const { username, password, port } = parseCredentialsFromEnvs( - containerData.Config.Env - ); + const { username, password, port } = parseCredentialsFromEnvs(containerData.Config.Env); if (!port) { throw new Error("RPC port not defined"); @@ -128,33 +127,21 @@ export async function bitcoin( const apiUrl = `http://${containerDomain}:${port}/`; // Fetch block count - const blockIndex = await rpcCall( - apiUrl, - username, - password, - "getblockcount" - ); + const blockIndex = await rpcCall(apiUrl, username, password, "getblockcount"); // Check and utilize cached block data if available const cachedBlockData = blockCache.get(apiUrl); + // eslint-disable-next-line @typescript-eslint/no-explicit-any let block: any; if (cachedBlockData && cachedBlockData.blockIndex === blockIndex) { block = cachedBlockData.block; } else { // Fetch block hash - const blockHash = await rpcCall( - apiUrl, - username, - password, - "getblockhash", - [blockIndex] - ); + const blockHash = await rpcCall(apiUrl, username, password, "getblockhash", [blockIndex]); // Fetch block data - block = await rpcCall(apiUrl, username, password, "getblock", [ - blockHash, - ]); + block = await rpcCall(apiUrl, username, password, "getblock", [blockHash]); // Update cache blockCache.set(apiUrl, { blockIndex, block }); @@ -174,20 +161,20 @@ export async function bitcoin( syncing: true, error: false, message: `Blocks synced: ${blockIndex} / ${estimatedTotalBlocks}`, - progress, + progress }; } else { return { syncing: false, error: false, - message: `Synced #${blockIndex}`, + message: `Synced #${blockIndex}` }; } - } catch (error: any) { + } catch (error) { return { syncing: false, error: true, - message: `Error: ${error.message}`, + message: `Error: ${error.message}` }; } } @@ -213,8 +200,7 @@ export function parseCredentialsFromEnvs(envsArray: string[]): { const portKey = keys.find((key) => key.includes("_RPCPORT")); if (!userKey) throw new Error("RPCUSER not defined in environment variables"); - if (!passKey) - throw new Error("RPCPASSWORD not defined in environment variables"); + if (!passKey) throw new Error("RPCPASSWORD not defined in environment variables"); const username = envs[userKey]; const password = envs[passKey]; diff --git a/packages/chains/src/drivers/ethereum.ts b/packages/chains/src/drivers/ethereum.ts index 7dde9b6d6..de5927e25 100644 --- a/packages/chains/src/drivers/ethereum.ts +++ b/packages/chains/src/drivers/ethereum.ts @@ -1,15 +1,10 @@ import { ChainDriverSpecs, InstalledPackageData } from "@dappnode/types"; -import { - buildNetworkAlias, - EthSyncing, - parseEthersSyncing, -} from "@dappnode/utils"; +import { buildNetworkAlias, EthSyncing, parseEthersSyncing } from "@dappnode/utils"; import { ChainDataResult } from "../types.js"; import { safeProgress } from "../utils.js"; const MIN_BLOCK_DIFF_SYNC = 60; -const gethSyncHelpUrl = - "https://github.com/ethereum/go-ethereum/issues/16218#issuecomment-371454280"; +const gethSyncHelpUrl = "https://github.com/ethereum/go-ethereum/issues/16218#issuecomment-371454280"; /** * Returns a chain data object for an [ethereum] API @@ -30,9 +25,7 @@ export async function ethereum( ): Promise<ChainDataResult | null> { // Get serviceName from chainDriverSpec and use normal method if no serviceName is defined in chainDriver const serviceName = chainDriver.serviceName || dnp.containers[0].serviceName; - const executionLayerContainer = dnp.containers.find( - (container) => container.serviceName === serviceName - ); + const executionLayerContainer = dnp.containers.find((container) => container.serviceName === serviceName); if (!executionLayerContainer) { throw Error(`${serviceName} service not found`); } @@ -46,7 +39,7 @@ export async function ethereum( const containerDomain = buildNetworkAlias({ dnpName, serviceName, - isMainOrMonoservice: true, + isMainOrMonoservice: true }); const apiUrl = `http://${containerDomain}:${port}`; @@ -55,15 +48,16 @@ export async function ethereum( const response = await fetch(apiUrl, { method: "POST", headers: { - "Content-Type": "application/json", + "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", method: method, params: params, - id: 1, - }), + id: 1 + }) }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = (await response.json()) as any; return data.result; } @@ -73,7 +67,7 @@ export async function ethereum( fetchJsonRpc("net_peerCount") .then((result) => parseInt(result, 16)) .catch(() => undefined), - fetchJsonRpc("eth_blockNumber").then((result) => parseInt(result, 16)), + fetchJsonRpc("eth_blockNumber").then((result) => parseInt(result, 16)) ]); return parseEthereumState(syncing, blockNumber, peersCount); @@ -83,11 +77,7 @@ export async function ethereum( * Parses is syncing return * Isolated in a pure function for testability */ -export function parseEthereumState( - syncing: EthSyncing, - blockNumber: number, - peersCount?: number -): ChainDataResult { +export function parseEthereumState(syncing: EthSyncing, blockNumber: number, peersCount?: number): ChainDataResult { if (syncing) { const { // Generic syncing response @@ -98,7 +88,7 @@ export function parseEthereumState( knownStates, // Open Ethereum variables warpChunksProcessed, - warpChunksAmount, + warpChunksAmount } = syncing; // Syncing but very close const currentBlockDiff = highestBlock - currentBlock; @@ -107,7 +97,7 @@ export function parseEthereumState( syncing: false, error: false, message: `Synced #${blockNumber}`, - peers: peersCount, + peers: peersCount }; // Geth sync with states @@ -118,24 +108,21 @@ export function parseEthereumState( // Render multiline status in the UI message: [ `Blocks synced: ${currentBlock} / ${highestBlock}`, - `States synced: ${pulledStates} / ${knownStates}`, + `States synced: ${pulledStates} / ${knownStates}` ].join("\n\n"), help: gethSyncHelpUrl, - peers: peersCount, + peers: peersCount }; } // Open Ethereum sync - if ( - typeof warpChunksProcessed === "number" && - typeof warpChunksAmount === "number" - ) { + if (typeof warpChunksProcessed === "number" && typeof warpChunksAmount === "number") { return { syncing: true, error: false, message: `Syncing snapshot: ${warpChunksProcessed} / ${warpChunksAmount}`, progress: safeProgress(warpChunksProcessed / warpChunksAmount), - peers: peersCount, + peers: peersCount }; } @@ -145,7 +132,7 @@ export function parseEthereumState( error: false, message: `Blocks synced: ${currentBlock} / ${highestBlock}`, progress: safeProgress(currentBlock / highestBlock), - peers: peersCount, + peers: peersCount }; } else { if (!blockNumber || blockNumber === 0) { @@ -154,14 +141,14 @@ export function parseEthereumState( syncing: true, error: false, message: `Syncing...`, - progress: 0, + progress: 0 }; } else { return { syncing: false, error: false, message: `Synced #${blockNumber}`, - peers: peersCount, + peers: peersCount }; } } diff --git a/packages/chains/src/drivers/ethereum2.ts b/packages/chains/src/drivers/ethereum2.ts index 16664c422..35d509077 100644 --- a/packages/chains/src/drivers/ethereum2.ts +++ b/packages/chains/src/drivers/ethereum2.ts @@ -13,9 +13,7 @@ export async function ethereum2( ): Promise<ChainDataResult | null> { // 1. Get network alias from the beacon chain service (use the default beaconchain service name if not specified) const serviceName = chainDriver.serviceName || "beacon-chain"; - const beaconChainContainer = dnp.containers.find( - (container) => container.serviceName === serviceName - ); + const beaconChainContainer = dnp.containers.find((container) => container.serviceName === serviceName); if (!beaconChainContainer) { throw Error(`${serviceName} service not found`); } @@ -27,7 +25,7 @@ export async function ethereum2( const containerDomain = buildNetworkAlias({ dnpName, serviceName, - isMainOrMonoservice: false, + isMainOrMonoservice: false }); // 2. Get the port number from the beacon chain service (use the default beaconchain port number if not specified) @@ -39,7 +37,7 @@ export async function ethereum2( try { const [nodeSyncing, peersCount] = await Promise.all([ fetchNodeSyncingStatus(apiUrl), - fetchNodePeersCount(apiUrl).then(parseNodePeersCount), + fetchNodePeersCount(apiUrl).then(parseNodePeersCount) ]); return parseNodeSyncingResponse(nodeSyncing, peersCount); @@ -48,7 +46,7 @@ export async function ethereum2( return { syncing: false, message: `Could not connect to RPC. ${e.message}`, - error: true, + error: true }; } } @@ -61,10 +59,7 @@ function parseNodePeersCount(peersCount: NodePeersCount): number { /** * Parses the response from the beacon node to describe if it's currently syncing or not, and if it is, what block it is up to. */ -export function parseNodeSyncingResponse( - nodeSyncing: NodeSyncing, - peersCount: number -): ChainDataResult { +export function parseNodeSyncingResponse(nodeSyncing: NodeSyncing, peersCount: number): ChainDataResult { const MIN_SLOT_DIFF_SYNC = 60; // Return error if no data if (!nodeSyncing || !nodeSyncing.data) @@ -72,7 +67,7 @@ export function parseNodeSyncingResponse( syncing: false, message: "No node syncing data", error: true, - progress: 0, + progress: 0 }; const { head_slot, sync_distance, is_syncing } = nodeSyncing.data; @@ -87,7 +82,7 @@ export function parseNodeSyncingResponse( syncing: false, error: false, message: `Synced #${headSlot}`, - peers: peersCount, + peers: peersCount }; } else { // Return syncing state @@ -96,7 +91,7 @@ export function parseNodeSyncingResponse( message: `Blocks synced ${headSlot} / ${highestBlock}`, progress: progress, error: false, - peers: peersCount, + peers: peersCount }; } } @@ -109,6 +104,7 @@ async function fetchNodeSyncingStatus(baseUrl: string): Promise<NodeSyncing> { return await fetch(urlJoin(baseUrl, "/eth/v1/node/syncing")).then( (res) => // TODO: do better type checking + // eslint-disable-next-line @typescript-eslint/no-explicit-any res.json() as any ); } @@ -121,6 +117,7 @@ async function fetchNodePeersCount(baseUrl: string): Promise<NodePeersCount> { return await fetch(urlJoin(baseUrl, "/eth/v1/node/peer_count")).then( (res) => // TODO: do better type checking + // eslint-disable-next-line @typescript-eslint/no-explicit-any res.json() as any ); } diff --git a/packages/chains/src/drivers/index.ts b/packages/chains/src/drivers/index.ts index 05a1bd3c5..d833b7e4e 100644 --- a/packages/chains/src/drivers/index.ts +++ b/packages/chains/src/drivers/index.ts @@ -1,8 +1,4 @@ -import { - ChainDriver, - ChainDriverSpecs, - InstalledPackageData, -} from "@dappnode/types"; +import { ChainDriver, ChainDriverSpecs, InstalledPackageData } from "@dappnode/types"; import { ChainDataResult } from "../types.js"; // Drivers import { bitcoin } from "./bitcoin.js"; @@ -24,7 +20,7 @@ export async function runWithChainDriver( let chainDriverSpecs: ChainDriverSpecs; if (typeof chainDriver === "string") { chainDriverSpecs = { - driver: chainDriver, + driver: chainDriver }; } else { chainDriverSpecs = chainDriver; diff --git a/packages/chains/src/drivers/monero.ts b/packages/chains/src/drivers/monero.ts index 21c134ee1..ac4d0ee15 100644 --- a/packages/chains/src/drivers/monero.ts +++ b/packages/chains/src/drivers/monero.ts @@ -1,4 +1,4 @@ -// @ts-ignore +// @ts-expect-error the library monoro-rpc is not typed import { Daemon } from "monero-rpc"; import { InstalledPackageData } from "@dappnode/types"; import { buildNetworkAlias } from "@dappnode/utils"; @@ -20,9 +20,7 @@ const MIN_BLOCK_DIFF_SYNC = 15; * error: true {bool}, * } */ -export async function monero( - dnp: InstalledPackageData -): Promise<ChainDataResult> { +export async function monero(dnp: InstalledPackageData): Promise<ChainDataResult> { const container = dnp.containers[0]; if (!container) throw Error("no container"); @@ -31,21 +29,19 @@ export async function monero( const containerDomain = buildNetworkAlias({ dnpName, serviceName, - isMainOrMonoservice: true, + isMainOrMonoservice: true }); // http://monero.dappnode:18081 const apiUrl = `http://${containerDomain}:18081`; - const info: MoneroRpcGetInfoResult = await new Promise( - (resolve, reject): void => { - const daemon = new Daemon(apiUrl); - daemon.getInfo((err: Error, res: MoneroRpcGetInfoResult) => { - if (err) reject(err); - else resolve(res); - }); - } - ); + const info: MoneroRpcGetInfoResult = await new Promise((resolve, reject): void => { + const daemon = new Daemon(apiUrl); + daemon.getInfo((err: Error, res: MoneroRpcGetInfoResult) => { + if (err) reject(err); + else resolve(res); + }); + }); const highestBlock = info.target_height; const currentBlock = info.height; @@ -54,13 +50,13 @@ export async function monero( syncing: true, error: false, message: `Blocks synced: ${currentBlock} / ${highestBlock}`, - progress: currentBlock / highestBlock, + progress: currentBlock / highestBlock }; } else { return { syncing: false, error: false, - message: `Synced #${currentBlock}`, + message: `Synced #${currentBlock}` }; } } diff --git a/packages/chains/src/getChainDriverName.ts b/packages/chains/src/getChainDriverName.ts index 92328680d..ccb432dc1 100644 --- a/packages/chains/src/getChainDriverName.ts +++ b/packages/chains/src/getChainDriverName.ts @@ -4,15 +4,13 @@ import { ChainDriver, InstalledPackageData } from "@dappnode/types"; * Get ChainDriver for a given dnp * Uses a hardcoded registry for new packages that have not updated their manifests yet */ -export function getChainDriverName( - dnp: InstalledPackageData -): ChainDriver | null { +export function getChainDriverName(dnp: InstalledPackageData): ChainDriver | null { return (dnp.chain || knownChains[dnp.dnpName]) ?? null; } const knownChains: { [dnpName: string]: ChainDriver } = { // Pending: https://github.com/dappnode/DAppNodePackage-prysm/pull/65 - "prysm.dnp.dappnode.eth": "ethereum-beacon-chain", + "prysm.dnp.dappnode.eth": "ethereum-beacon-chain" // =============================== // DO NOT ADD ANY NEW PACKAGE HERE // =============================== diff --git a/packages/chains/src/index.ts b/packages/chains/src/index.ts index 701669bfb..ea3d5f3b1 100644 --- a/packages/chains/src/index.ts +++ b/packages/chains/src/index.ts @@ -34,19 +34,18 @@ export async function getChainsData(): Promise<ChainData[]> { if (chainData) chainsData.push({ dnpName: dnp.dnpName, - ...chainData, + ...chainData }); } catch (e) { // Only log chain errors the first time they are seen - if (loggedErrors.get(dnp.dnpName) !== e.message) - logs.debug(`Error getting chain data ${dnp.dnpName}`, e); + if (loggedErrors.get(dnp.dnpName) !== e.message) logs.debug(`Error getting chain data ${dnp.dnpName}`, e); loggedErrors.set(dnp.dnpName, e.message); chainsData.push({ dnpName: dnp.dnpName, syncing: false, error: true, - message: parseChainErrors(e), + message: parseChainErrors(e) }); } }) diff --git a/packages/chains/src/utils.ts b/packages/chains/src/utils.ts index 240c8d944..dc8612eb6 100644 --- a/packages/chains/src/utils.ts +++ b/packages/chains/src/utils.ts @@ -3,8 +3,7 @@ * a NaN value may be converted to null */ export function safeProgress(progress: number): number | undefined { - if (typeof progress !== "number" || isNaN(progress) || !isFinite(progress)) - return undefined; + if (typeof progress !== "number" || isNaN(progress) || !isFinite(progress)) return undefined; else return progress; } @@ -12,8 +11,7 @@ export function safeProgress(progress: number): number | undefined { * Reword expected chain errors */ export function parseChainErrors(error: Error): string { - if (error.message.includes("ECONNREFUSED")) - return `DAppNode Package stopped or unreachable (connection refused)`; + if (error.message.includes("ECONNREFUSED")) return `DAppNode Package stopped or unreachable (connection refused)`; if (error.message.includes("Invalid JSON RPC response")) return `DAppNode Package stopped or unreachable (invalid response)`; diff --git a/packages/chains/test/unit/bitcoin.test.ts b/packages/chains/test/unit/bitcoin.test.ts index c9bde2f21..fc31813ae 100644 --- a/packages/chains/test/unit/bitcoin.test.ts +++ b/packages/chains/test/unit/bitcoin.test.ts @@ -9,12 +9,12 @@ describe("Watchers > chains > bitcoin", () => { "BTC_RPCUSER=dappnode", "BTC_RPCPASSWORD=dappnode", "BTC_TXINDEX=1", - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]; expect(parseCredentialsFromEnvs(envRows)).to.deep.equal({ username: "dappnode", password: "dappnode", - port: null, + port: null }); }); @@ -23,12 +23,12 @@ describe("Watchers > chains > bitcoin", () => { "ZCASH_RPCUSER=dappnode", "ZCASH_RPCPASSWORD=dappnode", "ZCASH_RPCPORT=8342", - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]; expect(parseCredentialsFromEnvs(envRows)).to.deep.equal({ username: "dappnode", password: "dappnode", - port: 8342, + port: 8342 }); }); }); diff --git a/packages/chains/test/unit/ethereum.test.ts b/packages/chains/test/unit/ethereum.test.ts index 335bb900a..51e4132d6 100644 --- a/packages/chains/test/unit/ethereum.test.ts +++ b/packages/chains/test/unit/ethereum.test.ts @@ -14,7 +14,7 @@ describe("Watchers > chains > ethereum", () => { highestBlock: "0x958116", startingBlock: "0x0", warpChunksAmount: "0x11a3", - warpChunksProcessed: "0x111f", + warpChunksProcessed: "0x111f" }; const blockNumber = 0; @@ -23,14 +23,10 @@ describe("Watchers > chains > ethereum", () => { error: false, message: "Syncing snapshot: 4383 / 4515", progress: 0.9707641196013289, - peers: 23, + peers: 23 }; - const chainData = parseEthereumState( - parseEthersSyncing(syncing), - blockNumber, - 23 - ); + const chainData = parseEthereumState(parseEthersSyncing(syncing), blockNumber, 23); expect(chainData).to.deep.equal(expectedChainData); }); @@ -41,7 +37,7 @@ describe("Watchers > chains > ethereum", () => { highestBlock: "0x958362", startingBlock: "0x947885", warpChunksAmount: null, - warpChunksProcessed: null, + warpChunksProcessed: null }; const blockNumber = 0; @@ -51,14 +47,10 @@ describe("Watchers > chains > ethereum", () => { error: false, message: "Blocks synced: 9730183 / 9798498", progress: 0.9930280130689418, - peers: 23, + peers: 23 }; - const chainData = parseEthereumState( - parseEthersSyncing(syncing), - blockNumber, - 23 - ); + const chainData = parseEthereumState(parseEthersSyncing(syncing), blockNumber, 23); expect(chainData).to.deep.equal(expecteChainData); }); diff --git a/packages/chains/test/unit/ethereum2.test.ts b/packages/chains/test/unit/ethereum2.test.ts index 537a522b1..20e349cb8 100644 --- a/packages/chains/test/unit/ethereum2.test.ts +++ b/packages/chains/test/unit/ethereum2.test.ts @@ -11,8 +11,8 @@ describe("Watchers > chains > ethereum2Prysm", () => { data: { head_slot: "2310476", sync_distance: "1", - is_syncing: false, - }, + is_syncing: false + } }, 23 ); @@ -21,7 +21,7 @@ describe("Watchers > chains > ethereum2Prysm", () => { syncing: false, error: false, message: "Synced #2310476", - peers: 23, + peers: 23 }; expect(chainData).to.deep.equal(expectedChainData); @@ -33,8 +33,8 @@ describe("Watchers > chains > ethereum2Prysm", () => { data: { head_slot: "134030", sync_distance: "2179666", - is_syncing: true, - }, + is_syncing: true + } }, 23 ); @@ -43,7 +43,7 @@ describe("Watchers > chains > ethereum2Prysm", () => { error: false, message: "Blocks synced 134030 / 2313696", progress: 0.05792895868774463, - peers: 23, + peers: 23 }; expect(chainData).to.deep.equal(expectedChainData); @@ -55,8 +55,8 @@ describe("Watchers > chains > ethereum2Prysm", () => { data: { head_slot: "696", sync_distance: "2311112", - is_syncing: true, - }, + is_syncing: true + } }, 23 ); @@ -66,7 +66,7 @@ describe("Watchers > chains > ethereum2Prysm", () => { error: false, message: "Blocks synced 696 / 2311808", progress: 0.00030106306406068326, - peers: 23, + peers: 23 }; expect(chainData).to.deep.equal(expectedChainData); diff --git a/packages/common/.eslintignore b/packages/common/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/common/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/common/.eslintrc.cjs b/packages/common/.eslintrc.cjs deleted file mode 100644 index e4caff64e..000000000 --- a/packages/common/.eslintrc.cjs +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - rules: { - // ##### @ts-ignore is needed in some cases - "@typescript-eslint/ban-ts-comment": "off", - // ##### Some schemas need a line length of more than 1000 - "max-len": "off", - // Sometimes we need {} or Function as a type - "@typescript-eslint/ban-types": [ - "error", - { - types: { - "{}": false, - Function: false, - }, - }, - ], - }, -}; diff --git a/packages/common/package.json b/packages/common/package.json index 57936b81b..3024fa25d 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "yarn run generate && tsc -p tsconfig.json", "generate": "node --import=tsx/esm ./src/validation/generateSchemas.ts tsconfig.json ./src/validation/schemas", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/types": "workspace:^0.1.0", diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index d1a771e19..4e4555835 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,17 +1,13 @@ export * from "./transport/jsonRpc/index.js"; export * from "./transport/socketIo/index.js"; -// Schemas - +// Schemas: expected ESLINT error until schemas are gnerated +// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import routesArgumentsSchema from "./validation/schemas/routesArguments.schema.js"; +export { default as routesArgumentsSchema } from "./validation/schemas/routesArguments.schema.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import routesReturnSchema from "./validation/schemas/routesReturn.schema.js"; +export { default as routesReturnSchema } from "./validation/schemas/routesReturn.schema.js"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import subscriptionsArgumentsSchema from "./validation/schemas/subscriptionsArguments.schema.js"; - -export { - routesArgumentsSchema, - routesReturnSchema, - subscriptionsArgumentsSchema, -}; +export { default as subscriptionsArgumentsSchema } from "./validation/schemas/subscriptionsArguments.schema.js"; diff --git a/packages/common/src/transport/socketIo/index.ts b/packages/common/src/transport/socketIo/index.ts index 2e91eb68b..b90b8ff86 100644 --- a/packages/common/src/transport/socketIo/index.ts +++ b/packages/common/src/transport/socketIo/index.ts @@ -1,11 +1,6 @@ import Ajv, { ErrorObject } from "ajv"; import { mapValues } from "lodash-es"; -import { - Args, - LoggerMiddleware, - Subscriptions, - subscriptionsData, -} from "@dappnode/types"; +import { Args, LoggerMiddleware, Subscriptions, subscriptionsData } from "@dappnode/types"; const ajv = new Ajv({ allErrors: true, strict: false }); @@ -27,7 +22,7 @@ interface SocketIsh { * for the callback depend on the event * @returns The default '/' Namespace */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type on(event: string, listener: Function): any; } @@ -79,20 +74,14 @@ export function subscriptionsFactory( if (onError) onError(`on - ${route}`, e, args); } }); - }, + } }; }); } -function formatErrors( - errors: Array<ErrorObject> | null | undefined, - route: string -): string { +function formatErrors(errors: Array<ErrorObject> | null | undefined, route: string): string { const dataVar = `root_prop`; const toReplace = `${dataVar}.${route}`; const errorsText = ajv.errorsText(errors, { separator: "\n", dataVar }); - return ( - "Validation error:\n" + - errorsText.replace(new RegExp(toReplace, "g"), "params") - ); + return "Validation error:\n" + errorsText.replace(new RegExp(toReplace, "g"), "params"); } diff --git a/packages/common/src/validation/generateSchemas.ts b/packages/common/src/validation/generateSchemas.ts index 019da3d1f..828c818e3 100644 --- a/packages/common/src/validation/generateSchemas.ts +++ b/packages/common/src/validation/generateSchemas.ts @@ -4,14 +4,9 @@ import TJS from "typescript-json-schema"; const tsConfigPath = process.argv[2]; // tsconfig.json const baseDir = process.argv[3]; // "src/common/schemas"; -if (!tsConfigPath || !baseDir) - throw Error("Requires 2 positional arguments: <tsConfigPath> <baseDir>"); +if (!tsConfigPath || !baseDir) throw Error("Requires 2 positional arguments: <tsConfigPath> <baseDir>"); -const typesToSchema = [ - "RoutesArguments", - "RoutesReturn", - "SubscriptionsArguments", -]; +const typesToSchema = ["RoutesArguments", "RoutesReturn", "SubscriptionsArguments"]; const getTsPath = (typeName: string) => { const firstLetter = typeName[0].toLowerCase(); @@ -19,8 +14,7 @@ const getTsPath = (typeName: string) => { return path.join(baseDir, `${firstLetter}${rest}.schema.ts`); }; -const getJsonPath = (typeName: string) => - path.join(baseDir, `${typeName}.schema.json`); +const getJsonPath = (typeName: string) => path.join(baseDir, `${typeName}.schema.json`); fs.mkdirSync(baseDir, { recursive: true }); // Pre-generate files so compilation doesn't fail @@ -31,11 +25,10 @@ for (const typeName of typesToSchema) { // Compile types to schemas const program = TJS.programFromConfig(tsConfigPath); for (const typeName of typesToSchema) { - /* eslint-disable-next-line no-console */ console.log(`Generating .schema.json of ${typeName}`); const schema = TJS.generateSchema(program, typeName, { required: true, - esModuleInterop: true, + esModuleInterop: true }); if (!schema) throw Error(`Error generating ${typeName} schema`); @@ -44,13 +37,9 @@ for (const typeName of typesToSchema) { // Remove empty arrays of items from argument schemas for (const route in schema.properties) { const prop = schema.properties[route]; - if (typeof prop !== "boolean" && prop.type === "array" && !prop.items) - delete schema.properties[route]; + if (typeof prop !== "boolean" && prop.type === "array" && !prop.items) delete schema.properties[route]; } fs.writeFileSync(getJsonPath(typeName), JSON.stringify(schema, null, 2)); - fs.writeFileSync( - getTsPath(typeName), - `export default ${JSON.stringify(schema)};` - ); + fs.writeFileSync(getTsPath(typeName), `export default ${JSON.stringify(schema)};`); } diff --git a/packages/common/src/validation/index.ts b/packages/common/src/validation/index.ts index e3f6c5a86..c1bbd27c4 100644 --- a/packages/common/src/validation/index.ts +++ b/packages/common/src/validation/index.ts @@ -6,7 +6,6 @@ import { Args } from "typescript-json-schema"; const ajv = new Ajv({ allErrors: true, strict: false }); -/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ export function validateRoutesArgsFactory() { const validate = ajv.compile(routesArgumentsSchema); return function validateRoutesArgs(route: string, args: Args): void { @@ -22,7 +21,6 @@ export function validateRoutesReturn(route: string, returnData: any): void { if (!valid) throw Error(formatErrors(validate.errors, "routeReturn")); } -/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ export function validateSubscriptionsArgsFactory() { const validate = ajv.compile(subscriptionsArgumentsSchema); return function validateSubscriptionsArgs(route: string, args: Args): void { @@ -36,7 +34,5 @@ function formatErrors( errors: any[] | null | undefined, dataVar: string ): string { - return ( - "Validation error:\n" + ajv.errorsText(errors, { separator: "\n", dataVar }) - ); + return "Validation error:\n" + ajv.errorsText(errors, { separator: "\n", dataVar }); } diff --git a/packages/daemons/.eslintignore b/packages/daemons/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/daemons/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/daemons/.eslintrc.cjs b/packages/daemons/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/daemons/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/daemons/package.json b/packages/daemons/package.json index e1c3e4fca..5fe289514 100644 --- a/packages/daemons/package.json +++ b/packages/daemons/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/daemons/src/autoUpdates/clearCompletedCoreUpdatesIfAny.ts b/packages/daemons/src/autoUpdates/clearCompletedCoreUpdatesIfAny.ts index 8b7234c8f..8ea08eba4 100644 --- a/packages/daemons/src/autoUpdates/clearCompletedCoreUpdatesIfAny.ts +++ b/packages/daemons/src/autoUpdates/clearCompletedCoreUpdatesIfAny.ts @@ -20,9 +20,7 @@ export function clearCompletedCoreUpdatesIfAny( const pending = db.autoUpdatePending.get(); const { version: pendingVersionId } = pending[params.coreDnpName] || {}; - const pendingVersionsAreInstalled = - pendingVersionId && - isVersionIdUpdated(pendingVersionId, currentCorePackages); + const pendingVersionsAreInstalled = pendingVersionId && isVersionIdUpdated(pendingVersionId, currentCorePackages); if (pendingVersionsAreInstalled && pendingVersionId) { flagCompletedUpdate(params.coreDnpName, pendingVersionId, timestamp); diff --git a/packages/daemons/src/autoUpdates/clearPendingUpdates.ts b/packages/daemons/src/autoUpdates/clearPendingUpdates.ts index 8fd538142..6a37d5056 100644 --- a/packages/daemons/src/autoUpdates/clearPendingUpdates.ts +++ b/packages/daemons/src/autoUpdates/clearPendingUpdates.ts @@ -14,9 +14,7 @@ export function clearPendingUpdates(dnpName: string): void { const pending = db.autoUpdatePending.get(); if (dnpName === MY_PACKAGES) { - const dnpNames = Object.keys(pending).filter( - dnpName => dnpName !== params.coreDnpName - ); + const dnpNames = Object.keys(pending).filter((dnpName) => dnpName !== params.coreDnpName); for (const dnpName of dnpNames) { clearPendingUpdatesOfDnp(dnpName); } diff --git a/packages/daemons/src/autoUpdates/editDnpSetting.ts b/packages/daemons/src/autoUpdates/editDnpSetting.ts index a289bf0a5..a9bcb7198 100644 --- a/packages/daemons/src/autoUpdates/editDnpSetting.ts +++ b/packages/daemons/src/autoUpdates/editDnpSetting.ts @@ -17,8 +17,7 @@ export function editDnpSetting(enabled: boolean, dnpName = MY_PACKAGES): void { // When disabling MY_PACKAGES, turn off all DNPs settings by // Ignoring all entries but the system packages - if (dnpName === MY_PACKAGES && !enabled) - db.autoUpdateSettings.set(pick(autoUpdateSettings, SYSTEM_PACKAGES)); + if (dnpName === MY_PACKAGES && !enabled) db.autoUpdateSettings.set(pick(autoUpdateSettings, SYSTEM_PACKAGES)); // When disabling any DNP, clear their pending updates // Ignoring all entries but the system packages diff --git a/packages/daemons/src/autoUpdates/flagCompletedUpdate.ts b/packages/daemons/src/autoUpdates/flagCompletedUpdate.ts index 8d328bdca..17cc6439e 100644 --- a/packages/daemons/src/autoUpdates/flagCompletedUpdate.ts +++ b/packages/daemons/src/autoUpdates/flagCompletedUpdate.ts @@ -11,14 +11,10 @@ import { omit } from "lodash-es"; * @param version "0.2.5" * @param timestamp Use ONLY to make tests deterministic */ -export function flagCompletedUpdate( - dnpName: string, - version: string, - timestamp?: number -): void { +export function flagCompletedUpdate(dnpName: string, version: string, timestamp?: number): void { setRegistry(dnpName, version, { updated: timestamp || Date.now(), - successful: true, + successful: true }); clearPendingUpdatesOfDnp(dnpName); @@ -32,11 +28,7 @@ export function flagCompletedUpdate( * @param version "0.2.5" * @param data { param: "value" } */ -function setRegistry( - dnpName: string, - version: string, - data: AutoUpdateRegistryEntry -): void { +function setRegistry(dnpName: string, version: string, data: AutoUpdateRegistryEntry): void { const registry = db.autoUpdateRegistry.get(); db.autoUpdateRegistry.set({ @@ -45,9 +37,9 @@ function setRegistry( ...(registry[dnpName] || {}), [version]: { ...((registry[dnpName] || {})[version] || {}), - ...data, - }, - }, + ...data + } + } }); eventBus.requestAutoUpdateData.emit(); diff --git a/packages/daemons/src/autoUpdates/formatNotificationBody.ts b/packages/daemons/src/autoUpdates/formatNotificationBody.ts index 54b1ec2c0..cf2dc3031 100644 --- a/packages/daemons/src/autoUpdates/formatNotificationBody.ts +++ b/packages/daemons/src/autoUpdates/formatNotificationBody.ts @@ -9,7 +9,7 @@ export function formatPackageUpdateNotification({ currentVersion, newVersion, upstreamVersion, - autoUpdatesEnabled, + autoUpdatesEnabled }: { dnpName: string; currentVersion: string; @@ -23,35 +23,30 @@ export function formatPackageUpdateNotification({ return [ `New version ready to install for ${prettyName} (current version ${currentVersion})`, upstreamVersion - ? ` - package version: ${newVersion}\n` + - ` - upstream version: ${upstreamVersion}` + ? ` - package version: ${newVersion}\n` + ` - upstream version: ${upstreamVersion}` : ` - version: ${newVersion}`, `Connect to your DAppNode to install this new version [install / ${prettyName}](${installUrl}).`, autoUpdatesEnabled ? `You may also wait for auto-updates to automatically install this version for you` - : `You can also enable auto-updates so packages are updated automatically by responding with the command: \n\n /enable_auto_updates`, + : `You can also enable auto-updates so packages are updated automatically by responding with the command: \n\n /enable_auto_updates` ].join("\n\n"); } export function formatSystemUpdateNotification({ packages, - autoUpdatesEnabled, + autoUpdatesEnabled }: { packages: CoreUpdateDataAvailable["packages"]; autoUpdatesEnabled: boolean; }): string { return [ "New system version ready to install", - packages.map( - (p) => - ` - ${prettyDnpName(p.name)}: ${p.to} ${p.from ? `(current: ${p.from})` : "" - }` - ), + packages.map((p) => ` - ${prettyDnpName(p.name)}: ${p.to} ${p.from ? `(current: ${p.from})` : ""}`), `Connect to your DAppNode to install this [system / update](${adminUiUpdateCoreUrl}).`, autoUpdatesEnabled ? `You may also wait for auto-updates to automatically install this version for you` - : `You can also enable auto-updates so packages are updated automatically by responding with the command: \n\n /enable_auto_updates`, + : `You can also enable auto-updates so packages are updated automatically by responding with the command: \n\n /enable_auto_updates` ].join("\n\n"); } diff --git a/packages/daemons/src/autoUpdates/getCoreUpdateData.ts b/packages/daemons/src/autoUpdates/getCoreUpdateData.ts index f94024d71..23ca9c3d9 100644 --- a/packages/daemons/src/autoUpdates/getCoreUpdateData.ts +++ b/packages/daemons/src/autoUpdates/getCoreUpdateData.ts @@ -26,7 +26,7 @@ export async function getCoreUpdateData( try { const dappgetResult = await dappnodeInstaller.getReleasesResolved({ name: coreName, - ver: coreVersion, + ver: coreVersion }); releases = dappgetResult.releases; } catch (e) { @@ -51,9 +51,7 @@ export async function getCoreUpdateData( * Ignore it to compute the update type */ const coreDnp = dnpList.find((_dnp) => _dnp.dnpName === coreName); - const coreDnpsToBeInstalled = releases.filter( - ({ dnpName }) => coreDnp || dnpName !== coreName - ); + const coreDnpsToBeInstalled = releases.filter(({ dnpName }) => coreDnp || dnpName !== coreName); const packages = coreDnpsToBeInstalled.map((release) => { const dnp = dnpList.find((_dnp) => _dnp.dnpName === release.dnpName); @@ -63,9 +61,7 @@ export async function getCoreUpdateData( from: dnp ? dnp.version : undefined, to: depManifest.version, warningOnInstall: - depManifest.warnings && depManifest.warnings.onInstall - ? depManifest.warnings.onInstall - : undefined, + depManifest.warnings && depManifest.warnings.onInstall ? depManifest.warnings.onInstall : undefined }; }); @@ -73,24 +69,21 @@ export async function getCoreUpdateData( * If there's no from version, it should be the max jump from "0.0.0", * from = "", to = "0.2.7": updateType = "minor" */ - const updateTypes = packages.map(({ from, to }) => - computeSemverUpdateType(from || "0.0.0", to) - ); + const updateTypes = packages.map(({ from, to }) => computeSemverUpdateType(from || "0.0.0", to)); const type = updateTypes.includes("major") ? "major" : updateTypes.includes("minor") - ? "minor" - : updateTypes.includes("patch") - ? "patch" - : undefined; + ? "minor" + : updateTypes.includes("patch") + ? "patch" + : undefined; /** * Compute updateAlerts */ const coreRelease = - releases.find(({ dnpName }) => dnpName === coreName) || - (await dappnodeInstaller.getRelease(coreName, coreVersion)); + releases.find(({ dnpName }) => dnpName === coreName) || (await dappnodeInstaller.getRelease(coreName, coreVersion)); const { manifest: coreManifest } = coreRelease; const dnpCore = dnpList.find((dnp) => dnp.dnpName === coreName); const from = dnpCore ? dnpCore.version : ""; @@ -106,9 +99,7 @@ export async function getCoreUpdateData( ); // versionId = "admin@0.2.4,vpn@0.2.2,core@0.2.6" - const versionId = getCoreVersionId( - packages.map(({ name, to }) => ({ dnpName: name, version: to })) - ); + const versionId = getCoreVersionId(packages.map(({ name, to }) => ({ dnpName: name, version: to }))); return { available: coreDnpsToBeInstalled.length > 0, @@ -117,6 +108,6 @@ export async function getCoreUpdateData( changelog: coreManifest.changelog || "", updateAlerts, versionId, - coreVersion: coreManifest.version, + coreVersion: coreManifest.version }; } diff --git a/packages/daemons/src/autoUpdates/index.ts b/packages/daemons/src/autoUpdates/index.ts index 3c07b0f2c..7d0c05a21 100644 --- a/packages/daemons/src/autoUpdates/index.ts +++ b/packages/daemons/src/autoUpdates/index.ts @@ -9,17 +9,11 @@ export { flagErrorUpdate } from "./flagErrorUpdate.js"; export { formatPackageUpdateNotification } from "./formatNotificationBody.js"; export { isCoreUpdateEnabled } from "./isCoreUpdateEnabled.js"; export { isDnpUpdateEnabled } from "./isDnpUpdateEnabled.js"; -export { - isUpdateDelayCompleted, - updateDelay -} from "./isUpdateDelayCompleted.js"; +export { isUpdateDelayCompleted, updateDelay } from "./isUpdateDelayCompleted.js"; export * from "./params.js"; export { sendUpdatePackageNotificationMaybe } from "./sendUpdateNotification.js"; export { setPending } from "./setPending.js"; export { setSettings } from "./setSettings.js"; export { checkNewPackagesVersion } from "./updateMyPackages.js"; -export { - checkSystemPackagesVersion, - autoUpdateSystemPackages -} from "./updateSystemPackages.js"; +export { checkSystemPackagesVersion, autoUpdateSystemPackages } from "./updateSystemPackages.js"; export { getCoreUpdateData } from "./getCoreUpdateData.js"; diff --git a/packages/daemons/src/autoUpdates/isUpdateDelayCompleted.ts b/packages/daemons/src/autoUpdates/isUpdateDelayCompleted.ts index cc2194311..cf043490f 100644 --- a/packages/daemons/src/autoUpdates/isUpdateDelayCompleted.ts +++ b/packages/daemons/src/autoUpdates/isUpdateDelayCompleted.ts @@ -2,10 +2,7 @@ import * as db from "@dappnode/db"; import { setPending } from "./setPending.js"; import { params } from "@dappnode/params"; -export const updateDelay = getRandomizedInterval( - params.AUTO_UPDATE_DELAY, - params.AUTO_UPDATE_DELAY_VARIATION -); +export const updateDelay = getRandomizedInterval(params.AUTO_UPDATE_DELAY, params.AUTO_UPDATE_DELAY_VARIATION); /** * Randomize an interval @@ -17,10 +14,7 @@ export const updateDelay = getRandomizedInterval( * @param variation * @returns */ -function getRandomizedInterval( - baseInterval: number, - variation: number -): number { +function getRandomizedInterval(baseInterval: number, variation: number): number { const randomAdjustment = Math.round((Math.random() * 2 - 1) * variation); // Random integer between -variation and +variation return baseInterval + randomAdjustment; } @@ -37,11 +31,7 @@ function getRandomizedInterval( * @param version "0.2.5" * @param timestamp Use ONLY to make tests deterministic */ -export function isUpdateDelayCompleted( - dnpName: string, - version: string, - timestamp?: number -): boolean { +export function isUpdateDelayCompleted(dnpName: string, version: string, timestamp?: number): boolean { if (!timestamp) timestamp = Date.now(); const pending = db.autoUpdatePending.get(); diff --git a/packages/daemons/src/autoUpdates/sendUpdateNotification.ts b/packages/daemons/src/autoUpdates/sendUpdateNotification.ts index 044bcd0ad..b43469a7d 100644 --- a/packages/daemons/src/autoUpdates/sendUpdateNotification.ts +++ b/packages/daemons/src/autoUpdates/sendUpdateNotification.ts @@ -5,10 +5,7 @@ import { eventBus } from "@dappnode/eventbus"; import { DappnodeInstaller } from "@dappnode/installer"; import { prettyDnpName } from "@dappnode/utils"; import { CoreUpdateDataAvailable, upstreamVersionToString } from "@dappnode/types"; -import { - formatPackageUpdateNotification, - formatSystemUpdateNotification, -} from "./formatNotificationBody.js"; +import { formatPackageUpdateNotification, formatSystemUpdateNotification } from "./formatNotificationBody.js"; import { isCoreUpdateEnabled } from "./isCoreUpdateEnabled.js"; import { isDnpUpdateEnabled } from "./isDnpUpdateEnabled.js"; @@ -16,7 +13,7 @@ export async function sendUpdatePackageNotificationMaybe({ dappnodeInstaller, dnpName, currentVersion, - newVersion, + newVersion }: { dappnodeInstaller: DappnodeInstaller; dnpName: string; @@ -25,18 +22,13 @@ export async function sendUpdatePackageNotificationMaybe({ }): Promise<void> { // If version has already been emitted, skip const lastEmittedVersion = db.notificationLastEmitVersion.get(dnpName); - if ( - lastEmittedVersion && - valid(lastEmittedVersion) && - lte(newVersion, lastEmittedVersion) - ) - return; // Already emitted update available for this version + if (lastEmittedVersion && valid(lastEmittedVersion) && lte(newVersion, lastEmittedVersion)) return; // Already emitted update available for this version // Ensure the release resolves on IPFS const release = await dappnodeInstaller.getRelease(dnpName, newVersion); const upstreamVersion = upstreamVersionToString({ upstreamVersion: release.manifest.upstreamVersion, - upstream: release.manifest.upstream, + upstream: release.manifest.upstream }); // Emit notification about new version available @@ -49,8 +41,8 @@ export async function sendUpdatePackageNotificationMaybe({ newVersion, upstreamVersion, currentVersion, - autoUpdatesEnabled: isDnpUpdateEnabled(dnpName), - }), + autoUpdatesEnabled: isDnpUpdateEnabled(dnpName) + }) }); // Register version to prevent sending notification again @@ -58,20 +50,13 @@ export async function sendUpdatePackageNotificationMaybe({ db.notificationLastEmitVersion.set(dnpName, newVersion); } -export async function sendUpdateSystemNotificationMaybe( - data: CoreUpdateDataAvailable -): Promise<void> { +export async function sendUpdateSystemNotificationMaybe(data: CoreUpdateDataAvailable): Promise<void> { const newVersion = data.coreVersion; const dnpName = params.coreDnpName; // If version has already been emitted, skip const lastEmittedVersion = db.notificationLastEmitVersion.get(dnpName); - if ( - lastEmittedVersion && - valid(lastEmittedVersion) && - lte(newVersion, lastEmittedVersion) - ) - return; // Already emitted update available for this version + if (lastEmittedVersion && valid(lastEmittedVersion) && lte(newVersion, lastEmittedVersion)) return; // Already emitted update available for this version // Emit notification about new version available eventBus.notification.emit({ @@ -80,8 +65,8 @@ export async function sendUpdateSystemNotificationMaybe( title: "System update available", body: formatSystemUpdateNotification({ packages: data.packages, - autoUpdatesEnabled: isCoreUpdateEnabled(), - }), + autoUpdatesEnabled: isCoreUpdateEnabled() + }) }); data.packages; diff --git a/packages/daemons/src/autoUpdates/setPending.ts b/packages/daemons/src/autoUpdates/setPending.ts index 8f8acd98c..71c5918aa 100644 --- a/packages/daemons/src/autoUpdates/setPending.ts +++ b/packages/daemons/src/autoUpdates/setPending.ts @@ -9,17 +9,14 @@ import { eventBus } from "@dappnode/eventbus"; * @param dnpName "bitcoin.dnp.dappnode.eth" * @param data { version: "0.2.6", param: "value" } */ -export function setPending( - dnpName: string, - data: AutoUpdatePendingEntry -): void { +export function setPending(dnpName: string, data: AutoUpdatePendingEntry): void { const pending = db.autoUpdatePending.get(); db.autoUpdatePending.set({ ...pending, [dnpName]: { ...(pending[dnpName] || {}), - ...data, - }, + ...data + } }); eventBus.requestAutoUpdateData.emit(); diff --git a/packages/daemons/src/autoUpdates/startAutoUpdatesDaemon.ts b/packages/daemons/src/autoUpdates/startAutoUpdatesDaemon.ts index 9b30693d9..6a845ee26 100644 --- a/packages/daemons/src/autoUpdates/startAutoUpdatesDaemon.ts +++ b/packages/daemons/src/autoUpdates/startAutoUpdatesDaemon.ts @@ -16,9 +16,7 @@ import { clearRegistry } from "./clearRegistry.js"; * All code is sequential, to not perform more than one update at once. * One of the update might be the core and crash the other updates. */ -async function checkAutoUpdates( - dappnodeInstaller: DappnodeInstaller -): Promise<void> { +async function checkAutoUpdates(dappnodeInstaller: DappnodeInstaller): Promise<void> { try { // Make sure the eth client provider is available before checking each package // Do it once and return for expected errors to reduce cluttering @@ -59,10 +57,7 @@ async function checkForCompletedCoreUpdates(): Promise<void> { /** * Auto updates daemon, run at most every interval */ -export function startAutoUpdatesDaemon( - dappnodeInstaller: DappnodeInstaller, - signal: AbortSignal -): void { +export function startAutoUpdatesDaemon(dappnodeInstaller: DappnodeInstaller, signal: AbortSignal): void { eventBus.packagesModified.on(({ dnpNames, removed }) => { for (const dnpName of dnpNames) { if (removed) clearPendingUpdates(dnpName); @@ -74,9 +69,5 @@ export function startAutoUpdatesDaemon( logs.error("Error on checkForCompletedCoreUpdates", e); }); - runAtMostEvery( - () => checkAutoUpdates(dappnodeInstaller), - params.AUTO_UPDATE_DAEMON_INTERVAL, - signal - ); + runAtMostEvery(() => checkAutoUpdates(dappnodeInstaller), params.AUTO_UPDATE_DAEMON_INTERVAL, signal); } diff --git a/packages/daemons/src/autoUpdates/updateMyPackages.ts b/packages/daemons/src/autoUpdates/updateMyPackages.ts index e8518ed22..93aeb05e6 100644 --- a/packages/daemons/src/autoUpdates/updateMyPackages.ts +++ b/packages/daemons/src/autoUpdates/updateMyPackages.ts @@ -17,9 +17,7 @@ import { isDnpUpdateEnabled } from "./isDnpUpdateEnabled.js"; * - Send notification once per package and version * - Auto-update the package if allowed */ -export async function checkNewPackagesVersion( - dappnodeInstaller: DappnodeInstaller -): Promise<void> { +export async function checkNewPackagesVersion(dappnodeInstaller: DappnodeInstaller): Promise<void> { const dnps = await listPackages(); for (const { dnpName, version: currentVersion } of dnps) { @@ -27,11 +25,7 @@ export async function checkNewPackagesVersion( // Ignore: // - core DNPs that must be updatable only from the "core.dnp.dappnode.eth" package // - non-valid versions (semver.lte will throw) - if ( - !dnpName || - !valid(currentVersion) || - params.corePackagesNotAutoupdatable.includes(dnpName) - ) { + if (!dnpName || !valid(currentVersion) || params.corePackagesNotAutoupdatable.includes(dnpName)) { continue; } @@ -44,10 +38,9 @@ export async function checkNewPackagesVersion( continue; } - const { version: newVersion } = - await dappnodeInstaller.getVersionAndIpfsHash({ - dnpNameOrHash: dnpName, - }); + const { version: newVersion } = await dappnodeInstaller.getVersionAndIpfsHash({ + dnpNameOrHash: dnpName + }); // This version is not an update if (lte(newVersion, currentVersion)) { @@ -59,7 +52,7 @@ export async function checkNewPackagesVersion( // Will try to resolve the IPFS release content, so await it to ensure it resolves await sendUpdatePackageNotificationMaybe({ dappnodeInstaller, - ...updateData, + ...updateData }); await autoUpdatePackageMaybe({ dappnodeInstaller, ...updateData }); @@ -79,7 +72,7 @@ async function autoUpdatePackageMaybe({ dappnodeInstaller, dnpName, currentVersion, - newVersion, + newVersion }: { dappnodeInstaller: DappnodeInstaller; dnpName: string; @@ -103,7 +96,7 @@ async function autoUpdatePackageMaybe({ try { await packageInstall(dappnodeInstaller, { name: dnpName, - version: newVersion, + version: newVersion }); flagCompletedUpdate(dnpName, newVersion); diff --git a/packages/daemons/src/autoUpdates/updateSystemPackages.ts b/packages/daemons/src/autoUpdates/updateSystemPackages.ts index 930c27f7e..8a977fef1 100644 --- a/packages/daemons/src/autoUpdates/updateSystemPackages.ts +++ b/packages/daemons/src/autoUpdates/updateSystemPackages.ts @@ -17,9 +17,7 @@ const coreDnpName = params.coreDnpName; * - Send notification if this specific DNP_CORE version has not been seen * - Auto-update system according if DNP_CORE or any dependency is not updated */ -export async function checkSystemPackagesVersion( - dappnodeInstaller: DappnodeInstaller -): Promise<void> { +export async function checkSystemPackagesVersion(dappnodeInstaller: DappnodeInstaller): Promise<void> { const coreUpdateData = await getCoreUpdateData(dappnodeInstaller); if (!coreUpdateData.available) return; @@ -47,7 +45,7 @@ export async function autoUpdateSystemPackages( try { await packageInstall(dappnodeInstaller, { name: coreDnpName, - options: { BYPASS_RESOLVER: true }, + options: { BYPASS_RESOLVER: true } }); /** diff --git a/packages/daemons/src/bind/ensureBindComposeIp.ts b/packages/daemons/src/bind/ensureBindComposeIp.ts index f556a3b7e..cf56af0ff 100644 --- a/packages/daemons/src/bind/ensureBindComposeIp.ts +++ b/packages/daemons/src/bind/ensureBindComposeIp.ts @@ -1,7 +1,4 @@ -import { - ComposeFileEditor, - parseServiceNetworks, -} from "@dappnode/dockercompose"; +import { ComposeFileEditor, parseServiceNetworks } from "@dappnode/dockercompose"; import { logs } from "@dappnode/logger"; import { params } from "@dappnode/params"; @@ -10,12 +7,9 @@ export function ensureBindComposeIp(): void { for (const service of Object.values(bindCompose.compose.services)) { if (service.networks) { const serviceCoreNetwork = parseServiceNetworks(service.networks); - const coreNetwork = - serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; + const coreNetwork = serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; if (coreNetwork.ipv4_address !== params.BIND_IP) { - logs.info( - `editing service ${params.bindDnpName} ip from ${coreNetwork.ipv4_address} to ${params.BIND_IP}` - ); + logs.info(`editing service ${params.bindDnpName} ip from ${coreNetwork.ipv4_address} to ${params.BIND_IP}`); coreNetwork.ipv4_address = params.BIND_IP; bindCompose.write(); } diff --git a/packages/daemons/src/bind/ensureBindContainerIpAndRunning.ts b/packages/daemons/src/bind/ensureBindContainerIpAndRunning.ts index 60d3cd942..7efcbf981 100644 --- a/packages/daemons/src/bind/ensureBindContainerIpAndRunning.ts +++ b/packages/daemons/src/bind/ensureBindContainerIpAndRunning.ts @@ -1,8 +1,4 @@ -import { - docker, - dockerComposeUp, - disconnectConflictingContainerIfAny, -} from "@dappnode/dockerapi"; +import { docker, dockerComposeUp, disconnectConflictingContainerIfAny } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { params } from "@dappnode/params"; import { getDockerComposePath } from "@dappnode/utils"; @@ -10,14 +6,11 @@ import Dockerode from "dockerode"; async function disconnectConflictingContainerAndStartBind(): Promise<void> { const network = docker.getNetwork(params.DOCKER_PRIVATE_NETWORK_NAME); - const conflictingContainer = await disconnectConflictingContainerIfAny( - network, - params.BIND_IP - ); + const conflictingContainer = await disconnectConflictingContainerIfAny(network, params.BIND_IP); logs.info(`Starting ${params.bindContainerName} container`); // The docker compose will start the container with the right IP await dockerComposeUp(getDockerComposePath(params.bindDnpName, true), { - forceRecreate: true, + forceRecreate: true }); // connect back the conflicting container to the network if (conflictingContainer) { @@ -25,16 +18,14 @@ async function disconnectConflictingContainerAndStartBind(): Promise<void> { `Connecting back ${conflictingContainer.Name} container to ${params.DOCKER_PRIVATE_NETWORK_NAME} network` ); await network.connect({ - Container: conflictingContainer.Name, + Container: conflictingContainer.Name }); } } export async function ensureBindContainerIpAndRunning(): Promise<void> { try { - const isBindRunning = ( - await docker.getContainer(params.bindContainerName).inspect() - ).State.Running; + const isBindRunning = (await docker.getContainer(params.bindContainerName).inspect()).State.Running; // check if the bind container is running if (!isBindRunning) { @@ -43,11 +34,8 @@ export async function ensureBindContainerIpAndRunning(): Promise<void> { } else { // check is connected to dncore_network const isConnectedToNetwork = Object.values( - ( - (await docker - .getNetwork(params.DOCKER_PRIVATE_NETWORK_NAME) - .inspect()) as Dockerode.NetworkInspectInfo - ).Containers ?? [] + ((await docker.getNetwork(params.DOCKER_PRIVATE_NETWORK_NAME).inspect()) as Dockerode.NetworkInspectInfo) + .Containers ?? [] ).some((container) => container.Name === params.bindContainerName); if (!isConnectedToNetwork) { @@ -58,9 +46,9 @@ export async function ensureBindContainerIpAndRunning(): Promise<void> { } else { // check it has the right IP const hasRightIp = - (await docker.getContainer(params.bindContainerName).inspect()) - .NetworkSettings.Networks[params.DOCKER_PRIVATE_NETWORK_NAME] - .IPAddress === params.BIND_IP; + (await docker.getContainer(params.bindContainerName).inspect()).NetworkSettings.Networks[ + params.DOCKER_PRIVATE_NETWORK_NAME + ].IPAddress === params.BIND_IP; if (hasRightIp) { // logs.info(`${params.bindContainerName} container has right IP`); return; @@ -73,18 +61,14 @@ export async function ensureBindContainerIpAndRunning(): Promise<void> { } catch (e) { // check if container does not exist 404 if (e.statusCode === 404) { - logs.warn( - `container ${params.bindContainerName} not found and it might be in an intermedium state` - ); + logs.warn(`container ${params.bindContainerName} not found and it might be in an intermedium state`); // the container might be in intermedium state with different name // TODO: what if there is a docker container already using this IP. // This would be extremley dangerous once the migration to the private ip range is done // and less ips are available. - logs.info( - `recreating container ${params.bindContainerName} with compose up` - ); + logs.info(`recreating container ${params.bindContainerName} with compose up`); await dockerComposeUp(getDockerComposePath(params.bindDnpName, true), { - forceRecreate: true, + forceRecreate: true }); } else throw e; } diff --git a/packages/daemons/src/diskUsage/index.ts b/packages/daemons/src/diskUsage/index.ts index 0869b9b67..f38964ca2 100644 --- a/packages/daemons/src/diskUsage/index.ts +++ b/packages/daemons/src/diskUsage/index.ts @@ -35,12 +35,10 @@ const thresholds = [ async function monitorDiskUsage(): Promise<void> { try { const diskAvailable = await shell(`df -k / | awk 'NR>1 { print $4}'`); - if (!diskAvailable || typeof diskAvailable !== "string") - throw Error("diskAvailable return must be a string"); + if (!diskAvailable || typeof diskAvailable !== "string") throw Error("diskAvailable return must be a string"); const diskAvailableKBytes = parseInt(diskAvailable.trim()); - if (isNaN(diskAvailableKBytes)) - throw Error("diskAvailableKBytes must be a number"); + if (isNaN(diskAvailableKBytes)) throw Error("diskAvailableKBytes must be a number"); for (const threshold of thresholds) { const thresholdIsActive = db.diskUsageThreshold.get(threshold.id); @@ -85,9 +83,8 @@ async function monitorDiskUsage(): Promise<void> { } // Format the names output to display the exact list of stopped containers - const stoppedContainerNames = - names && typeof names === "string" ? names.split(/\r?\n/g) : []; - const stoppedDnpNames = stoppedContainerNames.map(name => + const stoppedContainerNames = names && typeof names === "string" ? names.split(/\r?\n/g) : []; + const stoppedDnpNames = stoppedContainerNames.map((name) => name.replace(/(DAppNodePackage-)|(DAppNodeCore-)/g, "") ); const stoppedDnpNameList = stoppedDnpNames.join(", "); @@ -103,9 +100,7 @@ async function monitorDiskUsage(): Promise<void> { body: [ `Available disk space is less than a ${threshold.id}.`, `To prevent your DAppNode from becoming unusable ${threshold.containersDescription} where stopped.`, - stoppedDnpNames - .map(dnpName => ` - ${prettyDnpName(dnpName)}`) - .join("\n"), + stoppedDnpNames.map((dnpName) => ` - ${prettyDnpName(dnpName)}`).join("\n"), `Please, free up enough disk space and start them again.` ].join("\n\n") }); @@ -128,9 +123,5 @@ async function monitorDiskUsage(): Promise<void> { * Prevents disk usage from getting full by stopping non-essential packages */ export function startDiskUsageDaemon(signal: AbortSignal): void { - runAtMostEvery( - monitorDiskUsage, - params.CHECK_DISK_USAGE_DAEMON_INTERVAL, - signal - ); + runAtMostEvery(monitorDiskUsage, params.CHECK_DISK_USAGE_DAEMON_INTERVAL, signal); } diff --git a/packages/daemons/src/dyndns/lookup.ts b/packages/daemons/src/dyndns/lookup.ts index 19e1289e9..41dce2b0d 100644 --- a/packages/daemons/src/dyndns/lookup.ts +++ b/packages/daemons/src/dyndns/lookup.ts @@ -13,10 +13,7 @@ import dns from "dns"; * * Error: getaddrinfo EAI_AGAIN */ -export async function lookup( - hostname: string, - ignoreErrors?: boolean -): Promise<string | null> { +export async function lookup(hostname: string, ignoreErrors?: boolean): Promise<string | null> { try { const { address } = await dns.promises.lookup(hostname); return address; diff --git a/packages/daemons/src/ethMultiClient/index.ts b/packages/daemons/src/ethMultiClient/index.ts index 56b936a5a..d03cfb208 100644 --- a/packages/daemons/src/ethMultiClient/index.ts +++ b/packages/daemons/src/ethMultiClient/index.ts @@ -1,11 +1,7 @@ import * as db from "@dappnode/db"; import { eventBus } from "@dappnode/eventbus"; import { params } from "@dappnode/params"; -import { - runAtMostEvery, - runOnlyOneSequentially, - getConsensusUserSettings, -} from "@dappnode/utils"; +import { runAtMostEvery, runOnlyOneSequentially, getConsensusUserSettings } from "@dappnode/utils"; import { logs } from "@dappnode/logger"; import { EthClientRemote, @@ -13,19 +9,16 @@ import { EthClientInstallStatus, ExecutionClientMainnet, ConsensusClientMainnet, - Network, + Network } from "@dappnode/types"; import { ethereumClient, getLocalFallbackContentHash, serializeError, packageInstall, - DappnodeInstaller, + DappnodeInstaller } from "@dappnode/installer"; -import { - dockerComposeUpPackage, - listPackageNoThrow, -} from "@dappnode/dockerapi"; +import { dockerComposeUpPackage, listPackageNoThrow } from "@dappnode/dockerapi"; /** * Check status of the Ethereum client and do next actions @@ -52,8 +45,7 @@ export async function runEthClientInstaller( if (dnp) { // OK: Client is already installed, ensure it's running - if (dnp.containers.some((c) => !c.running)) - await dockerComposeUpPackage({ dnpName: target }, true); + if (dnp.containers.some((c) => !c.running)) await dockerComposeUpPackage({ dnpName: target }, true); return { status: "INSTALLED" }; } else { // Client is not installed @@ -70,13 +62,9 @@ export async function runEthClientInstaller( try { // check target belongs to enum ExecutionClientMainnet - if (isExecutionClientMainnet(target)) - db.ethExecClientInstallStatus.set(target, { status: "INSTALLING" }); + if (isExecutionClientMainnet(target)) db.ethExecClientInstallStatus.set(target, { status: "INSTALLING" }); else if (isConsensusClientMainnet(target)) - db.ethConsClientInstallStatus.set( - target as ConsensusClientMainnet, - { status: "INSTALLING" } - ); + db.ethConsClientInstallStatus.set(target as ConsensusClientMainnet, { status: "INSTALLING" }); try { if (isConsensusClientMainnet(target)) @@ -84,8 +72,8 @@ export async function runEthClientInstaller( name: target, userSettings: getConsensusUserSettings({ dnpName: target, - network: Network.Mainnet, - }), + network: Network.Mainnet + }) }); else await packageInstall(dappnodeInstaller, { name: target }); } catch (e) { @@ -99,7 +87,7 @@ export async function runEthClientInstaller( if (!contentHash) throw Error(`No local version for ${target}`); await packageInstall(dappnodeInstaller, { name: target, - version: contentHash, + version: contentHash }); } else { throw e; @@ -153,10 +141,7 @@ function verifyInitialStatusIsNotInstalling(): void { * - after changing the client * - after completing a run if the status has changed */ -export function startEthMultiClientDaemon( - dappnodeInstaller: DappnodeInstaller, - signal: AbortSignal -): void { +export function startEthMultiClientDaemon(dappnodeInstaller: DappnodeInstaller, signal: AbortSignal): void { verifyInitialStatusIsNotInstalling(); const runEthMultiClientTaskMemo = runOnlyOneSequentially( @@ -171,12 +156,7 @@ export function startEthMultiClientDaemon( const execClient = db.executionClientMainnet.get(); const consClient = db.consensusClientMainnet.get(); - if ( - db.ethClientRemote.get() === EthClientRemote.on || - !execClient || - !consClient - ) - return; // Nothing to install + if (db.ethClientRemote.get() === EthClientRemote.on || !execClient || !consClient) return; // Nothing to install for (const client of [execClient, consClient]) { if (!client) continue; @@ -184,11 +164,7 @@ export function startEthMultiClientDaemon( const prev = isExecutionClientMainnet(client) ? db.ethExecClientInstallStatus.get(client) : db.ethConsClientInstallStatus.get(client); - const next = await runEthClientInstaller( - dappnodeInstaller, - client, - prev - ); + const next = await runEthClientInstaller(dappnodeInstaller, client, prev); if (!next) continue; // Package is uninstalled isExecutionClientMainnet(client) @@ -199,10 +175,7 @@ export function startEthMultiClientDaemon( // Next run MUST be defered to next event loop for prevStatus to refresh setTimeout(eventBus.runEthClientInstaller.emit, 1000); - if ( - isExecutionClientMainnet(client) && - next.status === "INSTALLED" - ) { + if (isExecutionClientMainnet(client) && next.status === "INSTALLED") { // If status switched to "INSTALLED", map to fullnode.dappnode // Must be done here in case the package is already installed // 1. Domain for BIND package @@ -211,7 +184,7 @@ export function startEthMultiClientDaemon( ethereumClient.updateFullnodeAlias({ prevExecClientDnpName: multiClientArgs?.prevExecClientDnpName, newExecClientDnpName: client, - network: Network.Mainnet, + network: Network.Mainnet }); } } @@ -227,25 +200,13 @@ export function startEthMultiClientDaemon( runEthMultiClientTaskMemo({ prevExecClientDnpName }) ); - runAtMostEvery( - async () => runEthMultiClientTaskMemo(), - params.AUTO_UPDATE_DAEMON_INTERVAL, - signal - ); + runAtMostEvery(async () => runEthMultiClientTaskMemo(), params.AUTO_UPDATE_DAEMON_INTERVAL, signal); } -function isExecutionClientMainnet( - value: string -): value is ExecutionClientMainnet { - return Object.values(ExecutionClientMainnet).includes( - value as ExecutionClientMainnet - ); +function isExecutionClientMainnet(value: string): value is ExecutionClientMainnet { + return Object.values(ExecutionClientMainnet).includes(value as ExecutionClientMainnet); } -function isConsensusClientMainnet( - value: string -): value is ConsensusClientMainnet { - return Object.values(ConsensusClientMainnet).includes( - value as ConsensusClientMainnet - ); +function isConsensusClientMainnet(value: string): value is ConsensusClientMainnet { + return Object.values(ConsensusClientMainnet).includes(value as ConsensusClientMainnet); } diff --git a/packages/daemons/src/ethicalMetrics/checkEthicalMetricsStatus.ts b/packages/daemons/src/ethicalMetrics/checkEthicalMetricsStatus.ts index 6b2234de1..be4caa101 100644 --- a/packages/daemons/src/ethicalMetrics/checkEthicalMetricsStatus.ts +++ b/packages/daemons/src/ethicalMetrics/checkEthicalMetricsStatus.ts @@ -9,9 +9,7 @@ import { InstalledPackageData } from "@dappnode/types"; * Make sure that on Ethical metrics enabled and existing email, * the packages DMS and Ethical metrics are installed and running */ -export async function checkEthicalMetricsStatus( - dappnodeInstaller: DappnodeInstaller -): Promise<void> { +export async function checkEthicalMetricsStatus(dappnodeInstaller: DappnodeInstaller): Promise<void> { const dmsDnpName = "dms.dnp.dappnode.eth"; try { @@ -26,18 +24,17 @@ export async function checkEthicalMetricsStatus( // Check ethical metrics pkg const ethicalMetricsPkg = await listPackageNoThrow({ - dnpName: ethicalMetricsDnpName, + dnpName: ethicalMetricsDnpName }); if (!ethicalMetricsPkg) await packageInstall(dappnodeInstaller, { - name: ethicalMetricsDnpName, + name: ethicalMetricsDnpName }); else ensureAllContainersRunning(ethicalMetricsPkg); // check dms package const dmsPkg = await listPackageNoThrow({ dnpName: dmsDnpName }); - if (!dmsPkg) - await packageInstall(dappnodeInstaller, { name: dmsDnpName }); + if (!dmsPkg) await packageInstall(dappnodeInstaller, { name: dmsDnpName }); else ensureAllContainersRunning(dmsPkg); // Register instance @@ -48,9 +45,7 @@ export async function checkEthicalMetricsStatus( } } -async function ensureAllContainersRunning( - pkg: InstalledPackageData -): Promise<void> { +async function ensureAllContainersRunning(pkg: InstalledPackageData): Promise<void> { for (const container of pkg.containers) { if (!container.running) { await dockerContainerStart(container.containerName); diff --git a/packages/daemons/src/ethicalMetrics/index.ts b/packages/daemons/src/ethicalMetrics/index.ts index ada516d05..174f357ff 100644 --- a/packages/daemons/src/ethicalMetrics/index.ts +++ b/packages/daemons/src/ethicalMetrics/index.ts @@ -9,10 +9,7 @@ import { DappnodeInstaller } from "@dappnode/installer"; * Run the Ethical metrics daemon. * It will check that DMS, Exporter and Ethical metrics are installed and running if Ethical metrics is enabled */ -export function startEthicalMetricsDaemon( - dappnodeInstaller: DappnodeInstaller, - signal: AbortSignal -): void { +export function startEthicalMetricsDaemon(dappnodeInstaller: DappnodeInstaller, signal: AbortSignal): void { const runEthicalMetricsTaskMemo = runOnlyOneSequentially(async () => { try { await checkEthicalMetricsStatus(dappnodeInstaller); @@ -24,9 +21,5 @@ export function startEthicalMetricsDaemon( // Subscribe with a throttle to run only one time at once eventBus.runEthicalMetricsInstaller.on(() => runEthicalMetricsTaskMemo()); - runAtMostEvery( - async () => runEthicalMetricsTaskMemo(), - params.ETHICAL_METRICS_DAEMON_INTERVAL, - signal - ); + runAtMostEvery(async () => runEthicalMetricsTaskMemo(), params.ETHICAL_METRICS_DAEMON_INTERVAL, signal); } diff --git a/packages/daemons/src/index.ts b/packages/daemons/src/index.ts index 6adecbab3..fa6883a6f 100644 --- a/packages/daemons/src/index.ts +++ b/packages/daemons/src/index.ts @@ -12,10 +12,7 @@ import { startTemperatureDaemon } from "./temperature/index.js"; // DAEMONS EXPORT -export function startDaemons( - dappnodeInstaller: DappnodeInstaller, - signal: AbortSignal -): void { +export function startDaemons(dappnodeInstaller: DappnodeInstaller, signal: AbortSignal): void { startAutoUpdatesDaemon(dappnodeInstaller, signal); startDiskUsageDaemon(signal); startDynDnsDaemon(signal); diff --git a/packages/daemons/src/natRenewal/getLocalIp.ts b/packages/daemons/src/natRenewal/getLocalIp.ts index 573c9ec33..ed5391a75 100644 --- a/packages/daemons/src/natRenewal/getLocalIp.ts +++ b/packages/daemons/src/natRenewal/getLocalIp.ts @@ -3,16 +3,12 @@ import isIp from "is-ip"; import { logs } from "@dappnode/logger"; import { getDappmanagerImage } from "@dappnode/dockerapi"; -export async function getLocalIp(options?: { - silent: boolean; -}): Promise<string | undefined> { +export async function getLocalIp(options?: { silent: boolean }): Promise<string | undefined> { const silent = options && options.silent; try { const image = await getDappmanagerImage(); - const output = await shell( - `docker run --rm --net=host --entrypoint=/sbin/ip ${image} route get 1` - ); + const output = await shell(`docker run --rm --net=host --entrypoint=/sbin/ip ${image} route get 1`); const internalIp = ((output || "").match(/src\s((\d+\.?){4})/) || [])[1]; return isIp(internalIp) ? internalIp : undefined; } catch (e) { diff --git a/packages/daemons/src/natRenewal/getPortsToOpen.ts b/packages/daemons/src/natRenewal/getPortsToOpen.ts index b0d4c05b2..2688598a3 100644 --- a/packages/daemons/src/natRenewal/getPortsToOpen.ts +++ b/packages/daemons/src/natRenewal/getPortsToOpen.ts @@ -5,16 +5,13 @@ import { ComposeFileEditor } from "@dappnode/dockercompose"; export function getPortsToOpen(containers: PackageContainer[]): PortToOpen[] { // Aggreate ports with an object form to prevent duplicates const portsToOpen = new Map<string, PortToOpen>(); - const addPortToOpen = ( - port: PortMapping, - container: PackageContainer - ): void => { + const addPortToOpen = (port: PortMapping, container: PackageContainer): void => { if (port.host) { portsToOpen.set(`${port.host}-${port.protocol}`, { protocol: port.protocol, portNumber: port.host, serviceName: container.serviceName, - dnpName: container.dnpName, + dnpName: container.dnpName }); } }; @@ -28,22 +25,15 @@ export function getPortsToOpen(containers: PackageContainer[]): PortToOpen[] { } else { try { // If DNP is exited, the port mapping is only available in the docker-compose - const compose = new ComposeFileEditor( - container.dnpName, - container.isCore - ); + const compose = new ComposeFileEditor(container.dnpName, container.isCore); const service = compose.services()[container.serviceName]; if (service) { // Only consider ports that are mapped (not ephemeral ports) - for (const port of service.getPortMappings()) - addPortToOpen(port, container); + for (const port of service.getPortMappings()) addPortToOpen(port, container); } } catch (e) { - logs.error( - `Error getting ports of ${container.dnpName} from docker-compose`, - e - ); + logs.error(`Error getting ports of ${container.dnpName} from docker-compose`, e); } } } diff --git a/packages/daemons/src/natRenewal/index.ts b/packages/daemons/src/natRenewal/index.ts index 691ea36f9..d68be9e08 100644 --- a/packages/daemons/src/natRenewal/index.ts +++ b/packages/daemons/src/natRenewal/index.ts @@ -5,10 +5,7 @@ import * as db from "@dappnode/db"; import { getPortsToOpen } from "./getPortsToOpen.js"; import { getLocalIp } from "./getLocalIp.js"; // Utils -import { - runAtMostEveryIntervals, - runOnlyOneSequentially, -} from "@dappnode/utils"; +import { runAtMostEveryIntervals, runOnlyOneSequentially } from "@dappnode/utils"; import { PackagePort } from "@dappnode/types"; import { logs } from "@dappnode/logger"; import { listPackageContainers } from "@dappnode/dockerapi"; @@ -36,9 +33,7 @@ async function natRenewal(): Promise<void> { if (isFirstRun) { logs.info( "UPnP device available. Current UPNP port mappings\n", - portMappings - .map((p) => `${p.ip} ${p.exPort}:${p.inPort}/${p.protocol}`) - .join("\n") + portMappings.map((p) => `${p.ip} ${p.exPort}:${p.inPort}/${p.protocol}`).join("\n") ); } } catch (e) { @@ -56,10 +51,7 @@ async function natRenewal(): Promise<void> { const portsToOpen = getPortsToOpen(containers); db.portsToOpen.set(portsToOpen); if (isFirstRun) - logs.info( - "NAT renewal portsToOpen\n", - portsToOpen.map((p) => `${p.portNumber}/${p.protocol}`).join(", ") - ); + logs.info("NAT renewal portsToOpen\n", portsToOpen.map((p) => `${p.portNumber}/${p.protocol}`).join(", ")); // Fetch the localIp only once for all the portsToOpen const localIp = await getLocalIp(); @@ -101,8 +93,7 @@ async function natRenewal(): Promise<void> { ); const portIsOpen = Boolean(currentPort); if (portIsOpen) { - if (isFirstRun) - logs.info(`Port ${portId(portToOpen)} successfully opened`); + if (isFirstRun) logs.info(`Port ${portId(portToOpen)} successfully opened`); } else { logs.error(`Port ${portId(portToOpen)} is not open`); } @@ -154,7 +145,7 @@ export function startNatRenewalDaemon(signal: AbortSignal): void { // So run this daemon 2 times a bit more frequently for that case. 5 * 60 * 1000, 15 * 60 * 1000, - params.NAT_RENEWAL_DAEMON_INTERVAL, + params.NAT_RENEWAL_DAEMON_INTERVAL ], signal ); diff --git a/packages/daemons/src/stakerConfig/index.ts b/packages/daemons/src/stakerConfig/index.ts index d62a5622f..cf800f5ee 100644 --- a/packages/daemons/src/stakerConfig/index.ts +++ b/packages/daemons/src/stakerConfig/index.ts @@ -3,27 +3,14 @@ import * as db from "@dappnode/db"; import { logs } from "@dappnode/logger"; import { DappnodeInstaller, packagePickItemData } from "@dappnode/installer"; import { memoizeDebounce } from "@dappnode/utils"; -import { - MevBoostHolesky, - MevBoostMainnet, - MevBoostPrater, -} from "@dappnode/types"; +import { MevBoostHolesky, MevBoostMainnet, MevBoostPrater } from "@dappnode/types"; -async function updateMevBoostOnDb({ - dnpNames, - removed, -}: { - dnpNames: string[]; - removed?: boolean; -}): Promise<void> { +async function updateMevBoostOnDb({ dnpNames, removed }: { dnpNames: string[]; removed?: boolean }): Promise<void> { try { if (!removed) return; - if (dnpNames.includes(MevBoostMainnet.Mevboost)) - await db.mevBoostMainnet.set(false); - if (dnpNames.includes(MevBoostPrater.Mevboost)) - await db.mevBoostPrater.set(false); - if (dnpNames.includes(MevBoostHolesky.Mevboost)) - await db.mevBoostHolesky.set(false); + if (dnpNames.includes(MevBoostMainnet.Mevboost)) await db.mevBoostMainnet.set(false); + if (dnpNames.includes(MevBoostPrater.Mevboost)) await db.mevBoostPrater.set(false); + if (dnpNames.includes(MevBoostHolesky.Mevboost)) await db.mevBoostHolesky.set(false); } catch (e) { logs.error("Error updating mev boost on db", e); } @@ -31,7 +18,7 @@ async function updateMevBoostOnDb({ async function runStakerCacheUpdate({ dappnodeInstaller, - dnpName, + dnpName }: { dappnodeInstaller: DappnodeInstaller; dnpName: string; @@ -47,7 +34,7 @@ async function runStakerCacheUpdate({ // Define the memoize options with a normalizer function const memoizeOptions = { - normalizer: ([{ dnpName }]: [{ dnpName: string }]) => dnpName, + normalizer: ([{ dnpName }]: [{ dnpName: string }]) => dnpName }; const memoizeDebouncedCacheUpdate = memoizeDebounce( diff --git a/packages/daemons/src/telegramBot/dappnodeTelegramBot.ts b/packages/daemons/src/telegramBot/dappnodeTelegramBot.ts index 6cfae466f..17f4fe1db 100644 --- a/packages/daemons/src/telegramBot/dappnodeTelegramBot.ts +++ b/packages/daemons/src/telegramBot/dappnodeTelegramBot.ts @@ -25,30 +25,30 @@ const COMMANDS: Record<string, ICommand> = { "/enable_auto_updates": { description: "Enable auto-updates for all packages", action: "handleEnableAutoUpdates", - requiresAuth: true, + requiresAuth: true }, "/disable_auto_updates": { description: "Disable auto-updates for all packages", action: "handleDisableAutoUpdates", - requiresAuth: true, + requiresAuth: true }, "/start": { description: "Subscribe to future notifications", - action: "handleSubscribe", + action: "handleSubscribe" }, "/unsubscribe": { description: "Unsubscribe from future notifications", - action: "handleUnsubscribe", + action: "handleUnsubscribe" }, "/help": { description: "Display all available commands", - action: "handleGetHelp", + action: "handleGetHelp" }, "/get_wireguard_credentials": { description: "Fetch wireguard credentials", action: "handleGetWireguardCredentials", - requiresAuth: true, - }, + requiresAuth: true + } }; export class DappnodeTelegramBot { @@ -62,9 +62,7 @@ export class DappnodeTelegramBot { // 3. ETELEGRAM if error was returned from Telegram servers // ETELEGRAM: 409 Conflict => More than one bot instance polling // ETELEGRAM: 404 Not Found => wrong token or not found - this.bot.on("polling_error", (error) => - logs.error(`${error.name}: ${error.message}`) - ); + this.bot.on("polling_error", (error) => logs.error(`${error.name}: ${error.message}`)); this.bot.on("message", (msg) => this.handleMessage(msg)); } @@ -83,9 +81,7 @@ export class DappnodeTelegramBot { private async handleMessage(msg: TelegramBot.Message): Promise<void> { if (!msg.text) return; - const command = Object.keys(COMMANDS).find((cmd) => - msg.text?.startsWith(cmd) - ); + const command = Object.keys(COMMANDS).find((cmd) => msg.text?.startsWith(cmd)); if (!command) { await this.checkSubscription(msg); return; @@ -105,9 +101,7 @@ export class DappnodeTelegramBot { /** * Fetch wireguard credentials with the default device */ - private async handleGetWireguardCredentials( - msg: TelegramBot.Message - ): Promise<void> { + private async handleGetWireguardCredentials(msg: TelegramBot.Message): Promise<void> { // default device name is dappnode_admin, see https://github.com/dappnode/DNP_WIREGUARD/blob/4a074010c98b5d3003d1c3306edcb75392b247f4/docker-compose.yml#L12 const deviceName = msg.text?.split(" ")[1] || "dappnode_admin"; // build url with params.WIREGUARD_API_URL and deviceName @@ -120,11 +114,7 @@ export class DappnodeTelegramBot { msg.chat.id, `Device ${deviceName} not found. Please provide a valid device name or if you have setup dappnode cloud wait for the credentials to be generated.` ); - else - return await this.sendMessage( - msg.chat.id, - `Error fetching wireguard credentials. Please try again later.` - ); + else return await this.sendMessage(msg.chat.id, `Error fetching wireguard credentials. Please try again later.`); } await this.sendMessage(msg.chat.id, configRemote); @@ -133,9 +123,7 @@ export class DappnodeTelegramBot { /** * Enable auto-updates for system and regular packages */ - private async handleEnableAutoUpdates( - msg: TelegramBot.Message - ): Promise<void> { + private async handleEnableAutoUpdates(msg: TelegramBot.Message): Promise<void> { editDnpSetting(true); editCoreSetting(true); await this.sendMessage( @@ -147,9 +135,7 @@ export class DappnodeTelegramBot { /** * Disable auto-updates for system and regular packages */ - private async handleDisableAutoUpdates( - msg: TelegramBot.Message - ): Promise<void> { + private async handleDisableAutoUpdates(msg: TelegramBot.Message): Promise<void> { editDnpSetting(false); editCoreSetting(false); await this.sendMessage( @@ -164,14 +150,10 @@ export class DappnodeTelegramBot { private async handleGetHelp(msg: TelegramBot.Message): Promise<void> { const chatId = msg.chat.id.toString(); const commandsList = Object.entries(COMMANDS).map( - ([command, { description }]) => - `${command.replace(/_/g, "\\_")} - ${description}` // escape underscore for markdown + ([command, { description }]) => `${command.replace(/_/g, "\\_")} - ${description}` // escape underscore for markdown ); - await this.sendMessage( - chatId, - [bold("Commands"), ...commandsList].join("\n\n") - ); + await this.sendMessage(chatId, [bold("Commands"), ...commandsList].join("\n\n")); } /** @@ -179,9 +161,7 @@ export class DappnodeTelegramBot { */ private async handleSubscribe(msg: TelegramBot.Message): Promise<void> { const chatId = msg.chat.id.toString(); - const message = - this.formatTelegramCommandHeader("Success") + - "Successfully saved channel ID"; + const message = this.formatTelegramCommandHeader("Success") + "Successfully saved channel ID"; this.addChannelId(chatId); @@ -197,12 +177,9 @@ export class DappnodeTelegramBot { if (this.channelIdExists(chatId)) { this.removeChannelId(chatId); - message = - this.formatTelegramCommandHeader("Success") + - "Succesfully removed channel ID"; + message = this.formatTelegramCommandHeader("Success") + "Succesfully removed channel ID"; } else { - message = - this.formatTelegramCommandHeader("Fail") + "Channel ID not found"; + message = this.formatTelegramCommandHeader("Fail") + "Channel ID not found"; } await this.sendMessage(chatId, message); @@ -214,13 +191,8 @@ export class DappnodeTelegramBot { return !!userId && userId.toString() === db.telegramUserId.get(); } - private async sendUnauthorizedMessage( - chatId: number | string - ): Promise<void> { - await this.sendMessage( - chatId, - "Unauthorized user. Please contact the admin" - ); + private async sendUnauthorizedMessage(chatId: number | string): Promise<void> { + await this.sendMessage(chatId, "Unauthorized user. Please contact the admin"); } private async checkSubscription(msg: TelegramBot.Message): Promise<void> { @@ -241,17 +213,13 @@ export class DappnodeTelegramBot { private removeChannelId(channelId: string): void { const channelIds = db.telegramChannelIds.get(); - db.telegramChannelIds.set( - channelIds.filter((chatId) => chatId !== channelId) - ); + db.telegramChannelIds.set(channelIds.filter((chatId) => chatId !== channelId)); } /** * Builds the telegram command message header */ - private formatTelegramCommandHeader( - header: TelegramCommandMessageHeader - ): string { + private formatTelegramCommandHeader(header: TelegramCommandMessageHeader): string { switch (header) { case "Fail": return `❌ `; diff --git a/packages/daemons/src/telegramBot/formatNotification.ts b/packages/daemons/src/telegramBot/formatNotification.ts index 6235aa40e..3bc14c5b0 100644 --- a/packages/daemons/src/telegramBot/formatNotification.ts +++ b/packages/daemons/src/telegramBot/formatNotification.ts @@ -8,10 +8,7 @@ import { bold } from "./markdown.js"; * Format a notification as a Telegram message with emojis */ export function formatNotification(notification: PackageNotification): string { - return [ - `${typeToEmoji(notification.type)} ${bold(notification.title)}`, - notification.body, - ].join("\n\n"); + return [`${typeToEmoji(notification.type)} ${bold(notification.title)}`, notification.body].join("\n\n"); } /** diff --git a/packages/daemons/src/telegramBot/index.ts b/packages/daemons/src/telegramBot/index.ts index 7dc5e717f..a037dc7e4 100644 --- a/packages/daemons/src/telegramBot/index.ts +++ b/packages/daemons/src/telegramBot/index.ts @@ -43,8 +43,7 @@ async function checkTelegramStatus(): Promise<void> { } } -const checkTelegramStatusThrottled = - runOnlyOneSequentially(checkTelegramStatus); +const checkTelegramStatusThrottled = runOnlyOneSequentially(checkTelegramStatus); /** * Telegram bot diff --git a/packages/daemons/src/telegramBot/types.ts b/packages/daemons/src/telegramBot/types.ts index 4bf68c96f..7f4900bfe 100644 --- a/packages/daemons/src/telegramBot/types.ts +++ b/packages/daemons/src/telegramBot/types.ts @@ -1,6 +1 @@ -export type TelegramCommandMessageHeader = - | "Fail" - | "Success" - | "Stats" - | "Help" - | "Note"; +export type TelegramCommandMessageHeader = "Fail" | "Success" | "Stats" | "Help" | "Note"; diff --git a/packages/daemons/src/temperature/index.ts b/packages/daemons/src/temperature/index.ts index 50a5b998b..80da5c333 100644 --- a/packages/daemons/src/temperature/index.ts +++ b/packages/daemons/src/temperature/index.ts @@ -19,21 +19,21 @@ const thresholds: TemperatureThreshold[] = [ type: "warning", celsius: 95, title: "CPU temperature is too high", - body: "The CPU temperature has consistently been at a warning level of 95ºC, you can ommit this waring if your dappnode is syncinga blockchain, its temperature should decrease once synced.", + body: "The CPU temperature has consistently been at a warning level of 95ºC, you can ommit this waring if your dappnode is syncinga blockchain, its temperature should decrease once synced." }, { id: "cpuTemperature-danger", type: "danger", celsius: 100, title: "CPU temperature is too high", - body: "The CPU temperature is at a dangerous level of 100ºC. An unexpected shutdown might occur.", - }, + body: "The CPU temperature is at a dangerous level of 100ºC. An unexpected shutdown might occur." + } ]; // Store temperature exceedances const temperatureRecords: Record<string, TemperatureRecord> = { "cpuTemperature-warning": { lastEmit: 0, count: 0 }, - "cpuTemperature-danger": { lastEmit: 0, count: 0 }, + "cpuTemperature-danger": { lastEmit: 0, count: 0 } }; const HOUR_IN_MS = 3600000; // 60 minutes * 60 seconds * 1000 milliseconds @@ -84,7 +84,7 @@ function emitNotification(threshold: TemperatureThreshold): void { id: threshold.id, type: threshold.type, title: threshold.title, - body: threshold.body, + body: threshold.body }); } @@ -93,9 +93,5 @@ function emitNotification(threshold: TemperatureThreshold): void { * Checks CPU temperature and emit events if it's too high. */ export function startTemperatureDaemon(signal: AbortSignal): void { - runAtMostEvery( - async () => monitorCpuTemperature(), - params.TEMPERATURE_DAEMON_INTERVAL, - signal - ); + runAtMostEvery(async () => monitorCpuTemperature(), params.TEMPERATURE_DAEMON_INTERVAL, signal); } diff --git a/packages/daemons/test/testUtils.ts b/packages/daemons/test/testUtils.ts index 4ff25417f..0ab69ea40 100644 --- a/packages/daemons/test/testUtils.ts +++ b/packages/daemons/test/testUtils.ts @@ -4,9 +4,7 @@ import { ethers } from "ethers"; export const dappnodeInstaller = new DappnodeInstaller( "https://api.ipfs.dappnode.io", - new ethers.JsonRpcProvider( - `https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}` - ) + new ethers.JsonRpcProvider(`https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}`) ); export const mockDnpName = "mock-dnp.dnp.dappnode.eth"; @@ -36,7 +34,7 @@ export const mockContainer: PackageContainer = { defaultVolumes: [], dependencies: {}, origin: "", - avatarUrl: "", + avatarUrl: "" }; export const mockDnp: InstalledPackageData = { @@ -48,5 +46,5 @@ export const mockDnp: InstalledPackageData = { dependencies: {}, origin: "", avatarUrl: "", - containers: [mockContainer], + containers: [mockContainer] }; diff --git a/packages/daemons/test/unit/ethMultiClient.test.ts b/packages/daemons/test/unit/ethMultiClient.test.ts index b2cfa33f6..f9c79caf9 100644 --- a/packages/daemons/test/unit/ethMultiClient.test.ts +++ b/packages/daemons/test/unit/ethMultiClient.test.ts @@ -8,7 +8,7 @@ import { InstalledPackageData, Eth2ClientTarget, EthClientRemote, - EthClientInstallStatus, + EthClientInstallStatus } from "@dappnode/types"; import { mockDnp, mockContainer, dappnodeInstaller } from "../testUtils.js"; @@ -19,13 +19,12 @@ interface State { describe.skip("daemons > ethMultiClient > runWatcher", () => { it("Simulate a client change process", async () => { - let currentExecClient: string | null | undefined = - "besu.public.dappnode.eth"; + let currentExecClient: string | null | undefined = "besu.public.dappnode.eth"; let currentConsClient: string | null | undefined = "prysm.dnp.dappnode.eth"; let currentRemote: EthClientRemote | null = EthClientRemote.on; const newTarget: Eth2ClientTarget = { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }; /** @@ -33,7 +32,7 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { */ const state: State = { target: "remote", - status: {}, + status: {} }; /** @@ -48,19 +47,19 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { get: (): string | null | undefined => currentExecClient, set: async (execClient: string | null | undefined) => { currentExecClient = execClient; - }, + } }, consensusClientMainnet: { get: (): string | null | undefined => currentConsClient, set: async (consClient: string | null | undefined) => { currentConsClient = consClient; - }, + } }, ethClientRemote: { get: (): EthClientRemote | null => currentRemote, set: (target: EthClientRemote | null) => { currentRemote = target; - }, + } }, ethExecClientInstallStatus: { getAll: () => ({}), @@ -70,7 +69,7 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { }, remove: (keyArg: string) => { keyArg; - }, + } }, ethConsClientInstallStatus: { getAll: () => ({}), @@ -80,13 +79,13 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { }, remove: (keyArg: string) => { keyArg; - }, + } }, fullnodeDomainTarget: { get: (): string => "", set: (dnpName: string) => { dnpName; - }, + } }, ethClientUserSettings: { getAll: () => ({}), @@ -100,16 +99,11 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { }, remove: (keyArg: Eth2ClientTarget) => { keyArg; - }, - }, + } + } }; - /* eslint-enable @typescript-eslint/explicit-function-return-type */ - async function listPackageNoThrow({ - dnpName, - }: { - dnpName: string; - }): Promise<InstalledPackageData | null> { + async function listPackageNoThrow({ dnpName }: { dnpName: string }): Promise<InstalledPackageData | null> { return dnpList.find((d) => d.dnpName === dnpName) || null; } @@ -141,11 +135,7 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { if (target && target !== "remote") { const { execClient, consClient } = target; for (const client of [consClient, execClient]) { - const nextStatus = await runEthClientInstaller( - dappnodeInstaller, - client, - state.status[client] - ); + const nextStatus = await runEthClientInstaller(dappnodeInstaller, client, state.status[client]); if (nextStatus) state.status[client] = nextStatus; } } @@ -160,7 +150,7 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { expect(state).to.deep.equal( { target: "remote", - status: {}, + status: {} } as State, "State should be equal to initial" ); @@ -173,8 +163,8 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { target: newTarget, status: { [newTarget.execClient]: { status: "INSTALLED" }, - [newTarget.consClient]: { status: "INSTALLED" }, - }, + [newTarget.consClient]: { status: "INSTALLED" } + } } as State, "After the user selects a new target it should start installing" ); @@ -185,12 +175,12 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { { ...mockDnp, dnpName: newTarget.execClient, - containers: [{ ...mockContainer, running: true }], + containers: [{ ...mockContainer, running: true }] }, { ...mockDnp, dnpName: newTarget.consClient, - containers: [{ ...mockContainer, running: true }], + containers: [{ ...mockContainer, running: true }] } ); @@ -200,8 +190,8 @@ describe.skip("daemons > ethMultiClient > runWatcher", () => { target: newTarget, status: { [newTarget.execClient]: { status: "INSTALLED" }, - [newTarget.consClient]: { status: "INSTALLED" }, - }, + [newTarget.consClient]: { status: "INSTALLED" } + } } as State, "After installation, the loop does nothing" ); diff --git a/packages/daemons/test/unit/natRenewal.test.ts b/packages/daemons/test/unit/natRenewal.test.ts index 5f532a4fe..603d95c23 100644 --- a/packages/daemons/test/unit/natRenewal.test.ts +++ b/packages/daemons/test/unit/natRenewal.test.ts @@ -15,21 +15,21 @@ describe("daemons > natRenewal > getPortsToOpen", () => { isCore: true, dnpName: "admin.dnp.dappnode.eth", ports: [{ container: 80, host: 8090, protocol: PortProtocol.TCP }], - running: true, + running: true }, { ...mockContainer, isCore: true, dnpName: "vpn.dnp.dappnode.eth", ports: [{ container: 1194, host: 1194, protocol: PortProtocol.UDP }], - running: true, + running: true }, { ...mockContainer, isCore: true, dnpName: "vpn.dnp.dappnode.eth2", ports: [{ container: 1194, host: 1194, protocol: PortProtocol.UDP }], - running: true, + running: true }, { ...mockContainer, @@ -38,16 +38,16 @@ describe("daemons > natRenewal > getPortsToOpen", () => { ports: [ { container: 30303, host: 32769, protocol: PortProtocol.TCP }, { container: 30303, host: 32771, protocol: PortProtocol.UDP }, - { container: 30304, host: 32770, protocol: PortProtocol.UDP }, + { container: 30304, host: 32770, protocol: PortProtocol.UDP } ], - running: true, + running: true }, { ...mockContainer, isCore: false, dnpName: stoppedDnp, - running: false, - }, + running: false + } ]; async function listContainers(): Promise<PackageContainer[]> { @@ -60,13 +60,13 @@ describe("daemons > natRenewal > getPortsToOpen", () => { services: { [stoppedDnp]: { container_name: stoppedDnp, - image: stoppedDnp, - }, - }, + image: stoppedDnp + } + } }); compose.services()[stoppedDnp].setPortMapping([ { host: 4001, container: 4001, protocol: PortProtocol.UDP }, - { host: 4001, container: 4001, protocol: PortProtocol.TCP }, + { host: 4001, container: 4001, protocol: PortProtocol.TCP } ]); compose.writeTo(ComposeEditor.getComposePath(stoppedDnp, false)); @@ -79,14 +79,14 @@ describe("daemons > natRenewal > getPortsToOpen", () => { dnpName: "admin.dnp.dappnode.eth", protocol: "TCP", portNumber: 8090, - serviceName: "mock-dnp.dnp.dappnode.eth", + serviceName: "mock-dnp.dnp.dappnode.eth" }, // From "vpn.dnp.dappnode.eth" { dnpName: "vpn.dnp.dappnode.eth2", protocol: "UDP", portNumber: 1194, - serviceName: "mock-dnp.dnp.dappnode.eth", + serviceName: "mock-dnp.dnp.dappnode.eth" }, // From "goerli.dnp.dappnode.eth" @@ -94,20 +94,20 @@ describe("daemons > natRenewal > getPortsToOpen", () => { dnpName: "goerli.dnp.dappnode.eth", protocol: "TCP", portNumber: 32769, - serviceName: "mock-dnp.dnp.dappnode.eth", + serviceName: "mock-dnp.dnp.dappnode.eth" }, { dnpName: "goerli.dnp.dappnode.eth", protocol: "UDP", portNumber: 32771, - serviceName: "mock-dnp.dnp.dappnode.eth", + serviceName: "mock-dnp.dnp.dappnode.eth" }, { dnpName: "goerli.dnp.dappnode.eth", protocol: "UDP", portNumber: 32770, - serviceName: "mock-dnp.dnp.dappnode.eth", - }, + serviceName: "mock-dnp.dnp.dappnode.eth" + } // From "stopped.dnp.dappnode.eth" ]); }); @@ -122,13 +122,13 @@ describe("daemons > natRenewal > getPortsToOpen", () => { isCore: true, dnpName: "admin.dnp.dappnode.eth", ports: [{ container: 80, host: 8090, protocol: PortProtocol.TCP }], - running: true, + running: true }, { ...mockContainer, dnpName: throwsDnp, - running: false, - }, + running: false + } ]; } @@ -152,8 +152,8 @@ describe("daemons > natRenewal > getPortsToOpen", () => { dnpName: "admin.dnp.dappnode.eth", protocol: "TCP", portNumber: 8090, - serviceName: "mock-dnp.dnp.dappnode.eth", - }, + serviceName: "mock-dnp.dnp.dappnode.eth" + } ]); }); }); diff --git a/packages/daemons/test/unit/telegramBot.test.ts b/packages/daemons/test/unit/telegramBot.test.ts index a874ffa35..11b59da54 100644 --- a/packages/daemons/test/unit/telegramBot.test.ts +++ b/packages/daemons/test/unit/telegramBot.test.ts @@ -13,7 +13,7 @@ describe("daemons > telegramBot > formatNotification", () => { - Line 1 - Line 2 -Final line`, +Final line` }; const message = formatNotification(notification); diff --git a/packages/dappmanager/.eslintignore b/packages/dappmanager/.eslintignore deleted file mode 100644 index 7aa3f8b8f..000000000 --- a/packages/dappmanager/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -typings/ -dist -node_modules \ No newline at end of file diff --git a/packages/dappmanager/.eslintrc.cjs b/packages/dappmanager/.eslintrc.cjs deleted file mode 100644 index 4685e2b94..000000000 --- a/packages/dappmanager/.eslintrc.cjs +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs" // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - ignorePatterns: ["src/modules/ipfs/writeStreamToFs.ts"], - parserOptions: { - ecmaVersion: 2019 // For target ES2019 - }, - rules: { - // ##### Some libraries do not have typings and the compiler does not understand .d.ts files - "@typescript-eslint/no-var-requires": "off", - // ##### typescript does not understand hoisting - "@typescript-eslint/no-use-before-define": "off", - // ### This project uses docker-compose which has many variables not in camelCase - "@typescript-eslint/camelcase": "off" - } -}; diff --git a/packages/dappmanager/.prettierignore b/packages/dappmanager/.prettierignore deleted file mode 100644 index ead15ce46..000000000 --- a/packages/dappmanager/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -# Ignore image assets -*.png - -# Ignore test assets -*.tar.xz -*.sh \ No newline at end of file diff --git a/packages/dappmanager/.prettierrc b/packages/dappmanager/.prettierrc deleted file mode 100644 index 307e1bf0b..000000000 --- a/packages/dappmanager/.prettierrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "printWidth": 80, - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "quoteProps": "as-needed", - "jsxSingleQuote": false, - "trailingComma": "none", - "bracketSpacing": true, - "jsxBracketSameLine": false, - "arrowParens": "avoid" -} diff --git a/packages/dappmanager/package.json b/packages/dappmanager/package.json index 831434653..230439281 100644 --- a/packages/dappmanager/package.json +++ b/packages/dappmanager/package.json @@ -14,8 +14,6 @@ "test:int": "npm run test:int:file \"./{,!(node_modules)/**}/*.test.int.ts\" ", "test:int:file": "HTTP_API_PORT=5000 TEST=true mocha --config ./test/integration/.mocharc.yaml --timeout 180000", "test:all": "npm run test && npm run test:int", - "lint": "eslint . --ext .ts --fix", - "prettier": "prettier --write 'src/**/*.*' 'test/**/*.*'", "clean": "rm -rf DNCORE/ dnp_repo/ .temp-transfer/ cache/ dist/" }, "license": "GPL-3.0", diff --git a/packages/dappmanager/src/api/auth/adminPasswordDb.ts b/packages/dappmanager/src/api/auth/adminPasswordDb.ts index 215020e0f..162252418 100644 --- a/packages/dappmanager/src/api/auth/adminPasswordDb.ts +++ b/packages/dappmanager/src/api/auth/adminPasswordDb.ts @@ -83,8 +83,7 @@ export class AdminPasswordDb { const hash = passwordMap[id]; if (hash) { const loginToken = parseLoginToken(hash); - if (loginToken == null) - throw Error(AdminPasswordDbError.PASSWORD_CHANGED); + if (loginToken == null) throw Error(AdminPasswordDbError.PASSWORD_CHANGED); return loginToken; } diff --git a/packages/dappmanager/src/api/auth/sessionAuth.ts b/packages/dappmanager/src/api/auth/sessionAuth.ts index 494651419..ac6426fad 100644 --- a/packages/dappmanager/src/api/auth/sessionAuth.ts +++ b/packages/dappmanager/src/api/auth/sessionAuth.ts @@ -39,11 +39,7 @@ export class AuthPasswordSession { adminPasswordDb: AdminPasswordDb; recoveryDb: PlainTextFileDb; - constructor( - sessions: SessionsManager, - adminPasswordDb: AdminPasswordDb, - params: AuthPasswordSessionParams - ) { + constructor(sessions: SessionsManager, adminPasswordDb: AdminPasswordDb, params: AuthPasswordSessionParams) { this.sessions = sessions; this.adminPasswordDb = adminPasswordDb; this.recoveryDb = new PlainTextFileDb(params.ADMIN_RECOVERY_FILE); @@ -98,8 +94,7 @@ export class AuthPasswordSession { const password = req.body.password; if (!username || !password) throw new MissingCredentialsError(); - if (this.adminPasswordDb.hasSomePassword()) - throw new AlreadyRegisteredError(); + if (this.adminPasswordDb.hasSomePassword()) throw new AlreadyRegisteredError(); this.adminPasswordDb.setPassword(username, password); diff --git a/packages/dappmanager/src/api/auth/token.ts b/packages/dappmanager/src/api/auth/token.ts index dea8f9361..1491c8a60 100644 --- a/packages/dappmanager/src/api/auth/token.ts +++ b/packages/dappmanager/src/api/auth/token.ts @@ -4,12 +4,7 @@ export function getRandomAlphanumericToken(len: number): string { let token = ""; while (token.length < len) { - token += crypto - .randomBytes(len) - .toString("base64") - .replace(/\+/g, "") - .replace(/\//g, "") - .replace(/=/g, ""); + token += crypto.randomBytes(len).toString("base64").replace(/\+/g, "").replace(/\//g, "").replace(/=/g, ""); } return token.slice(0, len); diff --git a/packages/dappmanager/src/api/handler/index.ts b/packages/dappmanager/src/api/handler/index.ts index 9bafe0195..655655068 100644 --- a/packages/dappmanager/src/api/handler/index.ts +++ b/packages/dappmanager/src/api/handler/index.ts @@ -1,21 +1,13 @@ import Ajv from "ajv"; import { routesArgumentsSchema } from "@dappnode/common"; -import { - LoggerMiddleware, - RpcPayload, - Routes, - RpcResponse -} from "@dappnode/types"; +import { LoggerMiddleware, RpcPayload, Routes, RpcResponse } from "@dappnode/types"; const ajv = new Ajv({ allErrors: true }); /** * Given a set of method handlers, parse a RPC request and handle it */ -export const getRpcHandler = ( - methods: Routes, - loggerMiddleware?: LoggerMiddleware -) => { +export const getRpcHandler = (methods: Routes, loggerMiddleware?: LoggerMiddleware) => { const validateParams = ajv.compile(routesArgumentsSchema); const { onCall, onSuccess, onError } = loggerMiddleware || {}; @@ -31,8 +23,7 @@ export const getRpcHandler = ( // Validate params const valid = validateParams({ [method]: params }); - if (!valid) - throw new JsonRpcReqError(formatErrors(validateParams.errors, method)); + if (!valid) throw new JsonRpcReqError(formatErrors(validateParams.errors, method)); const result = await handler(...params); if (onSuccess) onSuccess(method, result, params); @@ -59,13 +50,11 @@ function parseRpcRequest(body: RpcPayload): { // eslint-disable-next-line @typescript-eslint/no-explicit-any params: any[]; } { - if (typeof body !== "object") - throw Error(`body request must be an object, ${typeof body}`); + if (typeof body !== "object") throw Error(`body request must be an object, ${typeof body}`); const { method, params } = body; if (!method) throw new JsonRpcReqError("request body missing method"); if (!params) throw new JsonRpcReqError("request body missing params"); - if (!Array.isArray(params)) - throw new JsonRpcReqError("request body params must be an array"); + if (!Array.isArray(params)) throw new JsonRpcReqError("request body params must be an array"); return { method: method as keyof Routes, params }; } @@ -78,17 +67,11 @@ function tryToParseRpcRequest(body: any): { method?: string; params?: any[] } { } } -function formatErrors( - errors: Array<Ajv.ErrorObject> | null | undefined, - method: string -): string { +function formatErrors(errors: Array<Ajv.ErrorObject> | null | undefined, method: string): string { const dataVar = `root_prop`; const toReplace = `${dataVar}.${method}`; const errorsText = ajv.errorsText(errors, { separator: "\n", dataVar }); - return ( - "Validation error:\n" + - errorsText.replace(new RegExp(toReplace, "g"), "params") - ); + return "Validation error:\n" + errorsText.replace(new RegExp(toReplace, "g"), "params"); } /** diff --git a/packages/dappmanager/src/api/middlewares/ethForward/index.ts b/packages/dappmanager/src/api/middlewares/ethForward/index.ts index 8f033b59a..6c6463dfa 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/index.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/index.ts @@ -32,9 +32,5 @@ function parseEthDomainHost(req: express.Request): string | null { // - my.dappmanager.dnp.dappnode.eth => false // - my.dappnode => false const domain = req.headers.host; - return typeof domain === "string" && - domain.endsWith(".eth") && - !domain.endsWith("dnp.dappnode.eth") - ? domain - : null; + return typeof domain === "string" && domain.endsWith(".eth") && !domain.endsWith("dnp.dappnode.eth") ? domain : null; } diff --git a/packages/dappmanager/src/api/middlewares/ethForward/ipfsProxy.ts b/packages/dappmanager/src/api/middlewares/ethForward/ipfsProxy.ts index 919cbd3fe..05536cf1f 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/ipfsProxy.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/ipfsProxy.ts @@ -5,13 +5,7 @@ import { params } from "@dappnode/params"; import { urlJoin } from "@dappnode/utils"; import { logs } from "@dappnode/logger"; import * as views from "./views/index.js"; -import { - NodeNotAvailable, - ProxyError, - EnsResolverError, - NotFoundError, - Content -} from "./types.js"; +import { NodeNotAvailable, ProxyError, EnsResolverError, NotFoundError, Content } from "./types.js"; import { EthProviderError } from "@dappnode/types"; export enum ProxyType { @@ -27,7 +21,7 @@ export function getIpfsProxyHandler<T>( getContent: (req: express.Request, data: T) => Promise<Content> ): (req: express.Request, res: express.Response, data: T) => Promise<void> { const proxy = httpProxy.createProxyServer({}); - proxy.on("error", e => { + proxy.on("error", (e) => { logs.error(`${proxyType} proxy error`, e); }); @@ -35,11 +29,7 @@ export function getIpfsProxyHandler<T>( `Starting ${proxyType} proxy: IPFS -> ${params.ETHFORWARD_IPFS_REDIRECT} SWARM -> ${params.ETHFORWARD_SWARM_REDIRECT}` ); - return async function ethForwardProxyHttpHandler( - req, - res, - data - ): Promise<void> { + return async function ethForwardProxyHttpHandler(req, res, data): Promise<void> { try { const content = await getContent(req, data); const target = getTargetUrl(proxyType, content); @@ -58,8 +48,7 @@ export function getIpfsProxyHandler<T>( if (!e) return resolve(proxyRes); // Indicates that the host is unreachable. // Usually happens when the node is not running - if (e.message.includes("EHOSTUNREACH")) - reject(new NodeNotAvailable(e.message, content.location)); + if (e.message.includes("EHOSTUNREACH")) reject(new NodeNotAvailable(e.message, content.location)); else reject(new ProxyError(e.message, target)); }); }); @@ -114,8 +103,7 @@ function errorToResponseHtml(e: Error, domain?: string): string { logs.debug(`ETHFORWARD Error: ${e.message}`); // Not found views - if (e instanceof EnsResolverError || e instanceof NotFoundError) - return views.notFound(e); + if (e instanceof EnsResolverError || e instanceof NotFoundError) return views.notFound(e); // Node not available views if (e instanceof EthProviderError) return views.noEth(e); diff --git a/packages/dappmanager/src/api/middlewares/ethForward/resolveDomain.ts b/packages/dappmanager/src/api/middlewares/ethForward/resolveDomain.ts index 980adde61..ecc1c62f5 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/resolveDomain.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/resolveDomain.ts @@ -3,12 +3,7 @@ import { getEthersProvider, getEthUrl } from "@dappnode/installer"; import resolverAbi from "./abi/resolverAbi.json" assert { type: "json" }; import ensAbi from "./abi/ens.json" assert { type: "json" }; import { Network, Content, NotFoundError, EnsResolverError } from "./types.js"; -import { - decodeContentHash, - isEmpty, - decodeDnsLink, - decodeContent -} from "./utils/index.js"; +import { decodeContentHash, isEmpty, decodeDnsLink, decodeContent } from "./utils/index.js"; import memoize from "memoizee"; const providerUrlCacheMs = 60 * 1000; @@ -24,11 +19,7 @@ const ropstenJsonRpc = "http://ropsten.dappnode:8545"; const CONTENTHASH_INTERFACE_ID = "0xbc1c58d1"; const TEXT_INTERFACE_ID = "0x59d1d43c"; const CONTENT_INTERFACE_ID = "0xd8389dc5"; -const interfaces = [ - CONTENTHASH_INTERFACE_ID, - TEXT_INTERFACE_ID, - CONTENT_INTERFACE_ID -]; +const interfaces = [CONTENTHASH_INTERFACE_ID, TEXT_INTERFACE_ID, CONTENT_INTERFACE_ID]; interface InterfacesAvailable { [interfaceHash: string]: boolean; @@ -75,15 +66,11 @@ export function ResolveDomainWithCache(): (domain: string) => Promise<Content> { * @param domain * @returns content object */ -export async function resolveDomain( - domain: string, - provider: ethers.Provider -): Promise<Content> { +export async function resolveDomain(domain: string, provider: ethers.Provider): Promise<Content> { const node = ethers.namehash(domain); const ens = new ethers.Contract(ensAddress, ensAbi, provider); const resolverAddress = await ens.resolver(node); - if (parseInt(resolverAddress) === 0) - throw new EnsResolverError("resolver not found", { domain }); + if (parseInt(resolverAddress) === 0) throw new EnsResolverError("resolver not found", { domain }); const resolver = new ethers.Contract(resolverAddress, resolverAbi, provider); const interfacesAvailable = await getInterfacesAvailable(resolver); @@ -138,12 +125,10 @@ function parseNetworkFromDomain(domain: string): Network { * [TEXT_INTERFACE_ID]: true, * } */ -async function getInterfacesAvailable( - resolver: ethers.Contract -): Promise<InterfacesAvailable> { +async function getInterfacesAvailable(resolver: ethers.Contract): Promise<InterfacesAvailable> { const iAvail: InterfacesAvailable = {}; await Promise.all( - interfaces.map(async iHash => { + interfaces.map(async (iHash) => { iAvail[iHash] = await resolver.supportsInterface(iHash); }) ); diff --git a/packages/dappmanager/src/api/middlewares/ethForward/types.ts b/packages/dappmanager/src/api/middlewares/ethForward/types.ts index 872f120f6..b342c0ccd 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/types.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/types.ts @@ -24,11 +24,7 @@ export type Content = /** * Custom errors */ -export type EthForwardErrorCode = - | "NOTFOUND" - | "RESOLVERNOTFOUND" - | "PROXYERROR" - | "NODENOTAVAILABLE"; +export type EthForwardErrorCode = "NOTFOUND" | "RESOLVERNOTFOUND" | "PROXYERROR" | "NODENOTAVAILABLE"; export class EthForwardError extends Error { code: EthForwardErrorCode; diff --git a/packages/dappmanager/src/api/middlewares/ethForward/views/base.ts b/packages/dappmanager/src/api/middlewares/ethForward/views/base.ts index dabcf51da..41aa07457 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/views/base.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/views/base.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ const logoSrcBase64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABVCAMAAADpApMsAAAC31BMVEVHcEytra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra2tra25QZdfAAAA9HRSTlMABwr5/e/+AQL6+/YMBOoY8QPy/PMkCA715RPZCRLw6+YF3JZp7VcwDcXoPyND9MQdHiXJzPgbFFXdKKEfiX3TSNrbN+njgLJ5c3ca4Ijna6RlTSocoNTsJxdGWCIxfIufsBXChMcmIGyzEUczWRZCC5ebSz2pZD5wUY7L5HaYOgajzWpaEM50Sk/irKaRGZ7Y1lbeuNCHyLaaOylQu5kr4afR1Til91y5kMruOQ9ehr2BrnVuemhbtcZOosPXt2FJbZWSRY0yNa0swau60r9SLpM8wLSFNGadlERTYopBXUx/gr6cb37fYC9AqiHPg3GPVIyxeKqpyAAAB4hJREFUGBmtwIN6K4sCBeAVTlzbtrVt1du2bdu2bds8tu1r2+sBbjIzaWaSpue0X380R3Sfj+NX9n0XrSXgwxA6Jb+G1mFaTsmFkWgVxT0pW4pWsVVHWXsBzZZ0YsacQqgsMFO2TkBzDR1Up7N2HX0LCicSKVuF5goroei0Fh5B8yhJHopmMr1BiS4dCkVX6ZLYBs1V2Jayc0FQGNYrnmU7b6LZ3jFQlmWDUlxnHihE853IpuyqBkoBe7k3AH4IAvyZe4qyTlApT+bgCjSqXVXfdVuK4cfJQIoOjYRKYQ0330Jj0tvSKeYkGmf6tiedVqyBWl4Cu10U4GthNkVnF8KPzx7F0PwpVGL7RJHMvmeDN3tfysbBr6/JeqhUhdDF+FsTvATspSwNfj3RMwVK7XpS0iMDXopqKLsMv7oH8m4sFP5Mt6nwEjGJshj4tXsvDxQL8Kik2z14W2WkSN8Jfv39HzRfP/cwFxLNzd50ewxvawwULYqGH8Kn60Po0i1VA6AifZyBbmnfwItmLBkcGZl8Zzb86RdPme6fsUOrSs0kDTqKLMcqoDbCysRtC3OKBPiT42CDyKM1JI0xHbvXdw1hSGIZ+b+RUCo6RI5GU8LvU836ZWoRgCn7p6a3qwwkn82Eh2k5OWE8mjJqCJUSXmyNQAPhSRQZMwMNZsQzfgZ8lS/Jm2yH6IqRSp+boPLDPrLutgmS8RPIf5vgLaLPy5GXo34fBifTaKqkwEtGARlcpYFoNHmoCN5i51GUNWBk/17T6qjyNrxNuU+ar91KWrO0U586WkfAR7qOkm5ndfS2GD6iUyw07thjoMseDbwFnaOCNTmBCj3bwVdsp3zKjBvgw/aMMmPXRQ/yqlMt9KgV0Iigfg7KjkTDW/hHlDm6CwC089ngYAAa156y/CXw0YuyU1q4xO3Kp+RoBzRO2EmZ5SR8hHWmKHgZJEkLFrU1xBvIXfBnOWWhx+FryXo6RaUGwc1eOPOdbUN4IBd+dImk5KVNaMTADXsudcqAmv1D8l/wQ/OGni5D+sMPAT6WlfFIHPwo70zSvH6ZgJ9u+jPqZsUFRKAxoxysqew/DM0y1cienWMmpeQlwUcf8nM0kzDVTFHwvAB4yZxAaxdItKMW5ATgJ1gcSLdx46G2JJil0RBd7J1mjuxcHw632AHH39fC18U6enQ0QeUweQeim23pYukVBElO7x75jleGw5u9PRWyM6BUsZ6BX8BF+xUlhi8g2hpFF8fP4CV3O5VWQWnrZX6QCZdvblB2GC7DVlAyuBBqw8uo1FeAmz0iYjVZBdECC2U7TXBaZqHEeAVqbfRU6h0Eycg/3C8pNXBIBlzK3zZSthoulXTrBbUuOip9MkWAk/3VGIpCt4QDuY8u6CkLuQKXVLo9gNrklVSydD32fBiwxUqZ+fBfJiaTNOspOjgdLt1vUBKaA7WknfSi+3jMAwMb6BwkI5+2+WMCScvRoRAlraYkdCO85AXTY9p7dXQyUiVwx2tamLr/ZtCb6ZsgC7hkpqjHfqhoJprZ4Opu+/tLP0qj2sG/auDL1mZ+7+++PUo60qGgmWimOYEia/siOGln/o0qo+FHElD4lHTMAiDYpmsBaCaaaakd1euDtmfPt+8fDskqqlxDEwZ+RSbMits/NmvzJ7vy4r4201IbDswdOCXaBLfXqTIRTSmfRiZc19ElsKSMltpweHvLSgX9RjSpfJyRHmV3wuFj9z4qdJuCps100GNFNHx0eDOfHvo++BFbjPQI7YIGHTZWPZ4ZtDb9PJUcGWhaZgGV5kFmuv2ynkxIGWsl08bsCqTb93Y0aWgilQpskIwIptuXPwhBbw3a18MRc+lRAkOfo0mjDFTqHA3R+FLKenSqgJNp2IAz1XYcJkuq4SMzLCwCImFGPJVKIiCaY6XsGJSqS8haAWrafhOiorLqbUDAf9b1NFJpnQmi/XrKBkHleSjThsfaBHhol1vopD82/L+DzVQzz4Lkl1bKOkLF/j3ZtiDrdI4At9QyivRWOm3fsZ0emysgqbhOSf5wqE2uoUva6ybINrPBjYMbJgfNMrBB/GMBkjaBFKVooNY/kKL4LpBFUhY55t1YAMKIrhTpV+oZnCpAZHoyOITsMSYOamvHUbbIDkkgZckBkEy+VxpC6936AS/I4HoTJAPbVC7OCIKX6m6UXZgNye8o662BW0Y2S8cD0S/I0KkmNGHgAcpiAiDZlkZR6DY0KE7kJBuAuPZk6EMT/NPepeyVcEhMG4bQyVBpR4PiRE7KhNP0QWT+Q01ul1+fSUKj+oVQZP4V3ISFqwuy5s8xwaM4kUcy4TJ9Dxk47U86c/bYMDRmboqeTpZrsVCYaxOgFBbFI5kQbfpOT8lLHdAYW2pB1MoJ/bRoSlgiS2yQbHpK2Rg0LiIsNxNN+mysjoaOHSBaO42ywbPRMnnJdJk0AC5xhyjLbocW2V1KyQ4tnGwFlNV0QIvcNlISfBwuHSl7by1a5Bd0+zlc2u2jyDEHLdORbq9ClLOCTt1GoIU2hlBi6A5J9eKU00uL0VKzsyjpq0HrWHOeLqdy0VrOzN8e3LW2HC3yf+Xo1Doq1ayrAAAAAElFTkSuQmCC"; diff --git a/packages/dappmanager/src/api/middlewares/ethForward/views/index.ts b/packages/dappmanager/src/api/middlewares/ethForward/views/index.ts index 923498b70..262e4dbc0 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/views/index.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/views/index.ts @@ -8,8 +8,7 @@ const adminUiPackagesUrl = `${adminUiUrl}/packages`; const ropstenName = "ropsten.dnp.dappnode.eth"; const swarmName = "swarm.dnp.dappnode.eth"; -const a = (url: string, text?: string): string => - `<a href="${url}">${text || url}</a>`; +const a = (url: string, text?: string): string => `<a href="${url}">${text || url}</a>`; export function notFound(e: NotFoundError): string { return base( diff --git a/packages/dappmanager/src/api/routes/dataSend.ts b/packages/dappmanager/src/api/routes/dataSend.ts index a6d3b3988..68cc2fb82 100644 --- a/packages/dappmanager/src/api/routes/dataSend.ts +++ b/packages/dappmanager/src/api/routes/dataSend.ts @@ -14,7 +14,7 @@ export const dataSend = wrapHandler(async (req, res) => { const data = req.query.data || req.body; try { - if (typeof key === undefined) throw Error("missing"); + if (typeof key === "undefined") throw Error("missing"); if (typeof key !== "string") throw Error("must be a string"); if (!key) throw Error("must not be empty"); } catch (e) { @@ -22,7 +22,7 @@ export const dataSend = wrapHandler(async (req, res) => { } try { - if (typeof data === undefined) throw Error("missing"); + if (typeof data === "undefined") throw Error("missing"); if (typeof data !== "string") throw Error("must be a string"); // OK to be empty if (data.length > MAX_LENGTH) throw Error("too long"); diff --git a/packages/dappmanager/src/api/routes/download.ts b/packages/dappmanager/src/api/routes/download.ts index 9bf3912c7..e85049db8 100644 --- a/packages/dappmanager/src/api/routes/download.ts +++ b/packages/dappmanager/src/api/routes/download.ts @@ -20,9 +20,9 @@ export const download = wrapHandlerHtml<Params>((req, res) => { // Remove the fileId from the DB FIRST to prevent reply attacks db.fileTransferPath.remove(fileId); - return res.download(filePath, errHttp => { + return res.download(filePath, (errHttp) => { if (!errHttp) - fs.unlink(filePath, errFs => { + fs.unlink(filePath, (errFs) => { if (errFs) logs.error(`Error deleting file: ${errFs.message}`); }); }); diff --git a/packages/dappmanager/src/api/routes/downloadWireguardConfig.ts b/packages/dappmanager/src/api/routes/downloadWireguardConfig.ts index 908d2edab..586798593 100644 --- a/packages/dappmanager/src/api/routes/downloadWireguardConfig.ts +++ b/packages/dappmanager/src/api/routes/downloadWireguardConfig.ts @@ -10,22 +10,18 @@ interface Params { * - /device_admin/local * - /device_admin/ */ -export const downloadWireguardConfig = wrapHandlerHtml<Params>( - async (req, res) => { - const isLocal = req.query.local === "" || req.query.local; +export const downloadWireguardConfig = wrapHandlerHtml<Params>(async (req, res) => { + const isLocal = req.query.local === "" || req.query.local; - const device = req.params.device; - if (!device) throw Error(`Must provide device`); + const device = req.params.device; + if (!device) throw Error(`Must provide device`); - const { configRemote, configLocal } = await calls.wireguardDeviceGet( - device - ); + const { configRemote, configLocal } = await calls.wireguardDeviceGet(device); - const filename = `wireguard-${isLocal ? "local" : ""}config-${device}.txt`; - const mimetype = "text/plain"; - res.setHeader("Content-disposition", "attachment; filename=" + filename); - res.setHeader("Content-type", mimetype); + const filename = `wireguard-${isLocal ? "local" : ""}config-${device}.txt`; + const mimetype = "text/plain"; + res.setHeader("Content-disposition", "attachment; filename=" + filename); + res.setHeader("Content-type", mimetype); - res.status(200).send(isLocal ? configLocal : configRemote); - } -); + res.status(200).send(isLocal ? configLocal : configRemote); +}); diff --git a/packages/dappmanager/src/api/routes/fileDownload.ts b/packages/dappmanager/src/api/routes/fileDownload.ts index 748693b79..3fd599b79 100644 --- a/packages/dappmanager/src/api/routes/fileDownload.ts +++ b/packages/dappmanager/src/api/routes/fileDownload.ts @@ -1,9 +1,6 @@ import { wrapHandlerHtml } from "../utils.js"; import { dockerInfoArchive } from "@dappnode/dockerapi"; -import { - dockerGetFileOrDirBasedOnExtension, - dockerGetPathType -} from "@dappnode/dockerapi"; +import { dockerGetFileOrDirBasedOnExtension, dockerGetPathType } from "@dappnode/dockerapi"; interface Params { containerName: string; @@ -34,10 +31,5 @@ export const fileDownload = wrapHandlerHtml<Params>(async (req, res) => { // Download single file as same mimetype, directory as .tar res.attachment(isSingleFile ? filepath : `${filepath}.tar`); - await dockerGetFileOrDirBasedOnExtension( - containerNameOrId, - filePathAbsolute, - res, - { isSingleFile } - ); + await dockerGetFileOrDirBasedOnExtension(containerNameOrId, filePathAbsolute, res, { isSingleFile }); }); diff --git a/packages/dappmanager/src/api/routes/metrics.ts b/packages/dappmanager/src/api/routes/metrics.ts index 44ae97faf..e2c9d80d0 100644 --- a/packages/dappmanager/src/api/routes/metrics.ts +++ b/packages/dappmanager/src/api/routes/metrics.ts @@ -102,13 +102,7 @@ register.registerMetric( return 0; } - for (const network of [ - "mainnet", - "prater", - "gnosis", - "lukso", - "holesky" - ] as Network[]) { + for (const network of ["mainnet", "prater", "gnosis", "lukso", "holesky"] as Network[]) { const isMevBoostSelected = mevBoost.DbHandlers[network].get(); const executionClient = execution.DbHandlers[network].get(); const consensusClient = consensus.DbHandlers[network].get(); @@ -120,10 +114,7 @@ register.registerMetric( dnpName: executionClient })) ) - this.set( - { executionClient: network }, - parseClientToNumber(executionClient) - ); + this.set({ executionClient: network }, parseClientToNumber(executionClient)); else this.set({ executionClient: network }, 0); // Consensus client @@ -133,10 +124,7 @@ register.registerMetric( dnpName: consensusClient })) ) - this.set( - { consensusClient: network }, - parseClientToNumber(consensusClient) - ); + this.set({ consensusClient: network }, parseClientToNumber(consensusClient)); else this.set({ consensusClient: network }, 0); // MEV boost @@ -189,13 +177,8 @@ register.registerMetric( collect() { const autoUpdates = db.autoUpdateSettings.get(); if (!isEmpty(autoUpdates) && "system-packages" in autoUpdates) { - const autoUpdatesSystemPackages = autoUpdates["system-packages"].enabled - ? 1 - : 0; - this.set( - { autoUpdatesSystemPackages: "enabled" }, - autoUpdatesSystemPackages - ); + const autoUpdatesSystemPackages = autoUpdates["system-packages"].enabled ? 1 : 0; + this.set({ autoUpdatesSystemPackages: "enabled" }, autoUpdatesSystemPackages); } else { this.set({ autoUpdatesSystemPackages: "enabled" }, 0); } @@ -212,13 +195,8 @@ register.registerMetric( collect() { const autoUpdates = db.autoUpdateSettings.get(); if (!isEmpty(autoUpdates) && "my-packages" in autoUpdates) { - const autoUpdatesUserPackages = autoUpdates["my-packages"].enabled - ? 1 - : 0; - this.set( - { autoUpdatesUserPackages: "enabled" }, - autoUpdatesUserPackages - ); + const autoUpdatesUserPackages = autoUpdates["my-packages"].enabled ? 1 : 0; + this.set({ autoUpdatesUserPackages: "enabled" }, autoUpdatesUserPackages); } else { this.set({ autoUpdatesUserPackages: "enabled" }, 0); } diff --git a/packages/dappmanager/src/api/routes/notificationSend.ts b/packages/dappmanager/src/api/routes/notificationSend.ts index 2a3041cc8..ae38c3e5e 100644 --- a/packages/dappmanager/src/api/routes/notificationSend.ts +++ b/packages/dappmanager/src/api/routes/notificationSend.ts @@ -1,6 +1,7 @@ import { getDnpFromIp } from "./sign.js"; import { eventBus } from "@dappnode/eventbus"; import { HttpError, wrapHandler } from "../utils.js"; +import { NotificationType } from "@dappnode/types"; /** * Receive arbitrary notifications from packages to be shown in the UI @@ -11,16 +12,16 @@ export const notificationSend = wrapHandler(async (req, res) => { const body = req.query.body; // "Some text about notification" try { - if (typeof type === undefined) throw Error("missing"); + if (typeof type === "undefined") throw Error("missing"); if (typeof type !== "string") throw Error("must be a string"); - if (type !== ("danger" || "warning" || "success" || "info")) + if (!["danger", "warning", "success", "info"].includes(type)) throw Error("must be danger, warning, success or info"); } catch (e) { throw new HttpError({ statusCode: 400, name: `Arg type ${e.message}` }); } try { - if (typeof title === undefined) throw Error("missing"); + if (typeof title === "undefined") throw Error("missing"); if (typeof title !== "string") throw Error("must be a string"); if (!title) throw Error("must not be empty"); } catch (e) { @@ -28,7 +29,7 @@ export const notificationSend = wrapHandler(async (req, res) => { } try { - if (typeof body === undefined) throw Error("missing"); + if (typeof body === "undefined") throw Error("missing"); if (typeof body !== "string") throw Error("must be a string"); if (!body) throw Error("must not be empty"); } catch (e) { @@ -39,7 +40,7 @@ export const notificationSend = wrapHandler(async (req, res) => { eventBus.notification.emit({ id: `notification-${dnpName}`, - type, + type: type as NotificationType, // TODO: fix this type cast by using enum instead title, body }); diff --git a/packages/dappmanager/src/api/routes/publicPackagesData.ts b/packages/dappmanager/src/api/routes/publicPackagesData.ts index 351dad0a3..ccf14e602 100644 --- a/packages/dappmanager/src/api/routes/publicPackagesData.ts +++ b/packages/dappmanager/src/api/routes/publicPackagesData.ts @@ -1,7 +1,4 @@ -import { - listPackageContainers, - listPackageContainerNoThrow -} from "@dappnode/dockerapi"; +import { listPackageContainers, listPackageContainerNoThrow } from "@dappnode/dockerapi"; import { PackageContainer } from "@dappnode/types"; import { wrapHandler } from "../utils.js"; diff --git a/packages/dappmanager/src/api/routes/sign.ts b/packages/dappmanager/src/api/routes/sign.ts index 7399541ae..a3da381b6 100644 --- a/packages/dappmanager/src/api/routes/sign.ts +++ b/packages/dappmanager/src/api/routes/sign.ts @@ -1,10 +1,7 @@ import { PackageContainer } from "@dappnode/types"; import * as db from "@dappnode/db"; import { listPackageContainers } from "@dappnode/dockerapi"; -import { - signDataFromPackage, - getAddressFromPrivateKey -} from "../../utils/index.js"; +import { signDataFromPackage, getAddressFromPrivateKey } from "../../utils/index.js"; import { HttpError, wrapHandler } from "../utils.js"; type Params = Record<string, unknown>; @@ -16,7 +13,7 @@ export const sign = wrapHandler<Params>(async (req, res) => { const data = req.body as string | undefined; try { - if (typeof data === undefined) throw Error("missing"); + if (typeof data === "undefined") throw Error("missing"); if (typeof data !== "string") throw Error("must be a string"); if (!data) throw Error("must not be empty"); } catch (e) { @@ -47,9 +44,8 @@ export const sign = wrapHandler<Params>(async (req, res) => { export async function getDnpFromIp(ip: string): Promise<PackageContainer> { const ipv4 = ip.replace("::ffff:", ""); const dnps = await listPackageContainers(); - const dnp = dnps.find(_dnp => _dnp.ip === ipv4); - if (!dnp) - throw new HttpError({ statusCode: 405, name: `No DNP with ip ${ipv4}` }); + const dnp = dnps.find((_dnp) => _dnp.ip === ipv4); + if (!dnp) throw new HttpError({ statusCode: 405, name: `No DNP with ip ${ipv4}` }); return dnp; } diff --git a/packages/dappmanager/src/api/routes/upload.ts b/packages/dappmanager/src/api/routes/upload.ts index 9984eeb19..0aa9d61d3 100644 --- a/packages/dappmanager/src/api/routes/upload.ts +++ b/packages/dappmanager/src/api/routes/upload.ts @@ -14,30 +14,29 @@ const tempTransferDir = params.TEMP_TRANSFER_DIR; * A fileId will be provided afterwards to be used in another useful call */ export const upload = wrapHandler(async (req, res) => { - if (!req.files || typeof req.files !== "object") - return res.status(400).send("Argument files missing"); - if (Object.keys(req.files).length == 0) - return res.status(400).send("No files were uploaded."); + if (!req.files || typeof req.files !== "object") return res.status(400).send("Argument files missing"); + if (Object.keys(req.files).length == 0) return res.status(400).send("No files were uploaded."); const fileId = crypto.randomBytes(32).toString("hex"); const filePath = path.join(tempTransferDir, fileId); // Use the mv() method to place the file somewhere on your server // The name of the input field (i.e. "file") is used to retrieve the uploaded file - const file = Array.isArray(req.files.file) - ? req.files.file[0] - : req.files.file; - file.mv(filePath, err => { + const file = Array.isArray(req.files.file) ? req.files.file[0] : req.files.file; + file.mv(filePath, (err) => { if (err) return res.status(500).send(err); db.fileTransferPath.set(fileId, filePath); res.send(fileId); // Delete the file after 15 minutes - setTimeout(() => { - fs.unlink(filePath, errFs => { - if (errFs) logs.error(`Error deleting file: ${errFs.message}`); - }); - }, 15 * 60 * 1000); + setTimeout( + () => { + fs.unlink(filePath, (errFs) => { + if (errFs) logs.error(`Error deleting file: ${errFs.message}`); + }); + }, + 15 * 60 * 1000 + ); return; }); return; diff --git a/packages/dappmanager/src/api/startHttpApi.ts b/packages/dappmanager/src/api/startHttpApi.ts index a0bc097fb..616375415 100644 --- a/packages/dappmanager/src/api/startHttpApi.ts +++ b/packages/dappmanager/src/api/startHttpApi.ts @@ -8,30 +8,17 @@ import cors from "cors"; import { Server } from "socket.io"; import path from "path"; import { toSocketIoHandler, wrapHandler } from "./utils.js"; -import { - AuthPasswordSession, - AuthPasswordSessionParams -} from "./auth/index.js"; +import { AuthPasswordSession, AuthPasswordSessionParams } from "./auth/index.js"; import { AdminPasswordDb } from "./auth/adminPasswordDb.js"; -import { - ClientSideCookies, - ClientSideCookiesParams -} from "./sessions/index.js"; +import { ClientSideCookies, ClientSideCookiesParams } from "./sessions/index.js"; import { mapSubscriptionsToEventBus } from "./subscriptions.js"; import { Logs } from "@dappnode/logger"; import { EventBus } from "@dappnode/eventbus"; import { subscriptionsFactory } from "@dappnode/common"; -import { - RpcPayload, - RpcResponse, - LoggerMiddleware, - Routes -} from "@dappnode/types"; +import { RpcPayload, RpcResponse, LoggerMiddleware, Routes } from "@dappnode/types"; import { getRpcHandler } from "./handler/index.js"; -export interface HttpApiParams - extends ClientSideCookiesParams, - AuthPasswordSessionParams { +export interface HttpApiParams extends ClientSideCookiesParams, AuthPasswordSessionParams { AUTH_IP_ALLOW_LOCAL_IP: boolean; HTTP_API_PORT: number | string; UI_FILES_PATH: string; @@ -128,22 +115,18 @@ export function startHttpApi({ io.use(toSocketIoHandler(sessions.handler)); io.use(toSocketIoHandler(auth.onlyAdmin)); - io.on("connection", socket => { + io.on("connection", (socket) => { console.log(`Socket connected`, socket.id); // JSON RPC over WebSockets - socket.on( - "rpc", - (rpcPayload: RpcPayload, callback: (res: RpcResponse) => void) => { - if (typeof callback !== "function") - return logs.error("JSON RPC over WS req without cb", rpcPayload); - - rpcHandler(rpcPayload) - .then(callback) - .catch(error => callback({ error })) - .catch(error => logs.error("Error on JSON RPC over WS cb", error)); - } - ); + socket.on("rpc", (rpcPayload: RpcPayload, callback: (res: RpcResponse) => void) => { + if (typeof callback !== "function") return logs.error("JSON RPC over WS req without cb", rpcPayload); + + rpcHandler(rpcPayload) + .then(callback) + .catch((error) => callback({ error })) + .catch((error) => logs.error("Error on JSON RPC over WS cb", error)); + }); // If DAPPMANAGER's version has changed reload the client if (isNewDappmanagerVersion()) { @@ -197,8 +180,6 @@ export function startHttpApi({ // prettier-ignore app.get("*", (_, res) => res.sendFile(path.resolve(params.UI_FILES_PATH, "index.html"))); - server.listen(params.HTTP_API_PORT, () => - logs.info(`HTTP API ${params.HTTP_API_PORT}`) - ); + server.listen(params.HTTP_API_PORT, () => logs.info(`HTTP API ${params.HTTP_API_PORT}`)); return server; } diff --git a/packages/dappmanager/src/api/startTestApi.ts b/packages/dappmanager/src/api/startTestApi.ts index 23b40fec4..df766b100 100644 --- a/packages/dappmanager/src/api/startTestApi.ts +++ b/packages/dappmanager/src/api/startTestApi.ts @@ -38,8 +38,8 @@ export function startTestApi(): http.Server { if (callFn.length > 0) { app.post(`/${callCasted}`, (req, res) => { callFn(req.body as never) - .then(data => res.send(data)) - .catch(e => { + .then((data) => res.send(data)) + .catch((e) => { const errorResponse = { name: e.name, message: e.message, @@ -52,8 +52,8 @@ export function startTestApi(): http.Server { } else { app.get(`/${callCasted}`, (req, res) => { callFn(req.query as never) - .then(data => res.send(data)) - .catch(e => { + .then((data) => res.send(data)) + .catch((e) => { const errorResponse = { name: e.name, message: e.message, diff --git a/packages/dappmanager/src/api/subscriptions.ts b/packages/dappmanager/src/api/subscriptions.ts index 9a9767454..dbc893586 100644 --- a/packages/dappmanager/src/api/subscriptions.ts +++ b/packages/dappmanager/src/api/subscriptions.ts @@ -1,11 +1,7 @@ import { EventBus } from "@dappnode/eventbus"; import { Routes, Subscriptions } from "@dappnode/types"; -export function mapSubscriptionsToEventBus( - subscriptions: Subscriptions, - calls: Routes, - eventBus: EventBus -): void { +export function mapSubscriptionsToEventBus(subscriptions: Subscriptions, calls: Routes, eventBus: EventBus): void { // Pipe local events to WAMP eventBus.logUi.on(subscriptions.progressLog.emit); eventBus.logUserAction.on(subscriptions.userActionLog.emit); @@ -35,7 +31,7 @@ export function mapSubscriptionsToEventBus( }); // Push notifications to the UI - eventBus.notification.on(notification => { + eventBus.notification.on((notification) => { subscriptions.pushNotification.emit(notification); }); diff --git a/packages/dappmanager/src/api/utils.ts b/packages/dappmanager/src/api/utils.ts index 52c69d4f2..aaac9133b 100644 --- a/packages/dappmanager/src/api/utils.ts +++ b/packages/dappmanager/src/api/utils.ts @@ -15,13 +15,11 @@ export class HttpError extends Error { * Wrap express routes to be able to safely throw errors and return JSON * @param handler */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any + export function wrapHandler< // eslint-disable-next-line @typescript-eslint/no-explicit-any ReqParams extends { [key: string]: any } = Record<string, any> ->( - handler: express.RequestHandler<ReqParams> -): express.RequestHandler<ReqParams> { +>(handler: express.RequestHandler<ReqParams>): express.RequestHandler<ReqParams> { return async (req, res, next): Promise<void> => { try { await handler(req, res, next); @@ -55,9 +53,7 @@ export function wrapHandler< export function wrapHandlerHtml< // eslint-disable-next-line @typescript-eslint/no-explicit-any ReqParams extends { [key: string]: any } = Record<string, any> ->( - handler: express.RequestHandler<ReqParams> -): express.RequestHandler<ReqParams> { +>(handler: express.RequestHandler<ReqParams>): express.RequestHandler<ReqParams> { return async (req, res, next): Promise<void> => { try { await handler(req, res, next); @@ -67,9 +63,7 @@ export function wrapHandlerHtml< }; } -export function toSocketIoHandler( - expressHandler: express.Handler -): Parameters<Server["use"]>[0] { +export function toSocketIoHandler(expressHandler: express.Handler): Parameters<Server["use"]>[0] { return function (socket, next): void { expressHandler( socket.handshake as unknown as express.Request, diff --git a/packages/dappmanager/src/api/vpnApiClient.ts b/packages/dappmanager/src/api/vpnApiClient.ts index b6b8d621f..3661c710b 100644 --- a/packages/dappmanager/src/api/vpnApiClient.ts +++ b/packages/dappmanager/src/api/vpnApiClient.ts @@ -7,9 +7,7 @@ export interface VpnApiClient { removeDevice: (kwargs: { id: string }) => Promise<void>; resetDevice: (kwargs: { id: string }) => Promise<void>; listDevices: () => Promise<{ id: string }[]>; - getDeviceCredentials: (kwargs: { - id: string; - }) => Promise<{ filename: string; key: string; url: string }>; + getDeviceCredentials: (kwargs: { id: string }) => Promise<{ filename: string; key: string; url: string }>; getVersionData: () => Promise<PackageVersionData>; } @@ -30,7 +28,6 @@ export interface VpnApiClientParams { type Args = any[]; export function getVpnApiClient(params: VpnApiClientParams): VpnApiClient { - // eslint-disable-next-line @typescript-eslint/no-explicit-any return mapValues( vpnApiRoutesData, (_, route) => @@ -45,11 +42,7 @@ export function getVpnApiClient(params: VpnApiClientParams): VpnApiClient { * @param route "addDevice" * @param args [ { id: "name" } ] */ -async function vpnRpcCall<R>( - params: VpnApiClientParams, - route: string, - ...args: Args -): Promise<R> { +async function vpnRpcCall<R>(params: VpnApiClientParams, route: string, ...args: Args): Promise<R> { const res = await fetch(params.VPN_API_RPC_URL, { method: "post", body: JSON.stringify({ method: route, params: args }), @@ -62,9 +55,7 @@ async function vpnRpcCall<R>( try { body = JSON.parse(bodyText); } catch (e) { - throw Error( - `Error parsing JSON body (${res.status} ${res.statusText}): ${e.message}\n${bodyText}` - ); + throw Error(`Error parsing JSON body (${res.status} ${res.statusText}): ${e.message}\n${bodyText}`); } if (!res.ok) { diff --git a/packages/dappmanager/src/calls/autoUpdateDataGet.ts b/packages/dappmanager/src/calls/autoUpdateDataGet.ts index 3868f1ad1..9c915bf1a 100644 --- a/packages/dappmanager/src/calls/autoUpdateDataGet.ts +++ b/packages/dappmanager/src/calls/autoUpdateDataGet.ts @@ -12,12 +12,7 @@ import { } from "@dappnode/types"; import * as db from "@dappnode/db"; import { params } from "@dappnode/params"; -import { - isCoreUpdateEnabled, - SYSTEM_PACKAGES, - MY_PACKAGES, - isDnpUpdateEnabled -} from "@dappnode/daemons"; +import { isCoreUpdateEnabled, SYSTEM_PACKAGES, MY_PACKAGES, isDnpUpdateEnabled } from "@dappnode/daemons"; const coreDnpName = params.coreDnpName; @@ -53,9 +48,7 @@ export async function autoUpdateDataGet(): Promise<AutoUpdateDataView> { if (isDnpUpdateEnabled()) { const singleDnpsToShow: InstalledPackageData[] = []; for (const dnp of dnpList) { - const storedDnp = singleDnpsToShow.find( - _dnp => _dnp.dnpName === dnp.dnpName - ); + const storedDnp = singleDnpsToShow.find((_dnp) => _dnp.dnpName === dnp.dnpName); const storedVersion = storedDnp ? storedDnp.version : ""; if ( dnp.dnpName && @@ -121,17 +114,11 @@ export function getCoreFeedbackMessage( * Let's figure out the version of the core */ - const { - version: pendingVersion, - scheduledUpdate, - errorMessage - } = pending[coreDnpName] || {}; + const { version: pendingVersion, scheduledUpdate, errorMessage } = pending[coreDnpName] || {}; const lastUpdatedVersion = getLastRegistryEntry(registry[coreDnpName] || {}); const lastUpdatedVersionsAreInstalled = - lastUpdatedVersion.version && - isVersionIdUpdated(lastUpdatedVersion.version, currentCorePackages); - const pendingVersionsAreInstalled = - pendingVersion && isVersionIdUpdated(pendingVersion, currentCorePackages); + lastUpdatedVersion.version && isVersionIdUpdated(lastUpdatedVersion.version, currentCorePackages); + const pendingVersionsAreInstalled = pendingVersion && isVersionIdUpdated(pendingVersion, currentCorePackages); if (scheduledUpdate) { // If the pending version is the current BUT it is NOT in the registry, @@ -139,13 +126,11 @@ export function getCoreFeedbackMessage( if (pendingVersionsAreInstalled) return { manuallyUpdated: true }; // Here, an update can be pending - if (Date.now() > scheduledUpdate) - return { inQueue: true, ...(errorMessage ? { errorMessage } : {}) }; + if (Date.now() > scheduledUpdate) return { inQueue: true, ...(errorMessage ? { errorMessage } : {}) }; else return { scheduled: scheduledUpdate }; } else { // If current version is auto-installed, it will show up in the registry - if (lastUpdatedVersionsAreInstalled) - return { updated: lastUpdatedVersion.updated }; + if (lastUpdatedVersionsAreInstalled) return { updated: lastUpdatedVersion.updated }; } return {}; @@ -177,23 +162,15 @@ export function getDnpFeedbackMessage({ if (!registry) registry = db.autoUpdateRegistry.get(); if (!pending) pending = db.autoUpdatePending.get(); - const currentVersionRegistry = - (registry[dnpName] || {})[currentVersion] || {}; - const { - version: pendingVersion, - scheduledUpdate, - errorMessage - } = pending[dnpName] || {}; + const currentVersionRegistry = (registry[dnpName] || {})[currentVersion] || {}; + const { version: pendingVersion, scheduledUpdate, errorMessage } = pending[dnpName] || {}; const lastUpdatedVersion = getLastRegistryEntry(registry[dnpName] || {}); - const lastUpdatedVersionsAreInstalled = - lastUpdatedVersion.version && lastUpdatedVersion.version === currentVersion; - const pendingVersionsAreInstalled = - pendingVersion && pendingVersion === currentVersion; + const lastUpdatedVersionsAreInstalled = lastUpdatedVersion.version && lastUpdatedVersion.version === currentVersion; + const pendingVersionsAreInstalled = pendingVersion && pendingVersion === currentVersion; // If current version is auto-installed, it will show up in the registry - if (lastUpdatedVersionsAreInstalled) - return { updated: currentVersionRegistry.updated }; + if (lastUpdatedVersionsAreInstalled) return { updated: currentVersionRegistry.updated }; // If the pending version is the current BUT it is NOT in the registry, // it must have been updated by the user diff --git a/packages/dappmanager/src/calls/autoUpdateSettingsEdit.ts b/packages/dappmanager/src/calls/autoUpdateSettingsEdit.ts index f460fc99d..c0ded993f 100644 --- a/packages/dappmanager/src/calls/autoUpdateSettingsEdit.ts +++ b/packages/dappmanager/src/calls/autoUpdateSettingsEdit.ts @@ -1,9 +1,4 @@ -import { - editCoreSetting, - MY_PACKAGES, - SYSTEM_PACKAGES, - editDnpSetting -} from "@dappnode/daemons"; +import { editCoreSetting, MY_PACKAGES, SYSTEM_PACKAGES, editDnpSetting } from "@dappnode/daemons"; /** * Edits the auto-update settings @@ -11,15 +6,8 @@ import { * @param id = "my-packages", "system-packages" or "bitcoin.dnp.dappnode.eth" * @param enabled Auto update is enabled for ID */ -export async function autoUpdateSettingsEdit({ - id, - enabled -}: { - id: string; - enabled: boolean; -}): Promise<void> { - if (!id) - throw Error(`Argument id is required or generalSettings must be true`); +export async function autoUpdateSettingsEdit({ id, enabled }: { id: string; enabled: boolean }): Promise<void> { + if (!id) throw Error(`Argument id is required or generalSettings must be true`); if (id === MY_PACKAGES) editDnpSetting(enabled); else if (id === SYSTEM_PACKAGES) editCoreSetting(enabled); diff --git a/packages/dappmanager/src/calls/backupGet.ts b/packages/dappmanager/src/calls/backupGet.ts index c5ea76aea..28772a5bd 100644 --- a/packages/dappmanager/src/calls/backupGet.ts +++ b/packages/dappmanager/src/calls/backupGet.ts @@ -16,13 +16,7 @@ const tempTransferDir = params.TEMP_TRANSFER_DIR; /** * Does a backup of a DNP and sends it to the client for download. */ -export async function backupGet({ - dnpName, - backup -}: { - dnpName: string; - backup: PackageBackup[]; -}): Promise<string> { +export async function backupGet({ dnpName, backup }: { dnpName: string; backup: PackageBackup[] }): Promise<string> { if (!dnpName) throw Error("Argument dnpName must be defined"); if (!backup) throw Error("Argument backup must be defined"); if (!backup.length) throw Error("No backup items specified"); @@ -41,21 +35,15 @@ export async function backupGet({ let lastError: Error | null = null; for (const { name, path: fromPath, service } of backup) { try { - const container = dnp.containers.find( - c => !service || c.serviceName === service - ); - if (!container) - throw Error(`No container found for service ${service}`); + const container = dnp.containers.find((c) => !service || c.serviceName === service); + if (!container) throw Error(`No container found for service ${service}`); const toPath = path.join(backupDir, name); - await shell( - `docker cp ${container.containerName}:${fromPath} ${toPath}` - ); + await shell(`docker cp ${container.containerName}:${fromPath} ${toPath}`); successfulBackups.push(name); } catch (e) { - if (e.message.includes("No such container:path")) - lastError = Error(`path ${fromPath} does not exist`); + if (e.message.includes("No such container:path")) lastError = Error(`path ${fromPath} does not exist`); logs.error("Error getting backup", { dnpName, name, fromPath }, e); } } @@ -82,11 +70,14 @@ export async function backupGet({ db.fileTransferPath.set(fileId, backupDirComp); // DEFER THIS ACTION: Clean intermediate file - setTimeout(() => { - fs.unlink(backupDirComp, errFs => { - if (errFs) logs.error(`Error deleting file: ${errFs.message}`); - }); - }, 15 * 60 * 1000); + setTimeout( + () => { + fs.unlink(backupDirComp, (errFs) => { + if (errFs) logs.error(`Error deleting file: ${errFs.message}`); + }); + }, + 15 * 60 * 1000 + ); return fileId; } catch (e) { diff --git a/packages/dappmanager/src/calls/backupRestore.ts b/packages/dappmanager/src/calls/backupRestore.ts index bba2b54a2..432867faa 100644 --- a/packages/dappmanager/src/calls/backupRestore.ts +++ b/packages/dappmanager/src/calls/backupRestore.ts @@ -43,8 +43,7 @@ export async function backupRestore({ // Fetch the filePath and the file with fileId const filePath = db.fileTransferPath.get(fileId); if (!filePath) throw Error(`No file found for id: ${fileId}`); - if (!fs.existsSync(filePath)) - throw Error(`No file found at path: ${filePath}`); + if (!fs.existsSync(filePath)) throw Error(`No file found at path: ${filePath}`); await shell(`mv ${filePath} ${backupDirCompressed}`); try { @@ -62,17 +61,13 @@ export async function backupRestore({ let lastError: Error | null = null; for (const { name, path: toPath, service } of backup) { try { - const container = dnp.containers.find( - c => !service || c.serviceName === service - ); - if (!container) - throw Error(`No container found for service ${service}`); + const container = dnp.containers.find((c) => !service || c.serviceName === service); + if (!container) throw Error(`No container found for service ${service}`); const containerName = container.containerName; const fromPath = path.join(backupDir, name); // lstatSync throws if path does not exist, so must call existsSync first - if (!fs.existsSync(fromPath)) - throw Error(`path ${fromPath} does not exist`); + if (!fs.existsSync(fromPath)) throw Error(`path ${fromPath} does not exist`); // Make sure the base dir exists on the container (will throw otherwise) const toPathDir = path.parse(toPath).dir; diff --git a/packages/dappmanager/src/calls/changeIpfsTimeout.ts b/packages/dappmanager/src/calls/changeIpfsTimeout.ts index e79f5e4b2..668a17960 100644 --- a/packages/dappmanager/src/calls/changeIpfsTimeout.ts +++ b/packages/dappmanager/src/calls/changeIpfsTimeout.ts @@ -4,11 +4,7 @@ import { params } from "@dappnode/params"; * Used to test different IPFS timeout parameters live from the ADMIN UI. * @param timeout new IPFS timeout in ms */ -export async function changeIpfsTimeout({ - timeout -}: { - timeout?: number; -}): Promise<void> { +export async function changeIpfsTimeout({ timeout }: { timeout?: number }): Promise<void> { if (!timeout) throw Error("kwarg timeout must be defined"); params.IPFS_TIMEOUT = timeout; diff --git a/packages/dappmanager/src/calls/cleanCache.ts b/packages/dappmanager/src/calls/cleanCache.ts index 68df2f288..c33e56918 100644 --- a/packages/dappmanager/src/calls/cleanCache.ts +++ b/packages/dappmanager/src/calls/cleanCache.ts @@ -10,10 +10,7 @@ import { shell } from "@dappnode/utils"; * - temp transfer folder */ export async function cleanCache(): Promise<void> { - const pathsToDelete = [ - params.userActionLogsFilename, - params.TEMP_TRANSFER_DIR - ]; + const pathsToDelete = [params.userActionLogsFilename, params.TEMP_TRANSFER_DIR]; await shell(`rm -rf ${pathsToDelete.join(" ")}`); diff --git a/packages/dappmanager/src/calls/dappnodeWebNameSet.ts b/packages/dappmanager/src/calls/dappnodeWebNameSet.ts index 0854a198b..3911dc6b3 100644 --- a/packages/dappmanager/src/calls/dappnodeWebNameSet.ts +++ b/packages/dappmanager/src/calls/dappnodeWebNameSet.ts @@ -4,10 +4,6 @@ import * as db from "@dappnode/db"; * Sets the dappnodeWebName * @param dappnodeWebName New dappnodeWebName */ -export async function dappnodeWebNameSet({ - dappnodeWebName -}: { - dappnodeWebName: string; -}): Promise<void> { +export async function dappnodeWebNameSet({ dappnodeWebName }: { dappnodeWebName: string }): Promise<void> { db.dappnodeWebName.set(dappnodeWebName); } diff --git a/packages/dappmanager/src/calls/device/index.ts b/packages/dappmanager/src/calls/device/index.ts index 7b865b963..67aa51a04 100644 --- a/packages/dappmanager/src/calls/device/index.ts +++ b/packages/dappmanager/src/calls/device/index.ts @@ -1,13 +1,6 @@ -import { - AdminPasswordDb, - AdminPasswordDbError -} from "../../api/auth/adminPasswordDb.js"; +import { AdminPasswordDb, AdminPasswordDbError } from "../../api/auth/adminPasswordDb.js"; import { VpnApiClient } from "../../api/vpnApiClient.js"; -import { - VpnDeviceCredentials, - VpnDevice, - VpnDeviceAdminPassword -} from "@dappnode/types"; +import { VpnDeviceCredentials, VpnDevice, VpnDeviceAdminPassword } from "@dappnode/types"; // Temporal solution until eventBus is properly typed interface EventBusDevices { @@ -47,13 +40,7 @@ export class DeviceCalls { * Gives/removes admin rights to the provided device id. * @param id Device id name */ - deviceAdminToggle = async ({ - id, - isAdmin - }: { - id: string; - isAdmin: boolean; - }): Promise<void> => { + deviceAdminToggle = async ({ id, isAdmin }: { id: string; isAdmin: boolean }): Promise<void> => { // Set admin status in local DB this.adminPasswordDb.setIsAdmin(id, isAdmin); @@ -66,11 +53,7 @@ export class DeviceCalls { * concatenated with the device id. * @param id Device id name */ - deviceCredentialsGet = async ({ - id - }: { - id: string; - }): Promise<VpnDeviceCredentials> => { + deviceCredentialsGet = async ({ id }: { id: string }): Promise<VpnDeviceCredentials> => { const data = await this.vpnApiClient.getDeviceCredentials({ id }); const device = await this.devicelist(id); @@ -130,7 +113,7 @@ export class DeviceCalls { private devicelist = async (id: string): Promise<VpnDevice> => { const vpnDevices = await this.vpnApiClient.listDevices(); - const device = vpnDevices.find(d => d.id === id); + const device = vpnDevices.find((d) => d.id === id); if (!device) throw Error(`Device ${id} not found`); return this.readDevice(device.id); }; diff --git a/packages/dappmanager/src/calls/dockerUpgrade.ts b/packages/dappmanager/src/calls/dockerUpgrade.ts index 67d02d4ff..f1d2b9853 100644 --- a/packages/dappmanager/src/calls/dockerUpgrade.ts +++ b/packages/dappmanager/src/calls/dockerUpgrade.ts @@ -1,7 +1,4 @@ -import { - dockerUpgradeService, - dockerUpgradeCheck as _dockerUpgradeCheck -} from "@dappnode/hostscriptsservices"; +import { dockerUpgradeService, dockerUpgradeCheck as _dockerUpgradeCheck } from "@dappnode/hostscriptsservices"; import { DockerUpgradeRequirements } from "@dappnode/types"; /** diff --git a/packages/dappmanager/src/calls/ethClientFallbackSet.ts b/packages/dappmanager/src/calls/ethClientFallbackSet.ts index 3a5972ad7..d3d60cb51 100644 --- a/packages/dappmanager/src/calls/ethClientFallbackSet.ts +++ b/packages/dappmanager/src/calls/ethClientFallbackSet.ts @@ -4,10 +4,6 @@ import { EthClientFallback } from "@dappnode/types"; /** * Sets if a fallback should be used */ -export async function ethClientFallbackSet({ - fallback -}: { - fallback: EthClientFallback; -}): Promise<void> { +export async function ethClientFallbackSet({ fallback }: { fallback: EthClientFallback }): Promise<void> { db.ethClientFallback.set(fallback); } diff --git a/packages/dappmanager/src/calls/ethicalMetrics.ts b/packages/dappmanager/src/calls/ethicalMetrics.ts index 28847b148..e1573860c 100644 --- a/packages/dappmanager/src/calls/ethicalMetrics.ts +++ b/packages/dappmanager/src/calls/ethicalMetrics.ts @@ -4,11 +4,7 @@ import { listPackageNoThrow } from "@dappnode/dockerapi"; import * as db from "@dappnode/db"; import { packageInstall } from "./packageInstall.js"; import { logs } from "@dappnode/logger"; -import { - ethicalMetricsDnpName, - register, - unregister -} from "@dappnode/ethicalmetrics"; +import { ethicalMetricsDnpName, register, unregister } from "@dappnode/ethicalmetrics"; import { dockerContainerStart, dockerContainerStop } from "@dappnode/dockerapi"; /** @@ -55,8 +51,7 @@ export async function enableEthicalMetrics({ tgChannelId: string | null; sync: boolean; }): Promise<void> { - if (!mail && !tgChannelId) - throw new Error("You must provide an email or a telegram channel id"); + if (!mail && !tgChannelId) throw new Error("You must provide an email or a telegram channel id"); db.notifications.set({ mail, @@ -74,8 +69,7 @@ export async function enableEthicalMetrics({ } else { // Make sure pkg is running for (const container of ethicalMetricsPkg.containers) - if (!container.running) - await dockerContainerStart(container.containerName); + if (!container.running) await dockerContainerStart(container.containerName); // Make sure the instance is registered await register({ diff --git a/packages/dappmanager/src/calls/fetchCoreUpdateData.ts b/packages/dappmanager/src/calls/fetchCoreUpdateData.ts index 7f9e63813..9f7095162 100644 --- a/packages/dappmanager/src/calls/fetchCoreUpdateData.ts +++ b/packages/dappmanager/src/calls/fetchCoreUpdateData.ts @@ -5,10 +5,6 @@ import { dappnodeInstaller } from "../index.js"; /** * Fetches the core update data, if available */ -export async function fetchCoreUpdateData({ - version -}: { - version?: string; -}): Promise<CoreUpdateData> { +export async function fetchCoreUpdateData({ version }: { version?: string }): Promise<CoreUpdateData> { return await getCoreUpdateData(dappnodeInstaller, version); } diff --git a/packages/dappmanager/src/calls/fetchDirectory.ts b/packages/dappmanager/src/calls/fetchDirectory.ts index 631171b28..c4f81c72d 100644 --- a/packages/dappmanager/src/calls/fetchDirectory.ts +++ b/packages/dappmanager/src/calls/fetchDirectory.ts @@ -2,11 +2,7 @@ import { eventBus } from "@dappnode/eventbus"; import { DirectoryItem, DirectoryItemOk } from "@dappnode/types"; import { logs } from "@dappnode/logger"; import { listPackages } from "@dappnode/dockerapi"; -import { - fileToGatewayUrl, - getIsInstalled, - getIsUpdated -} from "@dappnode/utils"; +import { fileToGatewayUrl, getIsInstalled, getIsUpdated } from "@dappnode/utils"; import { throttle } from "lodash-es"; import { getEthersProvider } from "@dappnode/installer"; import { DappNodeDirectory } from "@dappnode/toolkit"; @@ -18,7 +14,7 @@ const loadThrottle = 500; // 0.5 seconds * Fetches all package names in the custom dappnode directory. */ export async function fetchDirectory(): Promise<DirectoryItem[]> { - const directory = new DappNodeDirectory(await getEthersProvider()) ; + const directory = new DappNodeDirectory(await getEthersProvider()); const installedDnpList = await listPackages(); @@ -81,12 +77,8 @@ export async function fetchDirectory(): Promise<DirectoryItem[]> { /** * Get a short description and trim it */ -export function getShortDescription(metadata: { - description?: string; - shortDescription?: string; -}): string { - const desc = - metadata.shortDescription || metadata.description || "No description"; +export function getShortDescription(metadata: { description?: string; shortDescription?: string }): string { + const desc = metadata.shortDescription || metadata.description || "No description"; // Don't send big descriptions, the UI crops them anyway return desc.slice(0, 80); } @@ -98,10 +90,7 @@ const fallbackCategories: { [dnpName: string]: string[] } = { "vipnode.dnp.dappnode.eth": ["Economic incentive"], "ropsten.dnp.dappnode.eth": ["Developer tools"], "rinkeby.dnp.dappnode.eth": ["Developer tools"], - "lightning-network.dnp.dappnode.eth": [ - "Payment channels", - "Economic incentive" - ], + "lightning-network.dnp.dappnode.eth": ["Payment channels", "Economic incentive"], "swarm.dnp.dappnode.eth": ["Storage", "Communications"], "goerli-geth.dnp.dappnode.eth": ["Developer tools"], "bitcoin.dnp.dappnode.eth": ["Blockchain"], @@ -168,8 +157,7 @@ const stakeHouseCard: DirectoryItemOk = { whitelisted: true, isFeatured: true, status: "ok", - description: - "Join or create an LSD Network and stake a validator with 4 ETH.", + description: "Join or create an LSD Network and stake a validator with 4 ETH.", avatarUrl: fileToGatewayUrl({ hash: "QmPZ7KYwjXEXDjEj5A2iXbQ2oj9bMWKgBNJBRgUxGNCjmw", source: "ipfs", diff --git a/packages/dappmanager/src/calls/fetchDnpRequest.ts b/packages/dappmanager/src/calls/fetchDnpRequest.ts index cfa286968..e2fc356d8 100644 --- a/packages/dappmanager/src/calls/fetchDnpRequest.ts +++ b/packages/dappmanager/src/calls/fetchDnpRequest.ts @@ -2,22 +2,10 @@ import { mapValues, omit } from "lodash-es"; import { valid, gt } from "semver"; import { params } from "@dappnode/params"; import deepmerge from "deepmerge"; -import { - fileToGatewayUrl, - getIsUpdated, - getIsInstalled -} from "@dappnode/utils"; +import { fileToGatewayUrl, getIsUpdated, getIsInstalled } from "@dappnode/utils"; import { dappnodeInstaller } from "../index.js"; -import { - dockerInfoArchive, - listPackages, - getDockerVersion -} from "@dappnode/dockerapi"; -import { - ComposeEditor, - ComposeFileEditor, - parseSpecialPermissions -} from "@dappnode/dockercompose"; +import { dockerInfoArchive, listPackages, getDockerVersion } from "@dappnode/dockerapi"; +import { ComposeEditor, ComposeFileEditor, parseSpecialPermissions } from "@dappnode/dockercompose"; import { RequestedDnp, UserSettingsAllDnps, @@ -29,12 +17,9 @@ import { ReleaseSignatureStatusCode } from "@dappnode/types"; import { Manifest, SetupWizardField } from "@dappnode/types"; +import { logs } from "@dappnode/logger"; -export async function fetchDnpRequest({ - id -}: { - id: string; -}): Promise<RequestedDnp> { +export async function fetchDnpRequest({ id }: { id: string }): Promise<RequestedDnp> { const mainRelease = await dappnodeInstaller.getRelease(id); const settings: UserSettingsAllDnps = {}; @@ -47,13 +32,10 @@ export async function fetchDnpRequest({ async function addReleaseToSettings(release: PackageRelease): Promise<void> { const { dnpName, compose, isCore } = release; - const dnp = dnpList.find(d => d.dnpName === dnpName); + const dnp = dnpList.find((d) => d.dnpName === dnpName); const defaultUserSet = new ComposeEditor(compose).getUserSettings(); - const prevUserSet = ComposeFileEditor.getUserSettingsIfExist( - dnpName, - isCore - ); + const prevUserSet = ComposeFileEditor.getUserSettingsIfExist(dnpName, isCore); settings[dnpName] = deepmerge(defaultUserSet, prevUserSet); specialPermissions[dnpName] = parseSpecialPermissions(compose, isCore); @@ -61,8 +43,7 @@ export async function fetchDnpRequest({ if (release.setupWizard) { const activeSetupWizardFields: SetupWizardField[] = []; for (const field of release.setupWizard.fields) { - if (await shouldAddSetupWizardField(field, dnp)) - activeSetupWizardFields.push(field); + if (await shouldAddSetupWizardField(field, dnp)) activeSetupWizardFields.push(field); } setupWizard[dnpName] = { ...release.setupWizard, @@ -84,11 +65,10 @@ export async function fetchDnpRequest({ let compatibleDnps: CompatibleDnps = {}; try { const { dnpName, reqVersion } = mainRelease; - const { state, currentVersions, releases } = - await dappnodeInstaller.getReleasesResolved({ - name: dnpName, - ver: reqVersion - }); + const { state, currentVersions, releases } = await dappnodeInstaller.getReleasesResolved({ + name: dnpName, + ver: reqVersion + }); compatibleDnps = mapValues(state, (nextVersion, dnpName) => ({ from: currentVersions[dnpName], to: nextVersion @@ -137,45 +117,25 @@ export async function fetchDnpRequest({ }, signedSafe, - signedSafeAll: Object.values(signedSafe).every(r => r.safe === true) + signedSafeAll: Object.values(signedSafe).every((r) => r.safe === true) }; } -async function getRequiresUninstallPackages({ - manifest -}: { - manifest: Manifest; -}): Promise<string[]> { +async function getRequiresUninstallPackages({ manifest }: { manifest: Manifest }): Promise<string[]> { const { notInstalledPackages } = manifest.requirements || {}; if (!notInstalledPackages || notInstalledPackages.length === 0) return []; const installedPackages = await listPackages(); - return notInstalledPackages.filter(dnpName => - installedPackages.find(dnp => dnp.dnpName === dnpName) - ); + return notInstalledPackages.filter((dnpName) => installedPackages.find((dnp) => dnp.dnpName === dnpName)); } -function getRequiresCoreUpdate( - { manifest }: { manifest: Manifest }, - dnpList: InstalledPackageData[] -): boolean { - const coreDnp = dnpList.find(dnp => dnp.dnpName === params.coreDnpName); +function getRequiresCoreUpdate({ manifest }: { manifest: Manifest }, dnpList: InstalledPackageData[]): boolean { + const coreDnp = dnpList.find((dnp) => dnp.dnpName === params.coreDnpName); if (!coreDnp) return false; const coreVersion = coreDnp.version; - const minDnVersion = manifest.requirements - ? manifest.requirements.minimumDappnodeVersion - : ""; - return Boolean( - minDnVersion && - valid(minDnVersion) && - valid(coreVersion) && - gt(minDnVersion, coreVersion) - ); + const minDnVersion = manifest.requirements ? manifest.requirements.minimumDappnodeVersion : ""; + return Boolean(minDnVersion && valid(minDnVersion) && valid(coreVersion) && gt(minDnVersion, coreVersion)); } -async function getRequiresDockerUpdate({ - manifest -}: { - manifest: Manifest; -}): Promise<boolean> { +async function getRequiresDockerUpdate({ manifest }: { manifest: Manifest }): Promise<boolean> { const minDockerVersion = manifest.requirements?.minimumDockerVersion; if (!minDockerVersion) return false; const currentDockerVersion = await getDockerVersion(); @@ -206,19 +166,15 @@ async function shouldAddSetupWizardField( if (dnp) { const serviceName = field.target.service; // Find the container referenced by the target or the first one if unspecified - const container = dnp.containers.find( - c => !serviceName || c.serviceName === serviceName - ); + const container = dnp.containers.find((c) => !serviceName || c.serviceName === serviceName); if (container) try { - const fileInfo = await dockerInfoArchive( - container.containerId, - field.target.path - ); + const fileInfo = await dockerInfoArchive(container.containerId, field.target.path); return !fileInfo.size; } catch (e) { // Ignore all errors: 404 Container not found, // 404 path not found, Base64 parsing, JSON parsing, etc. + logs.error(`Error fetching file info for ${dnp.dnpName} ${serviceName} ${field.target.path}`, e); } } return true; @@ -250,9 +206,6 @@ function getReleaseSignedSafeMessage(release: PackageRelease): string { } } -function getInstalledVersion( - { dnpName }: { dnpName: string }, - dnpList: InstalledPackageData[] -): string | undefined { - return dnpList.find(dnp => dnp.dnpName === dnpName)?.version; +function getInstalledVersion({ dnpName }: { dnpName: string }, dnpList: InstalledPackageData[]): string | undefined { + return dnpList.find((dnp) => dnp.dnpName === dnpName)?.version; } diff --git a/packages/dappmanager/src/calls/fetchRegistry.ts b/packages/dappmanager/src/calls/fetchRegistry.ts index 25792f400..9f6e27fae 100644 --- a/packages/dappmanager/src/calls/fetchRegistry.ts +++ b/packages/dappmanager/src/calls/fetchRegistry.ts @@ -1,15 +1,8 @@ import { listPackages } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { DirectoryItem } from "@dappnode/types"; -import { - fileToGatewayUrl, - getIsInstalled, - getIsUpdated -} from "@dappnode/utils"; -import { - getShortDescription, - getFallBackCategories -} from "./fetchDirectory.js"; +import { fileToGatewayUrl, getIsInstalled, getIsUpdated } from "@dappnode/utils"; +import { getShortDescription, getFallBackCategories } from "./fetchDirectory.js"; import { throttle } from "lodash-es"; import { PublicRegistryEntry } from "@dappnode/toolkit"; import { dappnodeInstaller, publicRegistry } from "../index.js"; @@ -30,9 +23,7 @@ export async function fetchRegistry(): Promise<DirectoryItem[]> { /** * Get IPFS data from registry packages */ -async function fetchRegistryIpfsData( - registry: PublicRegistryEntry[] -): Promise<DirectoryItem[]> { +async function fetchRegistryIpfsData(registry: PublicRegistryEntry[]): Promise<DirectoryItem[]> { const dnpList = await listPackages(); const registryPublicDnps: DirectoryItem[] = []; diff --git a/packages/dappmanager/src/calls/getCoreVersion.ts b/packages/dappmanager/src/calls/getCoreVersion.ts index a1a0630c8..7d6f4cfe9 100644 --- a/packages/dappmanager/src/calls/getCoreVersion.ts +++ b/packages/dappmanager/src/calls/getCoreVersion.ts @@ -8,7 +8,7 @@ const coreName = params.coreDnpName; */ export async function getCoreVersion(): Promise<string> { const dnpList = await listPackages(); - const coreDnp = dnpList.find(_dnp => _dnp.dnpName === coreName); + const coreDnp = dnpList.find((_dnp) => _dnp.dnpName === coreName); return coreDnp ? coreDnp.version : ""; } diff --git a/packages/dappmanager/src/calls/getUserActionLogs.ts b/packages/dappmanager/src/calls/getUserActionLogs.ts index 68df18d14..7797de420 100644 --- a/packages/dappmanager/src/calls/getUserActionLogs.ts +++ b/packages/dappmanager/src/calls/getUserActionLogs.ts @@ -8,10 +8,7 @@ import { UserActionLog } from "@dappnode/types"; * @param first for pagination * @param after for pagination */ -export async function getUserActionLogs({ - first = 50, - after = 0 -}): Promise<UserActionLog[]> { +export async function getUserActionLogs({ first = 50, after = 0 }): Promise<UserActionLog[]> { return collapseEqualLogs(logUserAction.get().slice(after, after + first)); } diff --git a/packages/dappmanager/src/calls/httpsPortal.ts b/packages/dappmanager/src/calls/httpsPortal.ts index ea3ee09ad..1d69e000f 100644 --- a/packages/dappmanager/src/calls/httpsPortal.ts +++ b/packages/dappmanager/src/calls/httpsPortal.ts @@ -4,22 +4,14 @@ import { httpsPortal, getExposableServices } from "@dappnode/httpsportal"; /** * HTTPs Portal: map a subdomain */ -export async function httpsPortalMappingAdd({ - mapping -}: { - mapping: HttpsPortalMapping; -}): Promise<void> { +export async function httpsPortalMappingAdd({ mapping }: { mapping: HttpsPortalMapping }): Promise<void> { await httpsPortal.addMapping(mapping); } /** * HTTPs Portal: remove an existing mapping */ -export async function httpsPortalMappingRemove({ - mapping -}: { - mapping: HttpsPortalMapping; -}): Promise<void> { +export async function httpsPortalMappingRemove({ mapping }: { mapping: HttpsPortalMapping }): Promise<void> { await httpsPortal.removeMapping(mapping); } @@ -45,16 +37,12 @@ export async function httpsPortalMappingsGet(): Promise<HttpsPortalMapping[]> { /** * HTTPs Portal: get exposable services with metadata */ -export async function httpsPortalExposableServicesGet(): Promise< - ExposableServiceMapping[] -> { +export async function httpsPortalExposableServicesGet(): Promise<ExposableServiceMapping[]> { const mappingsInfo = await getExposableServices(); const mappings = await httpsPortal.getMappings(); - const mappingsById = new Map( - mappings.map(mapping => [getServiceId(mapping), mapping]) - ); + const mappingsById = new Map(mappings.map((mapping) => [getServiceId(mapping), mapping])); - return mappingsInfo.map(mappingInfo => { + return mappingsInfo.map((mappingInfo) => { const exposedMapping = mappingsById.get(getServiceId(mappingInfo)); if (exposedMapping) { return { ...mappingInfo, ...exposedMapping, exposed: true }; // override .fromSubdomain potentially @@ -65,8 +53,6 @@ export async function httpsPortalExposableServicesGet(): Promise< } /** Helper to uniquely identify mapping target services */ -function getServiceId( - mapping: Omit<HttpsPortalMapping, "fromSubdomain"> -): string { +function getServiceId(mapping: Omit<HttpsPortalMapping, "fromSubdomain">): string { return `${mapping.dnpName}/${mapping.serviceName}/${mapping.port}`; } diff --git a/packages/dappmanager/src/calls/index.ts b/packages/dappmanager/src/calls/index.ts index 8fcf4a051..a61851ced 100644 --- a/packages/dappmanager/src/calls/index.ts +++ b/packages/dappmanager/src/calls/index.ts @@ -13,11 +13,7 @@ export { dockerUpgradeCheck, dockerUpgrade } from "./dockerUpgrade.js"; export { dappnodeWebNameSet } from "./dappnodeWebNameSet.js"; export { ethClientTargetSet } from "./ethClientTargetSet.js"; export { ethClientFallbackSet } from "./ethClientFallbackSet.js"; -export { - disableEthicalMetrics, - enableEthicalMetrics, - getEthicalMetricsConfig -} from "./ethicalMetrics.js"; +export { disableEthicalMetrics, enableEthicalMetrics, getEthicalMetricsConfig } from "./ethicalMetrics.js"; export { fetchCoreUpdateData } from "./fetchCoreUpdateData.js"; export { fetchDirectory } from "./fetchDirectory.js"; export { fetchDnpRequest } from "./fetchDnpRequest.js"; @@ -62,21 +58,11 @@ export * from "./releaseTrustedKey.js"; export { setStaticIp } from "./setStaticIp.js"; export { getShouldShowSmooth, setShouldShownSmooth } from "./smooth.js"; export { statsCpuGet } from "./statsCpuGet.js"; -export { - sshPortGet, - sshPortSet, - sshStatusGet, - sshStatusSet -} from "./sshManager.js"; +export { sshPortGet, sshPortSet, sshStatusGet, sshStatusSet } from "./sshManager.js"; export { statsMemoryGet } from "./statsMemoryGet.js"; export { statsDiskGet } from "./statsDiskGet.js"; export { systemInfoGet } from "./systemInfoGet.js"; -export { - telegramConfigGet, - telegramConfigSet, - telegramStatusGet, - telegramStatusSet -} from "./telegram.js"; +export { telegramConfigGet, telegramConfigSet, telegramStatusGet, telegramStatusSet } from "./telegram.js"; export { updateUpgrade } from "./updateUpgrade.js"; export { natRenewalIsEnabled, natRenewalEnable } from "./natRenewal.js"; export { volumeRemove } from "./volumeRemove.js"; diff --git a/packages/dappmanager/src/calls/ipfsClientTargetSet.ts b/packages/dappmanager/src/calls/ipfsClientTargetSet.ts index eb320d950..b292d449a 100644 --- a/packages/dappmanager/src/calls/ipfsClientTargetSet.ts +++ b/packages/dappmanager/src/calls/ipfsClientTargetSet.ts @@ -6,18 +6,10 @@ import { dappnodeInstaller } from "../index.js"; /** * Changes the IPFS client */ -export async function ipfsClientTargetSet({ - ipfsRepository -}: { - ipfsRepository: IpfsRepository; -}): Promise<void> { - if (!ipfsRepository.ipfsClientTarget) - throw Error(`Argument target must be defined`); +export async function ipfsClientTargetSet({ ipfsRepository }: { ipfsRepository: IpfsRepository }): Promise<void> { + if (!ipfsRepository.ipfsClientTarget) throw Error(`Argument target must be defined`); - await changeIpfsClient( - ipfsRepository.ipfsClientTarget, - ipfsRepository.ipfsGateway - ); + await changeIpfsClient(ipfsRepository.ipfsClientTarget, ipfsRepository.ipfsGateway); } /** @@ -27,10 +19,7 @@ export async function ipfsClientTargetSet({ * @param nextTarget "local" | "remote" * @param nextGateway Gateway endpoint to be used by remote node. By default dappnode gateway */ -async function changeIpfsClient( - nextTarget: IpfsClientTarget, - nextGateway?: string -): Promise<void> { +async function changeIpfsClient(nextTarget: IpfsClientTarget, nextGateway?: string): Promise<void> { try { // Return if targets and gateways are equal const currentTarget = db.ipfsClientTarget.get(); diff --git a/packages/dappmanager/src/calls/ipfsTest.ts b/packages/dappmanager/src/calls/ipfsTest.ts index cdfc431ae..f2a8bfa6f 100644 --- a/packages/dappmanager/src/calls/ipfsTest.ts +++ b/packages/dappmanager/src/calls/ipfsTest.ts @@ -1,5 +1,5 @@ import retry from "async-retry"; -import { dappnodeInstaller } from "../index.js" +import { dappnodeInstaller } from "../index.js"; /** Well-known hash that should always be available */ const hash = "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB"; @@ -13,8 +13,7 @@ export async function ipfsTest(): Promise<void> { async () => { try { const file = await dappnodeInstaller.writeFileToMemory(hash); - if (!file.includes(expectedString)) - throw Error("Resolved file does not include expected string"); + if (!file.includes(expectedString)) throw Error("Resolved file does not include expected string"); } catch (e) { e.message = `Error verifying IPFS: ${e.message}`; throw e; diff --git a/packages/dappmanager/src/calls/localProxy.ts b/packages/dappmanager/src/calls/localProxy.ts index fb47b438a..bd3dad91d 100644 --- a/packages/dappmanager/src/calls/localProxy.ts +++ b/packages/dappmanager/src/calls/localProxy.ts @@ -1,9 +1,5 @@ import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - stopAvahiDaemon, - startAvahiDaemon, - getAvahiDaemonStatus -} from "@dappnode/hostscriptsservices"; +import { stopAvahiDaemon, startAvahiDaemon, getAvahiDaemonStatus } from "@dappnode/hostscriptsservices"; import { params } from "@dappnode/params"; import { AvahiDaemonStatus, LocalProxyingStatus } from "@dappnode/types"; import { packageSetEnvironment } from "./packageSetEnvironment.js"; @@ -16,9 +12,7 @@ import { listPackageNoThrow } from "@dappnode/dockerapi"; * - Stop exposing the port 80 to the local network * - Stop broadcasting .local domains to mDNS */ -export async function localProxyingEnableDisable( - enable: boolean -): Promise<void> { +export async function localProxyingEnableDisable(enable: boolean): Promise<void> { await packageSetEnvironment({ dnpName: params.HTTPS_PORTAL_DNPNAME, environmentByService: { @@ -26,7 +20,7 @@ export async function localProxyingEnableDisable( [params.HTTPS_PORTAL_LOCAL_PROXYING_ENVNAME]: enable ? "true" : "false" } } - }).catch(e => { + }).catch((e) => { e.message = `Error setting LOCAL_PROXYING: ${e.message}`; throw e; }); @@ -34,12 +28,12 @@ export async function localProxyingEnableDisable( // TODO: Stop exposing port 80 if (enable) { - await startAvahiDaemon().catch(e => { + await startAvahiDaemon().catch((e) => { e.message = `Error starting avahi daemon: ${e.message}`; throw e; }); } else { - await stopAvahiDaemon().catch(e => { + await stopAvahiDaemon().catch((e) => { e.message = `Error stopping avahi daemon: ${e.message}`; throw e; }); @@ -68,15 +62,13 @@ export async function localProxyingStatusGet(): Promise<LocalProxyingStatus> { ); const LOCAL_PROXYING = - userSettings.environment?.[params.HTTPS_PORTAL_MAIN_SERVICE]?.[ - params.HTTPS_PORTAL_LOCAL_PROXYING_ENVNAME - ]; + userSettings.environment?.[params.HTTPS_PORTAL_MAIN_SERVICE]?.[params.HTTPS_PORTAL_LOCAL_PROXYING_ENVNAME]; // https://github.com/dappnode/DNP_HTTPS/blob/2a52450061eb3b0c4bc321e9b75547661cba1017/fs_overlay/var/lib/nginx-conf/nginx.conf.erb#L115 // if ENV['LOCAL_PROXYING'].downcase == 'true' const localProxyingEnabled = String(LOCAL_PROXYING).toLowerCase() === "true"; - const avahiDaemonStatus = await getAvahiDaemonStatus().catch(e => { + const avahiDaemonStatus = await getAvahiDaemonStatus().catch((e) => { e.message = `Error getting avahi daemon status: ${e.message}`; throw e; }); @@ -85,23 +77,10 @@ export async function localProxyingStatusGet(): Promise<LocalProxyingStatus> { } // Utils -function parseLocalProxyingStatus( - avahiStatus: AvahiDaemonStatus, - localProxyingEnabled: boolean -): LocalProxyingStatus { - if ( - avahiStatus.avahiResolves && - avahiStatus.isAvahiEnabled && - avahiStatus.isAvahiRunning && - localProxyingEnabled - ) +function parseLocalProxyingStatus(avahiStatus: AvahiDaemonStatus, localProxyingEnabled: boolean): LocalProxyingStatus { + if (avahiStatus.avahiResolves && avahiStatus.isAvahiEnabled && avahiStatus.isAvahiRunning && localProxyingEnabled) return "running"; - if ( - !avahiStatus.avahiResolves && - !avahiStatus.isAvahiEnabled && - !avahiStatus.isAvahiRunning && - !localProxyingEnabled - ) + if (!avahiStatus.avahiResolves && !avahiStatus.isAvahiEnabled && !avahiStatus.isAvahiRunning && !localProxyingEnabled) return "stopped"; return "crashed"; } diff --git a/packages/dappmanager/src/calls/manageLvm.ts b/packages/dappmanager/src/calls/manageLvm.ts index f198e7016..1f09a1f4f 100644 --- a/packages/dappmanager/src/calls/manageLvm.ts +++ b/packages/dappmanager/src/calls/manageLvm.ts @@ -4,11 +4,7 @@ import { getHostLogicalVolumes, extendHostDiskSpace } from "@dappnode/hostscriptsservices"; -import { - HostHardDisk, - HostVolumeGroup, - HostLogicalVolume -} from "@dappnode/types"; +import { HostHardDisk, HostVolumeGroup, HostLogicalVolume } from "@dappnode/types"; export async function lvmhardDisksGet(): Promise<HostHardDisk[]> { return await getHostHardDisks(); diff --git a/packages/dappmanager/src/calls/natRenewal.ts b/packages/dappmanager/src/calls/natRenewal.ts index ef426f437..d7ce5bf65 100644 --- a/packages/dappmanager/src/calls/natRenewal.ts +++ b/packages/dappmanager/src/calls/natRenewal.ts @@ -1,11 +1,7 @@ import { throttledNatRenewal } from "@dappnode/daemons"; import * as db from "@dappnode/db"; -export async function natRenewalEnable({ - enableNatRenewal -}: { - enableNatRenewal: boolean; -}): Promise<void> { +export async function natRenewalEnable({ enableNatRenewal }: { enableNatRenewal: boolean }): Promise<void> { db.isNatRenewalDisabled.set(!enableNatRenewal); throttledNatRenewal(); diff --git a/packages/dappmanager/src/calls/notificationsRemove.ts b/packages/dappmanager/src/calls/notificationsRemove.ts index 8b78ba7c8..5b2fe17ed 100644 --- a/packages/dappmanager/src/calls/notificationsRemove.ts +++ b/packages/dappmanager/src/calls/notificationsRemove.ts @@ -6,11 +6,7 @@ import * as db from "@dappnode/db"; * @param ids Array of ids to be marked as read * ids = [ "notification-id1", "notification-id2" ] */ -export async function notificationsRemove({ - ids -}: { - ids: string[]; -}): Promise<void> { +export async function notificationsRemove({ ids }: { ids: string[] }): Promise<void> { if (!ids) throw Error("kwarg ids must be defined"); for (const id of ids) db.notification.remove(id); diff --git a/packages/dappmanager/src/calls/notificationsTest.ts b/packages/dappmanager/src/calls/notificationsTest.ts index 70ffcde9d..5275ae58a 100644 --- a/packages/dappmanager/src/calls/notificationsTest.ts +++ b/packages/dappmanager/src/calls/notificationsTest.ts @@ -12,11 +12,7 @@ import { PackageNotification, NotificationType } from "@dappnode/types"; * body: "Some text about notification" {string} * } */ -export async function notificationsTest({ - notification -}: { - notification?: PackageNotification; -}): Promise<void> { +export async function notificationsTest({ notification }: { notification?: PackageNotification }): Promise<void> { if (!notification) { notification = { id: String(Math.random()).slice(2), diff --git a/packages/dappmanager/src/calls/optimismConfig.ts b/packages/dappmanager/src/calls/optimismConfig.ts index 3db1b9d8f..b8d52ca63 100644 --- a/packages/dappmanager/src/calls/optimismConfig.ts +++ b/packages/dappmanager/src/calls/optimismConfig.ts @@ -15,11 +15,7 @@ import { dappnodeInstaller } from "../index.js"; * @param enableHistorical this enables the historical transactions on the Optimism network * @param targetOpExecutionClient this is the client that will be used to connect to the Optimism network */ -export async function optimismConfigSet({ - archive, - executionClient, - rollup -}: OptimismConfigSet): Promise<void> { +export async function optimismConfigSet({ archive, executionClient, rollup }: OptimismConfigSet): Promise<void> { await setOptimismConfig(dappnodeInstaller, { archive, executionClient, diff --git a/packages/dappmanager/src/calls/packageGet.ts b/packages/dappmanager/src/calls/packageGet.ts index 5891109c3..b068eee03 100644 --- a/packages/dappmanager/src/calls/packageGet.ts +++ b/packages/dappmanager/src/calls/packageGet.ts @@ -4,10 +4,6 @@ import { packageGet as _packageGet } from "@dappnode/installer"; /** * Get package detail information */ -export async function packageGet({ - dnpName -}: { - dnpName: string; -}): Promise<InstalledPackageDetailData> { +export async function packageGet({ dnpName }: { dnpName: string }): Promise<InstalledPackageDetailData> { return await _packageGet({ dnpName }); } diff --git a/packages/dappmanager/src/calls/packageRestart.ts b/packages/dappmanager/src/calls/packageRestart.ts index 9d7672462..7d84d67f6 100644 --- a/packages/dappmanager/src/calls/packageRestart.ts +++ b/packages/dappmanager/src/calls/packageRestart.ts @@ -26,14 +26,11 @@ export async function packageRestart({ // DAPPMANAGER patch if (dnp.dnpName === params.dappmanagerDnpName) { const composePath = getDockerComposePathSmart(dnpName); - if (!fs.existsSync(composePath)) - throw Error(`No docker-compose found for ${dnpName} at ${composePath}`); + if (!fs.existsSync(composePath)) throw Error(`No docker-compose found for ${dnpName} at ${composePath}`); return await restartDappmanagerPatch({ composePath }); } - const targetContainers = dnp.containers.filter( - c => !serviceNames || serviceNames.includes(c.serviceName) - ); + const targetContainers = dnp.containers.filter((c) => !serviceNames || serviceNames.includes(c.serviceName)); if (targetContainers.length === 0) { const queryId = [dnpName, ...(serviceNames || [])].join(", "); @@ -44,13 +41,13 @@ export async function packageRestart({ if (servicesSharingPid) { // First restart targetPid services (Process MUST exist) - const targetContainersPid = dnp.containers.filter(c => + const targetContainersPid = dnp.containers.filter((c) => servicesSharingPid.targetPidServices.includes(c.serviceName) ); await containersRestart(targetContainersPid); // Second restart dependandtPidServices (Process exists) - const dependantContainersPid = dnp.containers.filter(c => + const dependantContainersPid = dnp.containers.filter((c) => servicesSharingPid.dependantPidServices.includes(c.serviceName) ); await containersRestart(dependantContainersPid); @@ -65,12 +62,8 @@ export async function packageRestart({ // Utils -async function containersRestart( - targetContainers: PackageContainer[] -): Promise<void> { +async function containersRestart(targetContainers: PackageContainer[]): Promise<void> { await Promise.all( - targetContainers.map(async c => - dockerContainerRestart(c.containerName, { timeout: c.dockerTimeout }) - ) + targetContainers.map(async (c) => dockerContainerRestart(c.containerName, { timeout: c.dockerTimeout })) ); } diff --git a/packages/dappmanager/src/calls/packageRestartVolumes.ts b/packages/dappmanager/src/calls/packageRestartVolumes.ts index d0559e4b9..c2dc9caed 100644 --- a/packages/dappmanager/src/calls/packageRestartVolumes.ts +++ b/packages/dappmanager/src/calls/packageRestartVolumes.ts @@ -13,11 +13,7 @@ import { listPackage } from "@dappnode/dockerapi"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - ethicalMetricsDnpName, - ethicalMetricsTorServiceVolume, - unregister -} from "@dappnode/ethicalmetrics"; +import { ethicalMetricsDnpName, ethicalMetricsTorServiceVolume, unregister } from "@dappnode/ethicalmetrics"; import { getDockerComposePath, packageInstalledHasPid } from "@dappnode/utils"; import { restartDappmanagerPatch } from "@dappnode/installer"; @@ -36,8 +32,7 @@ export async function packageRestartVolumes({ }): Promise<void> { if (!dnpName) throw Error("kwarg dnpName must be defined"); - if (dnpName === params.dappmanagerDnpName) - throw Error("The dappmanager cannot be restarted"); + if (dnpName === params.dappmanagerDnpName) throw Error("The dappmanager cannot be restarted"); // Needs the extended info that includes the volume ownership data // Fetching all containers to not re-fetch below @@ -47,11 +42,9 @@ export async function packageRestartVolumes({ // Make sure the compose exists before deleting it's containers const composePath = getDockerComposePath(dnp.dnpName, dnp.isCore); - if (!fs.existsSync(composePath)) - throw Error(`No compose found for ${dnp.dnpName}: ${composePath}`); + if (!fs.existsSync(composePath)) throw Error(`No compose found for ${dnp.dnpName}: ${composePath}`); - const { volumesToRemove, containersToRemove } = - getContainersAndVolumesToRemove(dnp, volumeName, volumes); + const { volumesToRemove, containersToRemove } = getContainersAndVolumesToRemove(dnp, volumeName, volumes); logs.debug({ dnpName, volumesToRemove, containersToRemove }); // Skip early to prevent calling dockerComposeUp @@ -60,10 +53,7 @@ export async function packageRestartVolumes({ } // The Ethical Metrics instance must be unregistered if the tor hidden service volume is removed - if ( - (dnp.dnpName === ethicalMetricsDnpName && !volumeName) || - volumeName === ethicalMetricsTorServiceVolume - ) { + if ((dnp.dnpName === ethicalMetricsDnpName && !volumeName) || volumeName === ethicalMetricsTorServiceVolume) { try { await unregister(); } catch (e) { diff --git a/packages/dappmanager/src/calls/packageSentDataDelete.ts b/packages/dappmanager/src/calls/packageSentDataDelete.ts index d5d8f5500..830f3e1b7 100644 --- a/packages/dappmanager/src/calls/packageSentDataDelete.ts +++ b/packages/dappmanager/src/calls/packageSentDataDelete.ts @@ -4,13 +4,7 @@ import { eventBus } from "@dappnode/eventbus"; /** * Delete package sent data key */ -export async function packageSentDataDelete({ - dnpName, - key -}: { - dnpName: string; - key?: string; -}): Promise<void> { +export async function packageSentDataDelete({ dnpName, key }: { dnpName: string; key?: string }): Promise<void> { let packageData = db.packageSentData.get(dnpName); if (!packageData) { diff --git a/packages/dappmanager/src/calls/packageSetPortMappings.ts b/packages/dappmanager/src/calls/packageSetPortMappings.ts index 74b307c94..c0abdc350 100644 --- a/packages/dappmanager/src/calls/packageSetPortMappings.ts +++ b/packages/dappmanager/src/calls/packageSetPortMappings.ts @@ -3,11 +3,7 @@ import { params } from "@dappnode/params"; import { ComposeFileEditor } from "@dappnode/dockercompose"; import { PortMapping } from "@dappnode/types"; import { mapValues } from "lodash-es"; -import { - getContainersStatus, - dockerComposeUpPackage, - listPackage -} from "@dappnode/dockerapi"; +import { getContainersStatus, dockerComposeUpPackage, listPackage } from "@dappnode/dockerapi"; import { packageInstalledHasPid } from "@dappnode/utils"; /** @@ -23,23 +19,17 @@ export async function packageSetPortMappings({ options?: { merge: boolean }; }): Promise<void> { if (!dnpName) throw Error("kwarg id must be defined"); - if (!portMappingsByService) - throw Error("kwarg portMappingsByService must be defined"); + if (!portMappingsByService) throw Error("kwarg portMappingsByService must be defined"); - if (dnpName === params.dappmanagerDnpName) - throw Error("Can not edit DAPPMANAGER ports"); + if (dnpName === params.dappmanagerDnpName) throw Error("Can not edit DAPPMANAGER ports"); const dnp = await listPackage({ dnpName }); const compose = new ComposeFileEditor(dnp.dnpName, dnp.isCore); const services = compose.services(); - const previousPortMappings = mapValues(services, service => - service.getPortMappings() - ); + const previousPortMappings = mapValues(services, (service) => service.getPortMappings()); - for (const [serviceName, portMappings] of Object.entries( - portMappingsByService - )) { + for (const [serviceName, portMappings] of Object.entries(portMappingsByService)) { const service = services[serviceName]; if (!service) throw Error(`No service ${serviceName} in dnp ${dnpName}`); if (options && options.merge) service.mergePortMapping(portMappings); @@ -50,45 +40,27 @@ export async function packageSetPortMappings({ const containersStatus = await getContainersStatus({ dnpName }); - const dockerComposeUpOptions = - (packageInstalledHasPid(compose.compose) && { forceRecreate: true }) || {}; + const dockerComposeUpOptions = (packageInstalledHasPid(compose.compose) && { forceRecreate: true }) || {}; try { - await dockerComposeUpPackage( - { dnpName }, - false, - containersStatus, - dockerComposeUpOptions - ); + await dockerComposeUpPackage({ dnpName }, false, containersStatus, dockerComposeUpOptions); } catch (e) { if (e.message.toLowerCase().includes("port is already allocated")) { // Rollback port mappings are re-up - for (const [serviceName, portMappings] of Object.entries( - previousPortMappings - )) - if (services[serviceName]) - services[serviceName].setPortMapping(portMappings); + for (const [serviceName, portMappings] of Object.entries(previousPortMappings)) + if (services[serviceName]) services[serviceName].setPortMapping(portMappings); compose.write(); - await dockerComposeUpPackage( - { dnpName }, - false, - containersStatus, - dockerComposeUpOptions - ); + await dockerComposeUpPackage({ dnpName }, false, containersStatus, dockerComposeUpOptions); // Try to get the port colliding from the error - const ipAndPort = (e.message.match( - /(?:Bind for)(.+)(?:failed: port is already allocated)/ - ) || [])[1]; + const ipAndPort = (e.message.match(/(?:Bind for)(.+)(?:failed: port is already allocated)/) || [])[1]; const collidingPortNumber = (ipAndPort || "").split(":")[1] || ""; // Throw error throw Error( `${ - collidingPortNumber - ? `Port ${collidingPortNumber} is already mapped` - : "Port collision" + collidingPortNumber ? `Port ${collidingPortNumber} is already mapped` : "Port collision" }. Reverted port mapping update` ); } diff --git a/packages/dappmanager/src/calls/packageStartStop.ts b/packages/dappmanager/src/calls/packageStartStop.ts index 67306170b..f06c6639e 100644 --- a/packages/dappmanager/src/calls/packageStartStop.ts +++ b/packages/dappmanager/src/calls/packageStartStop.ts @@ -6,11 +6,7 @@ import { getServicesSharingPid } from "@dappnode/utils"; import { ComposeFileEditor } from "@dappnode/dockercompose"; import { PackageContainer } from "@dappnode/types"; -const dnpsAllowedToStop = [ - params.ipfsDnpName, - params.wifiDnpName, - params.HTTPS_PORTAL_DNPNAME -]; +const dnpsAllowedToStop = [params.ipfsDnpName, params.wifiDnpName, params.HTTPS_PORTAL_DNPNAME]; /** * Stops or starts a package containers @@ -36,9 +32,7 @@ export async function packageStartStop({ } } - const targetContainers = dnp.containers.filter( - c => !serviceNames || serviceNames.includes(c.serviceName) - ); + const targetContainers = dnp.containers.filter((c) => !serviceNames || serviceNames.includes(c.serviceName)); if (targetContainers.length === 0) { const queryId = [dnpName, ...(serviceNames || [])].join(", "); @@ -48,14 +42,14 @@ export async function packageStartStop({ const servicesSharingPid = getServicesSharingPid(compose, targetContainers); if (servicesSharingPid) { - const targetContainersPid = dnp.containers.filter(c => + const targetContainersPid = dnp.containers.filter((c) => servicesSharingPid.targetPidServices.includes(c.serviceName) ); - const dependantContainersPid = dnp.containers.filter(c => + const dependantContainersPid = dnp.containers.filter((c) => servicesSharingPid.dependantPidServices.includes(c.serviceName) ); - if (targetContainers.every(container => container.running)) { + if (targetContainers.every((container) => container.running)) { // STOP: first stop dependatPid containers (pid must exist), second stop targetPid containers await containersStop(dependantContainersPid); await containersStop(targetContainersPid); @@ -65,7 +59,7 @@ export async function packageStartStop({ await containersStart(dependantContainersPid); } } else { - if (targetContainers.every(container => container.running)) { + if (targetContainers.every((container) => container.running)) { await containersStop(targetContainers); } else { await containersStart(targetContainers); @@ -78,22 +72,12 @@ export async function packageStartStop({ // Utils -async function containersStop( - targetContainers: PackageContainer[] -): Promise<void> { +async function containersStop(targetContainers: PackageContainer[]): Promise<void> { await Promise.all( - targetContainers.map(async c => - dockerContainerStop(c.containerName, { timeout: c.dockerTimeout }) - ) + targetContainers.map(async (c) => dockerContainerStop(c.containerName, { timeout: c.dockerTimeout })) ); } -async function containersStart( - targetContainers: PackageContainer[] -): Promise<void> { - await Promise.all( - targetContainers.map(async container => - dockerContainerStart(container.containerName) - ) - ); +async function containersStart(targetContainers: PackageContainer[]): Promise<void> { + await Promise.all(targetContainers.map(async (container) => dockerContainerStart(container.containerName))); } diff --git a/packages/dappmanager/src/calls/passwordManager.ts b/packages/dappmanager/src/calls/passwordManager.ts index 8cdadecb3..0192234ba 100644 --- a/packages/dappmanager/src/calls/passwordManager.ts +++ b/packages/dappmanager/src/calls/passwordManager.ts @@ -16,9 +16,7 @@ const baseCommand = `docker run --rm -v /etc:/etc --privileged --entrypoint=""`; export async function isPasswordSecure(): Promise<boolean> { const image = await getDappmanagerImage(); try { - const res = await shell( - `${baseCommand} ${image} sh -c "grep dappnode:.*${insecureSalt} /etc/shadow"` - ); + const res = await shell(`${baseCommand} ${image} sh -c "grep dappnode:.*${insecureSalt} /etc/shadow"`); return !res; } catch (e) { /** @@ -39,8 +37,7 @@ export async function isPasswordSecure(): Promise<boolean> { */ export async function changePassword(newPassword: string): Promise<void> { if (!newPassword) throw Error("newPassword must be defined"); - if (typeof newPassword !== "string") - throw Error("newPassword must be a string"); + if (typeof newPassword !== "string") throw Error("newPassword must be a string"); /** * Make sure the password is OK: @@ -48,22 +45,14 @@ export async function changePassword(newPassword: string): Promise<void> { * - Does not contain the `'` character, which would break the command * - Does not contain non-ascii characters which may cause trouble in the command */ - if (newPassword.length < 8) - throw Error("password length must be at least 8 characters"); + if (newPassword.length < 8) throw Error("password length must be at least 8 characters"); if (!/^((?!['])[\x20-\x7F])*$/.test(newPassword)) - throw Error( - `Password must contain only ASCII characters and not the ' character` - ); + throw Error(`Password must contain only ASCII characters and not the ' character`); - if (await isPasswordSecure()) - throw Error( - "The password can only be changed if it's the insecure default" - ); + if (await isPasswordSecure()) throw Error("The password can only be changed if it's the insecure default"); const image = await getDappmanagerImage(); - await shell( - `${baseCommand} -e PASS='${newPassword}' ${image} sh -c 'echo dappnode:$PASS | chpasswd'` - ); + await shell(`${baseCommand} -e PASS='${newPassword}' ${image} sh -c 'echo dappnode:$PASS | chpasswd'`); } // API calls @@ -97,11 +86,7 @@ export async function passwordIsSecure(): Promise<boolean> { * * @param newPassword super-secure-password */ -export async function passwordChange({ - newPassword -}: { - newPassword: string; -}): Promise<void> { +export async function passwordChange({ newPassword }: { newPassword: string }): Promise<void> { if (!newPassword) throw Error("Argument newPassword must be defined"); await changePassword(newPassword); diff --git a/packages/dappmanager/src/calls/portsStatusGet.ts b/packages/dappmanager/src/calls/portsStatusGet.ts index b90b8320b..3953a0af0 100644 --- a/packages/dappmanager/src/calls/portsStatusGet.ts +++ b/packages/dappmanager/src/calls/portsStatusGet.ts @@ -1,13 +1,7 @@ import * as db from "@dappnode/db"; import { list } from "@dappnode/upnpc"; import { logs } from "@dappnode/logger"; -import { - PortToOpen, - UpnpTablePortStatus, - ApiTablePortStatus, - UpnpPortMapping, - PackagePort -} from "@dappnode/types"; +import { PortToOpen, UpnpTablePortStatus, ApiTablePortStatus, UpnpPortMapping, PackagePort } from "@dappnode/types"; import { params } from "@dappnode/params"; import Ajv from "ajv"; @@ -98,14 +92,12 @@ async function performPortsScan({ portsToOpen: PackagePort[]; }): Promise<PortScanResult[]> { const tcpPorts = portsToOpen - .filter(port => port.protocol === "TCP") - .map(port => port.portNumber.toString()) + .filter((port) => port.protocol === "TCP") + .map((port) => port.portNumber.toString()) .join(","); try { - const response = await fetch( - `${apiEndpoint}/${publicIp}?tcpPorts=${tcpPorts}` - ); + const response = await fetch(`${apiEndpoint}/${publicIp}?tcpPorts=${tcpPorts}`); const responseJson = await response.json(); const responseJsonSanitized = sanitizeApiResponse(responseJson); @@ -114,7 +106,7 @@ async function performPortsScan({ } catch (e) { // Returns ports with status "error" when an error occurs fetching the API logs.error(`Error fetching port scanner ${e.message}`); - return tcpPorts.split(",").map(tcpPort => { + return tcpPorts.split(",").map((tcpPort) => { return { port: parseInt(tcpPort), status: "error", @@ -148,16 +140,12 @@ export async function portsUpnpStatusGet({ }): Promise<UpnpTablePortStatus[]> { const upnpPortMappings: UpnpPortMapping[] = await list(); // Ports opened, mapped with UPnP - return portsToOpen.map(port => ({ + return portsToOpen.map((port) => ({ port: port.portNumber, protocol: port.protocol, dnpName: port.dnpName, serviceName: port.serviceName, - status: upnpPortMappings.find( - upnpPort => parseInt(upnpPort.inPort) === port.portNumber - ) - ? "open" - : "closed" + status: upnpPortMappings.find((upnpPort) => parseInt(upnpPort.inPort) === port.portNumber) ? "open" : "closed" })); } @@ -165,21 +153,15 @@ export async function portsUpnpStatusGet({ * API call that returns the ports status to be displayed in the ports table * using API scan service */ -export async function portsApiStatusGet({ - portsToOpen -}: { - portsToOpen: PortToOpen[]; -}): Promise<ApiTablePortStatus[]> { +export async function portsApiStatusGet({ portsToOpen }: { portsToOpen: PortToOpen[] }): Promise<ApiTablePortStatus[]> { const apiTcpPortsStatus = await performPortsScan({ publicIp: db.publicIp.get(), portsToOpen }); - return portsToOpen.map(port => { + return portsToOpen.map((port) => { const tcpPort = - port.protocol === "TCP" - ? apiTcpPortsStatus.find(tcpPort => tcpPort.port === port.portNumber) - : undefined; + port.protocol === "TCP" ? apiTcpPortsStatus.find((tcpPort) => tcpPort.port === port.portNumber) : undefined; return { port: port.portNumber, protocol: port.protocol, diff --git a/packages/dappmanager/src/calls/releaseTrustedKey.ts b/packages/dappmanager/src/calls/releaseTrustedKey.ts index 4f6fac4be..7620b8a46 100644 --- a/packages/dappmanager/src/calls/releaseTrustedKey.ts +++ b/packages/dappmanager/src/calls/releaseTrustedKey.ts @@ -4,9 +4,7 @@ import { TrustedReleaseKey, releaseSignatureProtocols } from "@dappnode/types"; /** * Add a release key to trusted keys db */ -export async function releaseTrustedKeyAdd( - newTrustedKey: TrustedReleaseKey -): Promise<void> { +export async function releaseTrustedKeyAdd(newTrustedKey: TrustedReleaseKey): Promise<void> { if (!newTrustedKey.name) throw Error("Empty key name"); if (!newTrustedKey.dnpNameSuffix) throw Error("Empty dnpNameSuffix"); if (!newTrustedKey.signatureProtocol) throw Error("Empty signatureProtocol"); @@ -19,7 +17,7 @@ export async function releaseTrustedKeyAdd( // Ensure uniqueness const existingKeyIds = new Set(trustedKeys.map(getKeyId)); - const existingKeyNames = new Set(trustedKeys.map(k => k.name)); + const existingKeyNames = new Set(trustedKeys.map((k) => k.name)); const newKeyId = getKeyId(newTrustedKey); if (existingKeyIds.has(newKeyId)) { throw Error(`Trusted release key already added: ${newKeyId}`); @@ -39,13 +37,13 @@ export async function releaseTrustedKeyAdd( */ export async function releaseTrustedKeyRemove(keyName: string): Promise<void> { const trustedKeys = db.releaseKeysTrusted.get(); - const existingKeyNames = new Set(trustedKeys.map(k => k.name)); + const existingKeyNames = new Set(trustedKeys.map((k) => k.name)); if (!existingKeyNames.has(keyName)) { throw Error(`No key with name ${keyName}`); } - trustedKeys.filter(key => key.name !== keyName); + trustedKeys.filter((key) => key.name !== keyName); db.releaseKeysTrusted.set(trustedKeys); } diff --git a/packages/dappmanager/src/calls/setStaticIp.ts b/packages/dappmanager/src/calls/setStaticIp.ts index cc99f1b30..4e5806be8 100644 --- a/packages/dappmanager/src/calls/setStaticIp.ts +++ b/packages/dappmanager/src/calls/setStaticIp.ts @@ -10,11 +10,7 @@ import { logs } from "@dappnode/logger"; * - To enable: "85.84.83.82" * - To disable: null */ -export async function setStaticIp({ - staticIp -}: { - staticIp: string; -}): Promise<void> { +export async function setStaticIp({ staticIp }: { staticIp: string }): Promise<void> { const oldStaticIp = db.staticIp.get(); db.staticIp.set(staticIp); diff --git a/packages/dappmanager/src/calls/smooth.ts b/packages/dappmanager/src/calls/smooth.ts index c1bcfbf05..07a89b39c 100644 --- a/packages/dappmanager/src/calls/smooth.ts +++ b/packages/dappmanager/src/calls/smooth.ts @@ -11,8 +11,7 @@ export async function getShouldShowSmooth(): Promise<boolean> { // If the Smooth modal has not been shown yet, check if it should be shown // The Smooth modal should be shown if the web3signer mainnet is installed - if (await listPackageNoThrow({ dnpName: "web3signer.dnp.dappnode.eth" })) - return true; + if (await listPackageNoThrow({ dnpName: "web3signer.dnp.dappnode.eth" })) return true; else return false; } @@ -21,11 +20,7 @@ export async function getShouldShowSmooth(): Promise<boolean> { * @param isShown A boolean indicating whether the Smooth modal has been shown. * @returns A Promise that resolves when the status is successfully updated. */ -export async function setShouldShownSmooth({ - isShown -}: { - isShown: boolean; -}): Promise<void> { +export async function setShouldShownSmooth({ isShown }: { isShown: boolean }): Promise<void> { // Update the status indicating whether the Smooth modal has been shown db.smoothShown.set(isShown); -} \ No newline at end of file +} diff --git a/packages/dappmanager/src/calls/sshManager.ts b/packages/dappmanager/src/calls/sshManager.ts index 71af1273a..fd9552190 100644 --- a/packages/dappmanager/src/calls/sshManager.ts +++ b/packages/dappmanager/src/calls/sshManager.ts @@ -113,9 +113,7 @@ class SshManager { if (port >= 65536) throw Error(`Port must be < 65536: ${port}`); // NOTE: "--" MUST be used to make the flag and the command work - await this.shellHost( - `sed -- -i "s/.*Port .*/Port ${port}/g" /etc/ssh/sshd_config` - ); + await this.shellHost(`sed -- -i "s/.*Port .*/Port ${port}/g" /etc/ssh/sshd_config`); await this.shellHost("systemctl restart ssh.service"); } @@ -139,18 +137,12 @@ class SshManager { async removeRootAccess(): Promise<void> { // NOTE: "--" MUST be used to make the flag and the command work - await this.shellHost( - `sed -- -i "s/.*PermitRootLogin .*/PermitRootLogin no/g" /etc/ssh/sshd_config` - ); + await this.shellHost(`sed -- -i "s/.*PermitRootLogin .*/PermitRootLogin no/g" /etc/ssh/sshd_config`); } // Public methods from SshCalls are added below: - public async sshStatusSet({ - status - }: { - status: "enabled" | "disabled"; - }): Promise<void> { + public async sshStatusSet({ status }: { status: "enabled" | "disabled" }): Promise<void> { switch (status) { case "enabled": return await this.enable(); @@ -167,10 +159,8 @@ class SshManager { public async sshPortSet({ port }: { port: number }): Promise<void> { if (isNaN(port) || !isFinite(port)) throw Error(`Invalid port ${port}`); - if (port > this.maxPortNumber) - throw Error(`Port ${port} over maxPortNumber ${this.maxPortNumber}`); - if (port < this.minPortNumber) - throw Error(`Port ${port} under minPortNumber ${this.minPortNumber}`); + if (port > this.maxPortNumber) throw Error(`Port ${port} over maxPortNumber ${this.maxPortNumber}`); + if (port < this.minPortNumber) throw Error(`Port ${port} under minPortNumber ${this.minPortNumber}`); await this.setPort(port); } @@ -192,11 +182,7 @@ export async function sshPortGet(): Promise<number> { return await sshManager.sshPortGet(); } -export async function sshStatusSet({ - status -}: { - status: "enabled" | "disabled"; -}): Promise<void> { +export async function sshStatusSet({ status }: { status: "enabled" | "disabled" }): Promise<void> { return await sshManager.sshStatusSet({ status }); } diff --git a/packages/dappmanager/src/calls/stakerConfig.ts b/packages/dappmanager/src/calls/stakerConfig.ts index d0708f9cc..14a95ca03 100644 --- a/packages/dappmanager/src/calls/stakerConfig.ts +++ b/packages/dappmanager/src/calls/stakerConfig.ts @@ -5,19 +5,8 @@ import { execution, consensus, mevBoost, signer } from "../index.js"; * Sets the staker configuration: execution and consensus clients, remote signer, * mev boost, graffiti, fee recipient address and checkpoint sync url */ -export async function stakerConfigSet({ - stakerConfig -}: { - stakerConfig: StakerConfigSet; -}): Promise<void> { - const { - network, - executionDnpName, - consensusDnpName, - mevBoostDnpName, - relays, - web3signerDnpName - } = stakerConfig; +export async function stakerConfigSet({ stakerConfig }: { stakerConfig: StakerConfigSet }): Promise<void> { + const { network, executionDnpName, consensusDnpName, mevBoostDnpName, relays, web3signerDnpName } = stakerConfig; await Promise.all([ await execution.setNewExecution(network, executionDnpName), await consensus.setNewConsensus(network, consensusDnpName), @@ -34,9 +23,7 @@ export async function stakerConfigSet({ * Returns the current staker configuration: execution and consensus clients, * remote signer, mev boost, graffiti, fee recipient address and checkpoint sync url */ -export async function stakerConfigGet( - network: Network -): Promise<StakerConfigGet> { +export async function stakerConfigGet(network: Network): Promise<StakerConfigGet> { return await Promise.all([ await execution.getAllExecutions(network), await consensus.getAllConsensus(network), diff --git a/packages/dappmanager/src/calls/statsMemoryGet.ts b/packages/dappmanager/src/calls/statsMemoryGet.ts index b76219297..8ee891abe 100644 --- a/packages/dappmanager/src/calls/statsMemoryGet.ts +++ b/packages/dappmanager/src/calls/statsMemoryGet.ts @@ -13,9 +13,7 @@ export async function statsMemoryGet(): Promise<HostStatMemory> { * Parses memory statistics * @param memData Memory data from systeminformation */ -export function parseMemoryStats( - memData: si.Systeminformation.MemData -): HostStatMemory { +export function parseMemoryStats(memData: si.Systeminformation.MemData): HostStatMemory { return { total: memData.total, used: memData.active, // Using 'active' as it's closer to 'used' in most contexts diff --git a/packages/dappmanager/src/calls/systemInfoGet.ts b/packages/dappmanager/src/calls/systemInfoGet.ts index 8699bbd02..d1f654435 100644 --- a/packages/dappmanager/src/calls/systemInfoGet.ts +++ b/packages/dappmanager/src/calls/systemInfoGet.ts @@ -8,8 +8,7 @@ import { isCoreUpdateEnabled } from "@dappnode/daemons"; * Returns the current DAppNode system info */ export async function systemInfoGet(): Promise<SystemInfo> { - const { target: eth2ClientTarget, ethRemoteRpc } = - ethereumClient.computeEthereumTarget(); + const { target: eth2ClientTarget, ethRemoteRpc } = ethereumClient.computeEthereumTarget(); return { // Git version data @@ -29,10 +28,7 @@ export async function systemInfoGet(): Promise<SystemInfo> { publicIp: db.publicIp.get(), // Eth provider configured URL eth2ClientTarget, - ethClientStatus: - eth2ClientTarget !== "remote" - ? db.ethExecClientStatus.get(eth2ClientTarget.execClient) - : null, + ethClientStatus: eth2ClientTarget !== "remote" ? db.ethExecClientStatus.get(eth2ClientTarget.execClient) : null, ethClientFallback: db.ethClientFallback.get(), ethRemoteRpc, // Domain map @@ -54,10 +50,7 @@ function getNewFeatureIds(): NewFeatureId[] { if (db.executionClientMainnet.get() && db.consensusClientMainnet.get()) { // If the user does not has the fallback on and has not seen the full // repository view, show a specific one just asking for the fallback - if ( - db.ethClientFallback.get() === "off" && - db.newFeatureStatus.get("repository") !== "seen" - ) + if (db.ethClientFallback.get() === "off" && db.newFeatureStatus.get("repository") !== "seen") newFeatureIds.push("repository-fallback"); } else { // repository: Show only if nothing is selected @@ -68,14 +61,13 @@ function getNewFeatureIds(): NewFeatureId[] { if (!isCoreUpdateEnabled()) newFeatureIds.push("system-auto-updates"); // enable-ethical-metrics: Show only if not seen - if (db.newFeatureStatus.get("enable-ethical-metrics") !== "seen") - newFeatureIds.push("enable-ethical-metrics"); + if (db.newFeatureStatus.get("enable-ethical-metrics") !== "seen") newFeatureIds.push("enable-ethical-metrics"); // change-host-password: Show only if insecure if (!db.passwordIsSecure.get()) newFeatureIds.push("change-host-password"); // Filter out features that the user has already seen or set - return newFeatureIds.filter(featureId => { + return newFeatureIds.filter((featureId) => { const status = db.newFeatureStatus.get(featureId); return status !== "seen"; }); diff --git a/packages/dappmanager/src/calls/telegram.ts b/packages/dappmanager/src/calls/telegram.ts index b49519a50..14401943c 100644 --- a/packages/dappmanager/src/calls/telegram.ts +++ b/packages/dappmanager/src/calls/telegram.ts @@ -12,11 +12,7 @@ export async function telegramStatusGet(): Promise<boolean> { * Sets the telegram status * @param telegramStatus switch telegram bot status */ -export async function telegramStatusSet({ - telegramStatus -}: { - telegramStatus: boolean; -}): Promise<void> { +export async function telegramStatusSet({ telegramStatus }: { telegramStatus: boolean }): Promise<void> { db.telegramStatus.set(telegramStatus); eventBus.telegramStatusChanged.emit(); } @@ -37,13 +33,7 @@ export async function telegramConfigGet(): Promise<{ /** * Set telegram configuration: token and user ID */ -export async function telegramConfigSet({ - token, - userId -}: { - token: string; - userId: string; -}): Promise<void> { +export async function telegramConfigSet({ token, userId }: { token: string; userId: string }): Promise<void> { db.telegramToken.set(token); db.telegramUserId.set(userId); eventBus.telegramStatusChanged.emit(); diff --git a/packages/dappmanager/src/calls/wifi.ts b/packages/dappmanager/src/calls/wifi.ts index 9c083f890..a6bf9241a 100644 --- a/packages/dappmanager/src/calls/wifi.ts +++ b/packages/dappmanager/src/calls/wifi.ts @@ -29,8 +29,7 @@ export async function wifiReportGet(): Promise<WifiReport> { info = "Wifi restarting. Wait until it starts"; break; case "dead": - info = - "Wifi service dead, you must manually remove it and install it again"; + info = "Wifi service dead, you must manually remove it and install it again"; report = { lastLog: parseWifiLogs(await getWifiLastLog()), exitCode: wifiContainer.exitCode @@ -61,13 +60,8 @@ export async function wifiCredentialsGet(): Promise<CurrentWifiCredentials> { const composeWifi = new ComposeFileEditor(params.wifiDnpName, true); const wifiService = composeWifi.services()[params.wifiDnpName]; const wifiEnvs = wifiService.getEnvs(); - if ( - wifiEnvs[params.WIFI_KEY_SSID] === undefined || - wifiEnvs[params.WIFI_KEY_PASSWORD] === undefined - ) - throw Error( - "Wifi SSID and/or Wifi password does not exist on compose file" - ); + if (wifiEnvs[params.WIFI_KEY_SSID] === undefined || wifiEnvs[params.WIFI_KEY_PASSWORD] === undefined) + throw Error("Wifi SSID and/or Wifi password does not exist on compose file"); return { ssid: wifiEnvs[params.WIFI_KEY_SSID], password: wifiEnvs[params.WIFI_KEY_PASSWORD] diff --git a/packages/dappmanager/src/calls/wireguard.ts b/packages/dappmanager/src/calls/wireguard.ts index ac6fcf467..a9035a0db 100644 --- a/packages/dappmanager/src/calls/wireguard.ts +++ b/packages/dappmanager/src/calls/wireguard.ts @@ -4,13 +4,8 @@ import { packageSetEnvironment } from "./packageSetEnvironment.js"; import { ComposeFileEditor } from "@dappnode/dockercompose"; import { WireguardDeviceCredentials } from "@dappnode/types"; -const { - WIREGUARD_API_URL, - WIREGUARD_DEVICES_ENVNAME, - WIREGUARD_DNP_NAME, - WIREGUARD_ISCORE, - WIREGUARD_MAIN_SERVICE -} = params; +const { WIREGUARD_API_URL, WIREGUARD_DEVICES_ENVNAME, WIREGUARD_DNP_NAME, WIREGUARD_ISCORE, WIREGUARD_MAIN_SERVICE } = + params; class WireguardClient { getDevices(): string[] { @@ -19,16 +14,14 @@ class WireguardClient { // So it's easier and cleaner to just parse the docker-compose.yml const compose = new ComposeFileEditor(WIREGUARD_DNP_NAME, WIREGUARD_ISCORE); const service = compose.services()[WIREGUARD_MAIN_SERVICE]; - if (!service) - throw Error(`Wireguard service ${WIREGUARD_MAIN_SERVICE} does not exist`); + if (!service) throw Error(`Wireguard service ${WIREGUARD_MAIN_SERVICE} does not exist`); const peersCsv = service.getEnvs()[WIREGUARD_DEVICES_ENVNAME] || ""; return peersCsv.split(","); } async addDevice(device: string): Promise<void> { if (!device) throw Error("Device name must not be empty"); - if (!/^[a-z0-9]+$/i.test(device)) - throw Error("Device name must contain only alphanumeric characters"); + if (!/^[a-z0-9]+$/i.test(device)) throw Error("Device name must contain only alphanumeric characters"); const devices = new Set(this.getDevices()); if (devices.has(device)) throw Error(`Device ${device} already exists`); @@ -59,9 +52,7 @@ class WireguardClient { // - remote qr: '/dappnode_admin?qr' // - local: '/dappnode_admin?local' // - local qr: '/dappnode_admin?local&qr' - async getDeviceCredentials( - device: string - ): Promise<WireguardDeviceCredentials> { + async getDeviceCredentials(device: string): Promise<WireguardDeviceCredentials> { const url = urlJoin(WIREGUARD_API_URL, device); const remoteConfigUrl = url; const localConfigUrl = `${url}?local=true`; @@ -100,9 +91,7 @@ export async function wireguardDeviceRemove(device: string): Promise<void> { await wireguardClient.removeDevice(device); } -export async function wireguardDeviceGet( - device: string -): Promise<WireguardDeviceCredentials> { +export async function wireguardDeviceGet(device: string): Promise<WireguardDeviceCredentials> { return wireguardClient.getDeviceCredentials(device); } diff --git a/packages/dappmanager/src/index.ts b/packages/dappmanager/src/index.ts index 62e9de2d3..4b7cafacd 100644 --- a/packages/dappmanager/src/index.ts +++ b/packages/dappmanager/src/index.ts @@ -8,13 +8,7 @@ import { copyHostServices, copyHostTimers } from "@dappnode/hostscriptsservices"; -import { - DappnodeInstaller, - getEthersProvider, - getEthUrl, - getIpfsUrl, - postRestartPatch -} from "@dappnode/installer"; +import { DappnodeInstaller, getEthersProvider, getEthUrl, getIpfsUrl, postRestartPatch } from "@dappnode/installer"; import * as calls from "./calls/index.js"; import { routesLogger, subscriptionsLogger, logs } from "@dappnode/logger"; import * as routes from "./api/routes/index.js"; @@ -25,11 +19,7 @@ import { createGlobalEnvsEnvFile } from "@dappnode/utils"; import { startAvahiDaemon, startDaemons } from "@dappnode/daemons"; import { executeMigrations } from "@dappnode/migrations"; import { startTestApi } from "./api/startTestApi.js"; -import { - getLimiter, - getViewsCounterMiddleware, - getEthForwardMiddleware -} from "./api/middlewares/index.js"; +import { getLimiter, getViewsCounterMiddleware, getEthForwardMiddleware } from "./api/middlewares/index.js"; import { AdminPasswordDb } from "./api/auth/adminPasswordDb.js"; import { DeviceCalls } from "./calls/device/index.js"; import { startHttpApi } from "./api/startHttpApi.js"; @@ -41,13 +31,10 @@ const controller = new AbortController(); // Initialize DB must be the first step so the db has the required values initializeDb() .then(() => logs.info("Initialized Database")) - .catch(e => logs.error("Error inititializing Database", e)); + .catch((e) => logs.error("Error inititializing Database", e)); -await getEthUrl().catch(e => { - logs.error( - `Error getting ethUrl, using default ${params.ETH_MAINNET_RPC_URL_REMOTE}`, - e - ); +await getEthUrl().catch((e) => { + logs.error(`Error getting ethUrl, using default ${params.ETH_MAINNET_RPC_URL_REMOTE}`, e); return params.ETH_MAINNET_RPC_URL_REMOTE; }); @@ -59,10 +46,7 @@ try { } // Required db to be initialized -export const dappnodeInstaller = new DappnodeInstaller( - ipfsUrl, - await getEthersProvider() -); +export const dappnodeInstaller = new DappnodeInstaller(ipfsUrl, await getEthersProvider()); export const publicRegistry = new DappNodeRegistry("public"); @@ -101,31 +85,25 @@ export const mevBoost = new MevBoost(dappnodeInstaller); export const signer = new Signer(dappnodeInstaller); // Execute migrations -executeMigrations(execution, consensus, signer, mevBoost).catch(e => - logs.error("Error on executeMigrations", e) -); +executeMigrations(execution, consensus, signer, mevBoost).catch((e) => logs.error("Error on executeMigrations", e)); // Start daemons startDaemons(dappnodeInstaller, controller.signal); Promise.all([ // Copy host scripts - copyHostScripts().catch(e => logs.error("Error copying host scripts", e)), + copyHostScripts().catch((e) => logs.error("Error copying host scripts", e)), // Copy host services - copyHostServices().catch(e => logs.error("Error copying host services", e)), + copyHostServices().catch((e) => logs.error("Error copying host services", e)), // Copy host timers - copyHostTimers().catch(e => logs.error("Error copying host timers", e)) + copyHostTimers().catch((e) => logs.error("Error copying host timers", e)) ]).then(() => { // avahiDaemon uses a host script that must be copied before been initialized - startAvahiDaemon().catch(e => logs.error("Error starting avahi daemon", e)); + startAvahiDaemon().catch((e) => logs.error("Error starting avahi daemon", e)); // start check-docker-network service with timer - checkDockerNetwork().catch(e => - logs.error("Error starting service docker network checker", e) - ); + checkDockerNetwork().catch((e) => logs.error("Error starting service docker network checker", e)); // start recreate-dappnode service with timer - recreateDappnode().catch(e => - logs.error("Error starting service recreate dappnode", e) - ); + recreateDappnode().catch((e) => logs.error("Error starting service recreate dappnode", e)); }); // Create the global env file @@ -133,7 +111,7 @@ createGlobalEnvsEnvFile(); // TODO: find a proper place for this // Store pushed notifications in DB -eventBus.notification.on(notification => { +eventBus.notification.on((notification) => { db.notificationPush(notification.id, notification); }); @@ -141,17 +119,15 @@ eventBus.notification.on(notification => { // TODO: find a proper place for this. Consider having a initial calls health check calls .passwordIsSecure() - .then(isSecure => - logs.info("Host password is", isSecure ? "secure" : "INSECURE") - ) - .catch(e => logs.error("Error checking if host user password is secure", e)); + .then((isSecure) => logs.info("Host password is", isSecure ? "secure" : "INSECURE")) + .catch((e) => logs.error("Error checking if host user password is secure", e)); // Read and print version data const versionData = getVersionData(); if (versionData.ok) logs.info("Version info", versionData.data); else logs.error(`Error getting version data: ${versionData.message}`); -postRestartPatch().catch(e => logs.error("Error on postRestartPatch", e)); +postRestartPatch().catch((e) => logs.error("Error on postRestartPatch", e)); // Graceful shutdown process.on("SIGINT", () => { diff --git a/packages/dappmanager/src/initializeDb.ts b/packages/dappmanager/src/initializeDb.ts index 14e48046a..e6e5e9fa2 100644 --- a/packages/dappmanager/src/initializeDb.ts +++ b/packages/dappmanager/src/initializeDb.ts @@ -2,12 +2,7 @@ import * as db from "@dappnode/db"; import { eventBus } from "@dappnode/eventbus"; import { generateKeysIfNotExistOrNotValid } from "@dappnode/dyndns"; import { getDappmanagerImage } from "@dappnode/dockerapi"; -import { - getInternalIp, - getServerName, - getStaticIp, - ping -} from "./utils/index.js"; +import { getInternalIp, getServerName, getStaticIp, ping } from "./utils/index.js"; import { getExternalUpnpIp, isUpnpAvailable } from "@dappnode/upnpc"; import { writeGlobalEnvsToEnvFile } from "@dappnode/db"; import { params } from "@dappnode/params"; @@ -21,10 +16,7 @@ const getInternalIpSafe = returnNullIfError(getInternalIp); const getExternalUpnpIpSafe = returnNullIfError(getExternalUpnpIp, true); const getPublicIpFromUrlsSafe = returnNullIfError(getPublicIpFromUrls); -function returnNullIfError( - fn: () => Promise<string>, - silent?: boolean -): () => Promise<string | null> { +function returnNullIfError(fn: () => Promise<string>, silent?: boolean): () => Promise<string | null> { return async function (): Promise<string | null> { try { return await fn(); @@ -60,8 +52,7 @@ export async function initializeDb(): Promise<void> { * Migrate ipfs remote gateway endpoint from http://ipfs.dappnode.io:8081 to https://ipfs.gateway.dappnode.io * The endpoint http://ipfs.dappnode.io:8081 is being deprecated */ - if (db.ipfsGateway.get() === "http://ipfs.dappnode.io:8081") - db.ipfsGateway.set(params.IPFS_REMOTE); + if (db.ipfsGateway.get() === "http://ipfs.dappnode.io:8081") db.ipfsGateway.set(params.IPFS_REMOTE); /** * @@ -111,12 +102,9 @@ export async function initializeDb(): Promise<void> { }); db.domain.set(vpndb.domain); } - if (vpndb.staticIp && !db.staticIp.get()) - db.staticIp.set(vpndb.staticIp || ""); + if (vpndb.staticIp && !db.staticIp.get()) db.staticIp.set(vpndb.staticIp || ""); if (vpndb["imported-installation-staticIp"]) - db.importedInstallationStaticIp.set( - Boolean(vpndb["imported-installation-staticIp"]) - ); + db.importedInstallationStaticIp.set(Boolean(vpndb["imported-installation-staticIp"])); db.isVpnDbMigrated.set(true); @@ -150,10 +138,7 @@ export async function initializeDb(): Promise<void> { // > External IP // If the host is exposed to the internet and the staticIp is set, avoid calling UPnP. // Otherwise, get the externalIp from UPnP - const externalIp: string | null = - staticIp && staticIp === internalIp - ? staticIp - : await getExternalUpnpIpSafe(); + const externalIp: string | null = staticIp && staticIp === internalIp ? staticIp : await getExternalUpnpIpSafe(); // > Public IP // `getPublicIpFromUrls` is a call to a centralized service. @@ -165,15 +150,10 @@ export async function initializeDb(): Promise<void> { // UPnP is available and necessary only if the internalIp is not equal to the public IP // and the external IP from UPnP command succeeded const upnpAvailable = - Boolean(publicIp && externalIp && internalIp !== publicIp) && - (await isUpnpAvailable()) - ? true - : false; + Boolean(publicIp && externalIp && internalIp !== publicIp) && (await isUpnpAvailable()) ? true : false; // > - const doubleNat = publicIp - ? Boolean(externalIp && externalIp !== publicIp) - : false; + const doubleNat = publicIp ? Boolean(externalIp && externalIp !== publicIp) : false; // > No NAT Loopback // This boolean will trigger a warning in the ADMIN UI to alert the user to use different VPN profiles @@ -181,16 +161,12 @@ export async function initializeDb(): Promise<void> { // to connect from the same network as the DAppNode // * The ping command is really slow, only execute it if necessary // * Ping does not throw - const noNatLoopback = publicIp - ? Boolean(internalIp !== publicIp ? !(await ping(publicIp)) : false) - : false; + const noNatLoopback = publicIp ? Boolean(internalIp !== publicIp ? !(await ping(publicIp)) : false) : false; // > Alert user to open ports // This boolean will trigger a warning in the ADMIN UI to alert the user to open ports // Will be true if the DAppNode is behind a router but the external IP from UPnP command failed - const alertUserToOpenPorts = publicIp - ? Boolean(internalIp !== publicIp && !upnpAvailable) - : false; + const alertUserToOpenPorts = publicIp ? Boolean(internalIp !== publicIp && !upnpAvailable) : false; const serverName = getServerName(); db.publicIp.set(publicIp || ""); @@ -220,7 +196,7 @@ export async function initializeDb(): Promise<void> { logs.info("Exposed to the public internet, disabling local proxying"); localProxyingEnableDisable(false).then( () => logs.info("Disabled local proxying"), - e => logs.error("Error disabling local proxying", e) + (e) => logs.error("Error disabling local proxying", e) ); } } diff --git a/packages/dappmanager/src/utils/getInternalIp.ts b/packages/dappmanager/src/utils/getInternalIp.ts index bf0c57dc7..8cd9cb44c 100644 --- a/packages/dappmanager/src/utils/getInternalIp.ts +++ b/packages/dappmanager/src/utils/getInternalIp.ts @@ -5,9 +5,7 @@ import { getDappmanagerImage } from "@dappnode/dockerapi"; export async function getInternalIp(): Promise<string> { try { const image = await getDappmanagerImage(); - const output = await shell( - `docker run --rm --net=host --entrypoint=/sbin/ip ${image} route get 1` - ); + const output = await shell(`docker run --rm --net=host --entrypoint=/sbin/ip ${image} route get 1`); // A unicode escape sequence is basically atomic. You cannot really build one dynamically // Template literals basically perform string concatenation, so your code is equivalent to // FROM: 1.0.0.0 via 104.248.144.1 dev eth0 src 104.248.150.201 uid 0 diff --git a/packages/dappmanager/src/utils/getVersionData.ts b/packages/dappmanager/src/utils/getVersionData.ts index c8d173b43..ece224606 100644 --- a/packages/dappmanager/src/utils/getVersionData.ts +++ b/packages/dappmanager/src/utils/getVersionData.ts @@ -20,9 +20,7 @@ export const getVersionData = memoize(function (): { message?: string; } { try { - const data: PackageVersionData = JSON.parse( - fs.readFileSync(params.GIT_DATA_PATH, "utf8") - ); + const data: PackageVersionData = JSON.parse(fs.readFileSync(params.GIT_DATA_PATH, "utf8")); const previousData = db.versionData.get(); const isNewVersion = !isEqual(previousData, data); diff --git a/packages/dappmanager/src/utils/index.ts b/packages/dappmanager/src/utils/index.ts index 2ac80832e..20410ab16 100644 --- a/packages/dappmanager/src/utils/index.ts +++ b/packages/dappmanager/src/utils/index.ts @@ -3,11 +3,6 @@ export { getServerName } from "./getServerName.js"; export { getStaticIp } from "./getStaticIp.js"; export { getVersionData, isNewDappmanagerVersion } from "./getVersionData.js"; export { ping } from "./ping.js"; -export { - prepareMessageFromPackage, - hashMessage, - signDataFromPackage, - getAddressFromPrivateKey -} from "./sign.js"; +export { prepareMessageFromPackage, hashMessage, signDataFromPackage, getAddressFromPrivateKey } from "./sign.js"; export { validateBackupArray } from "./validateBackupArray.js"; export { verifyXz } from "./verifyXz.js"; diff --git a/packages/dappmanager/src/utils/sign.ts b/packages/dappmanager/src/utils/sign.ts index 7b1e05d0f..ec58a7ee8 100644 --- a/packages/dappmanager/src/utils/sign.ts +++ b/packages/dappmanager/src/utils/sign.ts @@ -1,24 +1,10 @@ import { ethers } from "ethers"; import { params } from "@dappnode/params"; -export function prepareMessageFromPackage({ - packageEnsName, - data -}: { - packageEnsName: string; - data: string; -}): string { +export function prepareMessageFromPackage({ packageEnsName, data }: { packageEnsName: string; data: string }): string { // Adding a custom prefix to signature to prevent signing arbitrary data. // See https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign - return ( - params.SIGNATURE_PREFIX + - "\n" + - packageEnsName + - "\n" + - data.length + - "\n" + - data - ); + return params.SIGNATURE_PREFIX + "\n" + packageEnsName + "\n" + data.length + "\n" + data; } export function hashMessage(message: string): string { diff --git a/packages/dappmanager/src/utils/validateBackupArray.ts b/packages/dappmanager/src/utils/validateBackupArray.ts index b55747a49..535a81094 100644 --- a/packages/dappmanager/src/utils/validateBackupArray.ts +++ b/packages/dappmanager/src/utils/validateBackupArray.ts @@ -14,12 +14,9 @@ import path from "path"; export function validateBackupArray(backup: PackageBackup[]): void { const pathsObj: { [backupName: string]: boolean } = {}; for (const { name, path: _path } of backup) { - if (pathsObj[name]) - throw Error(`Backup name ${name} is duplicated. They must be unique`); - if (!path.isAbsolute(_path)) - throw Error(`Backup paths must be absolute, path: ${_path}`); - if (path.parse(name).dir) - throw Error(`Backup names cannot be a path, name: ${name}`); + if (pathsObj[name]) throw Error(`Backup name ${name} is duplicated. They must be unique`); + if (!path.isAbsolute(_path)) throw Error(`Backup paths must be absolute, path: ${_path}`); + if (path.parse(name).dir) throw Error(`Backup names cannot be a path, name: ${name}`); pathsObj[name] = true; } } diff --git a/packages/dappmanager/test/integration/backup.test.int.ts b/packages/dappmanager/test/integration/backup.test.int.ts index 0b0f71283..725f600e1 100644 --- a/packages/dappmanager/test/integration/backup.test.int.ts +++ b/packages/dappmanager/test/integration/backup.test.int.ts @@ -4,13 +4,7 @@ import * as fs from "fs"; import * as path from "path"; import * as db from "@dappnode/db"; import { shell } from "@dappnode/utils"; -import { - testDir, - cleanTestDir, - createTestDir, - clearDbs, - shellSafe -} from "../testUtils.js"; +import { testDir, cleanTestDir, createTestDir, clearDbs, shellSafe } from "../testUtils.js"; // Calls import { backupGet } from "../../src/calls/backupGet.js"; @@ -26,10 +20,8 @@ describe("Integration test for backup to and from:", function () { const dnpName = "test-backup.dnp.dappnode.eth"; const containerName = `DAppNodePackage-${dnpName}`; const backupFileCompName = "test-backup.dnp.dappnode.eth_backup.tar.xz"; - const fileId = - "e08dbd0f654c0ae06c08570e731c8f14c079ec54ab7e58915d52290612b0a908"; - const dockerComposePath = - "dnp_repo/test-backup.dnp.dappnode.eth/docker-compose.yml"; + const fileId = "e08dbd0f654c0ae06c08570e731c8f14c079ec54ab7e58915d52290612b0a908"; + const dockerComposePath = "dnp_repo/test-backup.dnp.dappnode.eth/docker-compose.yml"; const filePath = ".temp-transfer/test-backup.dnp.dappnode.eth_backup.tar.xz"; @@ -81,9 +73,7 @@ volumes: // Create the backup data structure await shell(`mkdir -p ${path.join(testDir, "test")}`); await shell(`echo "${content}" > ${path.join(testDir, "config")}`); - await shell( - `echo "${content}" > ${path.join(testDir, "test", "data.conf")}` - ); + await shell(`echo "${content}" > ${path.join(testDir, "test", "data.conf")}`); // Create tar.xz backup file const dirListToComp = ["config", "test"].join(" "); const backupFileComp = path.join(testDir, backupFileCompName); @@ -125,21 +115,11 @@ volumes: await shell(`tar -xf ${filePath} -C ${testDir}`); // Check the file contents - const backupFileContent = await shell( - `cat ${path.join(testDir, "config")}` - ); - expect(backupFileContent).to.equal( - content, - `Backup file (config) contents are incorrect` - ); + const backupFileContent = await shell(`cat ${path.join(testDir, "config")}`); + expect(backupFileContent).to.equal(content, `Backup file (config) contents are incorrect`); // Check the dir contents - const backupSubDirContent = await shell( - `cat ${path.join(testDir, "test/data.conf")}` - ); - expect(backupSubDirContent).to.equal( - content, - `Backup sub dir file (test/data.conf) contents are incorrect` - ); + const backupSubDirContent = await shell(`cat ${path.join(testDir, "test/data.conf")}`); + expect(backupSubDirContent).to.equal(content, `Backup sub dir file (test/data.conf) contents are incorrect`); }); after("Clean test docker container", async function () { diff --git a/packages/dappmanager/test/integration/fetchExternalData.test.int.ts b/packages/dappmanager/test/integration/fetchExternalData.test.int.ts index 19d3f46a0..7b35292c7 100644 --- a/packages/dappmanager/test/integration/fetchExternalData.test.int.ts +++ b/packages/dappmanager/test/integration/fetchExternalData.test.int.ts @@ -32,21 +32,15 @@ describe("Fetch external data", () => { describe("fetchDirectory", () => { it("Should fetch directory data", async () => { const directoryDnps = await calls.fetchDirectory(); - expect(directoryDnps).to.have.length.greaterThan( - 0, - "There should be packages in the directory return" - ); + expect(directoryDnps).to.have.length.greaterThan(0, "There should be packages in the directory return"); // Make sure the bitcoin DNP is there const dnpBitcoin = directoryDnps.find(({ name }) => name === bitcoinId); expect(dnpBitcoin, "Bitcoin DNP should be in directory array").to.be.ok; // Make sure that if there's a featured package it's first - const isThereFeatured = directoryDnps.some(dnp => dnp.isFeatured); + const isThereFeatured = directoryDnps.some((dnp) => dnp.isFeatured); if (isThereFeatured) { - expect( - directoryDnps[0].isFeatured, - "Wrong order: first package should be featured" - ).to.be.true; + expect(directoryDnps[0].isFeatured, "Wrong order: first package should be featured").to.be.true; } }); }); diff --git a/packages/dappmanager/test/integration/fetchSystemData.test.int.ts b/packages/dappmanager/test/integration/fetchSystemData.test.int.ts index 73d25f013..9099d56a8 100644 --- a/packages/dappmanager/test/integration/fetchSystemData.test.int.ts +++ b/packages/dappmanager/test/integration/fetchSystemData.test.int.ts @@ -73,10 +73,7 @@ describe.skip("Notifications", async () => { it("Should retrieve notifications", async () => { const result = await calls.notificationsGet(); - expect(result).to.have.length.greaterThan( - 0, - "There should be one notification" - ); + expect(result).to.have.length.greaterThan(0, "There should be one notification"); id = result[0].id; }); @@ -84,7 +81,7 @@ describe.skip("Notifications", async () => { if (!id) throw Error("Previous test failed"); await calls.notificationsRemove({ ids: [id] }); const result = await calls.notificationsGet(); - const deletedNotification = result.find(n => n.id === id); + const deletedNotification = result.find((n) => n.id === id); if (deletedNotification) { logs.info("deletedNotification", result); throw Error(`Notification id ${id} was not deleted`); diff --git a/packages/dappmanager/test/integration/fileTransfer.test.int.ts b/packages/dappmanager/test/integration/fileTransfer.test.int.ts index f0046393a..f30e34b66 100644 --- a/packages/dappmanager/test/integration/fileTransfer.test.int.ts +++ b/packages/dappmanager/test/integration/fileTransfer.test.int.ts @@ -2,11 +2,7 @@ import { expect } from "chai"; import http from "http"; import express from "express"; import bodyParser from "body-parser"; -import { - docker, - dockerGetArchiveSingleFile, - dockerPutArchiveSingleFile -} from "@dappnode/dockerapi"; +import { docker, dockerGetArchiveSingleFile, dockerPutArchiveSingleFile } from "@dappnode/dockerapi"; import { fileDownload } from "../../src/api/routes/fileDownload.js"; import { URL } from "url"; import { MemoryWritable } from "./testStreamUtils.js"; @@ -14,11 +10,7 @@ import { MemoryWritable } from "./testStreamUtils.js"; describe("file transfer - docker archive put, get", function () { const containerName = "DAppNodeTest-file-transfer"; const filePath = "/a/b/c/sample.json"; - const fileContent = JSON.stringify( - { sampleConfig: true, someValue: 22 }, - null, - 2 - ); + const fileContent = JSON.stringify({ sampleConfig: true, someValue: 22 }, null, 2); async function removeContainer(): Promise<void> { const container = docker.getContainer(containerName); @@ -53,26 +45,15 @@ describe("file transfer - docker archive put, get", function () { describe("through docker", () => { it("Should put and get a file", async () => { - await dockerPutArchiveSingleFile( - containerName, - filePath, - Buffer.from(fileContent) - ); + await dockerPutArchiveSingleFile(containerName, filePath, Buffer.from(fileContent)); const fileContentSink = new MemoryWritable<Buffer>(); - await dockerGetArchiveSingleFile( - containerName, - filePath, - fileContentSink - ); + await dockerGetArchiveSingleFile(containerName, filePath, fileContentSink); const returnedFileBuffer = Buffer.concat(fileContentSink.chunks); const returnedFileContent = returnedFileBuffer.toString("utf8"); - expect(returnedFileContent).to.equal( - fileContent, - "returned file does not match put file" - ); + expect(returnedFileContent).to.equal(fileContent, "returned file does not match put file"); }); }); @@ -86,11 +67,7 @@ describe("file transfer - docker archive put, get", function () { }); beforeEach("Add file to container", async () => { - await dockerPutArchiveSingleFile( - containerName, - filePath, - Buffer.from(fileContent) - ); + await dockerPutArchiveSingleFile(containerName, filePath, Buffer.from(fileContent)); }); it("Sould put and get a file from the API directly", async () => { @@ -100,14 +77,11 @@ describe("file transfer - docker archive put, get", function () { app.use(bodyParser.urlencoded({ extended: true })); const port = 8965; - app.get<{ containerName: string }>( - "/file-download/:containerName", - fileDownload - ); + app.get<{ containerName: string }>("/file-download/:containerName", fileDownload); const server = new http.Server(app); - await new Promise<void>(resolve => { + await new Promise<void>((resolve) => { server.listen(port, () => { resolve(); }); @@ -130,10 +104,7 @@ describe("file transfer - docker archive put, get", function () { throw Error(`${res.statusText}\n${resText}`); } - expect(resText).to.equal( - fileContent, - "returned file does not match put file" - ); + expect(resText).to.equal(fileContent, "returned file does not match put file"); }); }); }); diff --git a/packages/dappmanager/test/integration/packageHasPid.test.int.ts b/packages/dappmanager/test/integration/packageHasPid.test.int.ts index c21e5767f..075188780 100644 --- a/packages/dappmanager/test/integration/packageHasPid.test.int.ts +++ b/packages/dappmanager/test/integration/packageHasPid.test.int.ts @@ -2,11 +2,7 @@ import "mocha"; import fs from "fs"; import { expect } from "chai"; import { mockPackageData, shellSafe } from "../testUtils.js"; -import { - packageToInstallHasPid, - getServicesSharingPid, - ComposeServicesSharingPid -} from "@dappnode/utils"; +import { packageToInstallHasPid, getServicesSharingPid, ComposeServicesSharingPid } from "@dappnode/utils"; import { ComposeFileEditor } from "@dappnode/dockercompose"; describe("Module > compose > pid", () => { @@ -101,8 +97,6 @@ volumes: dependantPidServices: ["rpcdaemon"] }; - expect(getServicesSharingPid(compose.compose)).to.deep.equal( - expectedResult - ); + expect(getServicesSharingPid(compose.compose)).to.deep.equal(expectedResult); }); }); diff --git a/packages/dappmanager/test/integration/testIpfsUtils.ts b/packages/dappmanager/test/integration/testIpfsUtils.ts index 277c9b8f8..56977941c 100644 --- a/packages/dappmanager/test/integration/testIpfsUtils.ts +++ b/packages/dappmanager/test/integration/testIpfsUtils.ts @@ -48,10 +48,8 @@ export async function setUpIpfsNode(): Promise<void> { } // Get dappnode ipfs gateway ID - const dappnodeIpfsGatewayId = await remoteIpfsApi.id().catch(e => { - throw Error( - `Error getting dappnode ipfs gateway ID, dappnode ipfs gateway not available ${e}` - ); + const dappnodeIpfsGatewayId = await remoteIpfsApi.id().catch((e) => { + throw Error(`Error getting dappnode ipfs gateway ID, dappnode ipfs gateway not available ${e}`); }); // Connect to ipfs.dappnode.io diff --git a/packages/dappmanager/test/integration/testPackageUtils.ts b/packages/dappmanager/test/integration/testPackageUtils.ts index 523c5b52a..c0fa57d90 100644 --- a/packages/dappmanager/test/integration/testPackageUtils.ts +++ b/packages/dappmanager/test/integration/testPackageUtils.ts @@ -2,22 +2,15 @@ import "mocha"; import * as calls from "../../src/calls/index.js"; import { InstalledPackageData, ContainerState } from "@dappnode/types"; -export async function getDnpFromListPackages( - dnpName: string -): Promise<InstalledPackageData | undefined> { +export async function getDnpFromListPackages(dnpName: string): Promise<InstalledPackageData | undefined> { const dnpList = await calls.packagesGet(); if (!Array.isArray(dnpList)) throw Error("listPackages must return an array"); - return dnpList.find(dnp => dnp.dnpName === dnpName); + return dnpList.find((dnp) => dnp.dnpName === dnpName); } -export async function getDnpState( - dnpName: string, - serviceName?: string -): Promise<ContainerState | "down"> { +export async function getDnpState(dnpName: string, serviceName?: string): Promise<ContainerState | "down"> { const dnp = await getDnpFromListPackages(dnpName); if (!dnp) return "down"; - const container = dnp.containers.find( - c => !serviceName || c.serviceName === serviceName - ); + const container = dnp.containers.find((c) => !serviceName || c.serviceName === serviceName); return container ? container.state : "down"; } diff --git a/packages/dappmanager/test/testUtils.ts b/packages/dappmanager/test/testUtils.ts index b907dd334..0617c0521 100644 --- a/packages/dappmanager/test/testUtils.ts +++ b/packages/dappmanager/test/testUtils.ts @@ -19,9 +19,7 @@ import { ethers } from "ethers"; export const dappnodeInstaller = new DappnodeInstaller( "https://api.ipfs.dappnode.io", - new ethers.JsonRpcProvider( - `https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}` - ) + new ethers.JsonRpcProvider(`https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}`) ); export const testDir = "./test_files/"; @@ -31,9 +29,7 @@ const testMountpoint = "./test_mountpoints"; export const manifestFileName = "dappnode_package.json"; export const composeFileName = "docker-compose.yml"; -export const beforeAndAfter = ( - ...args: Parameters<Mocha.HookFunction> -): void => { +export const beforeAndAfter = (...args: Parameters<Mocha.HookFunction>): void => { before(...args); after(...args); }; @@ -55,6 +51,7 @@ function ignoreErrors<A, R>(fn: (arg: A) => R) { return await fn(arg); } catch (e) { // Ignore + console.error(e); } }; } @@ -73,19 +70,13 @@ export async function cleanRepos(): Promise<void> { await shell(`rm -rf ${params.REPO_DIR} ${params.DNCORE_DIR}/*.yml`); } -export async function cleanContainers( - ...containerIds: string[] -): Promise<void> { +export async function cleanContainers(...containerIds: string[]): Promise<void> { for (const containerId of containerIds) { // Clean containers - await shellSafe( - `docker rm -f -v $(docker ps -aq --filter name=${containerId})` - ); + await shellSafe(`docker rm -f -v $(docker ps -aq --filter name=${containerId})`); // Clean associated volumes const volumePrefix = containerId; - await shellSafe( - `docker volume rm -f $(docker volume ls --filter name=${volumePrefix} -q)` - ); + await shellSafe(`docker volume rm -f $(docker volume ls --filter name=${volumePrefix} -q)`); } } @@ -157,9 +148,7 @@ export const mockDockerSystemDfDataSample: DockerApiSystemDfReturn = { Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749", ParentId: "", RepoTags: ["busybox:latest"], - RepoDigests: [ - "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6" - ], + RepoDigests: ["busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"], Created: 1466724217, Size: 101010101, SharedSize: 0, @@ -173,8 +162,7 @@ export const mockDockerSystemDfDataSample: DockerApiSystemDfReturn = { Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148", Names: ["/top"], Image: "busybox", - ImageID: - "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749", + ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749", Command: "top", Created: 1472592424, SizeRootFs: 101010101, @@ -190,10 +178,8 @@ export const mockDockerSystemDfDataSample: DockerApiSystemDfReturn = { IPAMConfig: null, Links: null, Aliases: null, - NetworkID: - "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92", - EndpointID: - "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a", + NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92", + EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a", Gateway: "172.18.0.1", IPAddress: "172.18.0.2", IPPrefixLen: 16, diff --git a/packages/dappmanager/test/unit/api/index.test.ts b/packages/dappmanager/test/unit/api/index.test.ts index 6adf44406..653804bed 100644 --- a/packages/dappmanager/test/unit/api/index.test.ts +++ b/packages/dappmanager/test/unit/api/index.test.ts @@ -19,15 +19,13 @@ describe.skip("Test server auth", function () { async function parseRes(res: Response): Promise<RequestRes> { return { code: res.status, + // eslint-disable-next-line @typescript-eslint/no-explicit-any body: (await res.json()) as any }; } function expectRes(res: RequestRes, expectedRes: Partial<RequestRes>): void { - expect(res).to.deep.include( - expectedRes, - `Bad res\n${JSON.stringify(res, null, 2)}\n` - ); + expect(res).to.deep.include(expectedRes, `Bad res\n${JSON.stringify(res, null, 2)}\n`); } before("start server", () => { diff --git a/packages/dappmanager/test/unit/calls/autoUpdateDataGet.test.ts b/packages/dappmanager/test/unit/calls/autoUpdateDataGet.test.ts index b7b968bdb..cf0f2be3f 100644 --- a/packages/dappmanager/test/unit/calls/autoUpdateDataGet.test.ts +++ b/packages/dappmanager/test/unit/calls/autoUpdateDataGet.test.ts @@ -1,17 +1,7 @@ import "mocha"; import { expect } from "chai"; -import { - createTestDir, - cleanTestDir, - mockDnp, - clearDbs -} from "../../testUtils.js"; -import { - editDnpSetting, - editCoreSetting, - isUpdateDelayCompleted, - flagCompletedUpdate -} from "@dappnode/daemons"; +import { createTestDir, cleanTestDir, mockDnp, clearDbs } from "../../testUtils.js"; +import { editDnpSetting, editCoreSetting, isUpdateDelayCompleted, flagCompletedUpdate } from "@dappnode/daemons"; import { params } from "@dappnode/params"; import rewiremock from "rewiremock/node.js"; import { autoUpdateDataGet as autoUpdateDataGetType } from "../../../src/calls/autoUpdateDataGet.js"; @@ -61,7 +51,7 @@ describe.skip("Call function: autoUpdateDataGet", function () { beforeEach("Mock", async () => { const mock = await rewiremock.around( () => import("../../../src/calls/autoUpdateDataGet.js"), - mock => { + (mock) => { mock(() => import("@dappnode/dockerapi")) .with({ listPackages }) .toBeUsed(); @@ -80,11 +70,7 @@ describe.skip("Call function: autoUpdateDataGet", function () { editDnpSetting(true, dnpName); // Trigger some versions isUpdateDelayCompleted(dnpName, nextVersion, timestamp); - flagCompletedUpdate( - "core.dnp.dappnode.eth", - "admin@0.2.1,core@0.2.1", - timestamp - ); + flagCompletedUpdate("core.dnp.dappnode.eth", "admin@0.2.1,core@0.2.1", timestamp); }); it("should return auto-update data", async () => { diff --git a/packages/dappmanager/test/unit/calls/getHostUptime.test.ts b/packages/dappmanager/test/unit/calls/getHostUptime.test.ts index af2be1d35..5fa66a898 100644 --- a/packages/dappmanager/test/unit/calls/getHostUptime.test.ts +++ b/packages/dappmanager/test/unit/calls/getHostUptime.test.ts @@ -5,8 +5,7 @@ import { getHostUptime } from "../../../src/calls/getHostUptime.js"; describe.skip("Call function: getHostUptime", function () { it("Should return the uptime of the host", async () => { const output = await getHostUptime(); - const uptimePattern = - /^up (\d+ weeks?, )?(\d+ days?, )?(\d+ hours?, )?(\d+ minutes?)?$/; + const uptimePattern = /^up (\d+ weeks?, )?(\d+ days?, )?(\d+ hours?, )?(\d+ minutes?)?$/; const matches = uptimePattern.test(output); expect(matches).to.be.true; console.log(output); diff --git a/packages/dappmanager/test/unit/calls/packageInstall.test.ts b/packages/dappmanager/test/unit/calls/packageInstall.test.ts index b8d54c291..7182c40ba 100644 --- a/packages/dappmanager/test/unit/calls/packageInstall.test.ts +++ b/packages/dappmanager/test/unit/calls/packageInstall.test.ts @@ -76,7 +76,7 @@ describe.skip("Call function: packageInstall", function () { before("Mock", async () => { const mock = await rewiremock.around( () => import("../../../src/calls/packageInstall.js"), - mock => { + (mock) => { mock(() => import("@dappnode/installer")) .with({ DappnodeInstaller: DappnodeInstallerMock }) .toBeUsed(); @@ -139,10 +139,7 @@ describe.skip("Call function: packageInstall", function () { // Step 4: Download requested packages it("should have called download", async () => { sinon.assert.callCount(packages.download, 2); - expect([ - packages.download.getCall(0).args[0], - packages.download.getCall(1).args[0] - ]).deep.equal( + expect([packages.download.getCall(0).args[0], packages.download.getCall(1).args[0]]).deep.equal( [callKwargPkg, callKwargDep], `should call packages.download for ${pkgName} and ${depName}` ); @@ -151,10 +148,7 @@ describe.skip("Call function: packageInstall", function () { it("should have called load", async () => { sinon.assert.callCount(packages.load, 2); - expect([ - packages.load.getCall(0).args[0], - packages.load.getCall(1).args[0] - ]).deep.equal( + expect([packages.load.getCall(0).args[0], packages.load.getCall(1).args[0]]).deep.equal( [callKwargPkg, callKwargDep], `should call packages.load for ${pkgName} and ${depName}` ); @@ -164,10 +158,7 @@ describe.skip("Call function: packageInstall", function () { it("should have called run", async () => { sinon.assert.callCount(packages.run, 2); - expect([ - packages.run.getCall(0).args[0], - packages.run.getCall(1).args[0] - ]).deep.equal( + expect([packages.run.getCall(0).args[0], packages.run.getCall(1).args[0]]).deep.equal( [callKwargPkg, callKwargDep], `should call packages.run for ${pkgName} and ${depName}` ); diff --git a/packages/dappmanager/test/unit/calls/packageRemove.test.ts b/packages/dappmanager/test/unit/calls/packageRemove.test.ts index b094977f0..a0f3799db 100644 --- a/packages/dappmanager/test/unit/calls/packageRemove.test.ts +++ b/packages/dappmanager/test/unit/calls/packageRemove.test.ts @@ -44,7 +44,7 @@ describe.skip("Call function: packageRemove", function () { before("Mock", async () => { const mock = await rewiremock.around( () => import("../../../src/calls/packageRemove.js"), - mock => { + (mock) => { mock(() => import("@dappnode/dockerapi")) .with({ dockerComposeDown }) .toBeUsed(); diff --git a/packages/dappmanager/test/unit/dockerAutoUpdate/dockerAutoUpdate.test.int.ts b/packages/dappmanager/test/unit/dockerAutoUpdate/dockerAutoUpdate.test.int.ts index 0ed67ee05..f70a73588 100644 --- a/packages/dappmanager/test/unit/dockerAutoUpdate/dockerAutoUpdate.test.int.ts +++ b/packages/dappmanager/test/unit/dockerAutoUpdate/dockerAutoUpdate.test.int.ts @@ -7,11 +7,7 @@ import path from "path"; import { shell } from "@dappnode/utils"; import child from "child_process"; import { testDir, cleanTestDir, createTestDir } from "../../testUtils.js"; -import { - listContainer, - listPackageContainers, - dockerContainerInspect -} from "@dappnode/dockerapi"; +import { listContainer, listPackageContainers, dockerContainerInspect } from "@dappnode/dockerapi"; import { ComposeEditor } from "@dappnode/dockercompose"; /** * Dangerous docker-compose behaviour. If starting the container fails, @@ -28,20 +24,14 @@ const versionNext = "2.0.0"; const labelVersion = "test.dappnode.version"; const testDirContainer = path.resolve("/", testDir); -const volumes = [ - "/var/run/docker.sock:/var/run/docker.sock", - `${path.resolve(testDir)}:${testDirContainer}` -]; +const volumes = ["/var/run/docker.sock:/var/run/docker.sock", `${path.resolve(testDir)}:${testDirContainer}`]; const prevComposeName = `docker-compose-previous.yml`; const nextComposeName = `docker-compose-next.yml`; const restartComposeName = `docker-compose-restart.yml`; const restartEntrypoint = "restart-entrypoint.sh"; const inHost = (_path: string): string => path.join(testDir, _path); -const inContainer = (_path: string): string => - path.join(testDirContainer, _path); - -/* eslint-disable @typescript-eslint/explicit-function-return-type */ +const inContainer = (_path: string): string => path.join(testDirContainer, _path); /** * Skip until the image 'danielguerra/dind-compose' is publicly available @@ -50,13 +40,10 @@ const inContainer = (_path: string): string => describe.skip("Test a container restarting itself", function () { async function cleanContainers(): Promise<void> { try { - await shell( - `docker rm -f $(docker ps -aq --filter ancestor=${dindComposeImage})` - ); + await shell(`docker rm -f $(docker ps -aq --filter ancestor=${dindComposeImage})`); } catch (e) { // Ignore errors when there are no containers to delete - if (!e.message.includes("requires at least 1 argument")) - console.warn(`Error cleaning containers`, e); + if (!e.message.includes("requires at least 1 argument")) console.warn(`Error cleaning containers`, e); } } @@ -98,9 +85,7 @@ then docker compose -f ${inContainer(prevComposeName)} up -d -t 0 else echo "${mainContainerName} is not running, using --force-recreate" - docker compose -f ${inContainer( - prevComposeName - )} up -d -t 0 --force-recreate + docker compose -f ${inContainer(prevComposeName)} up -d -t 0 --force-recreate fi fi exit $UPEXIT @@ -116,20 +101,14 @@ exit $UPEXIT }); beforeEach("Start main container", async () => { - await runUntilExited( - `docker compose -f ${inHost(prevComposeName)} up -d`, - "main" - ); + await runUntilExited(`docker compose -f ${inHost(prevComposeName)} up -d`, "main"); }); function callRestart() { const doRestartCmd = `docker compose -f ${inContainer( restartComposeName )} up --exit-code-from ${restartContainerName}`; - return runUntilExited( - `docker exec ${mainContainerName} /bin/sh -c "${doRestartCmd}"`, - "call-restart" - ); + return runUntilExited(`docker exec ${mainContainerName} /bin/sh -c "${doRestartCmd}"`, "call-restart"); } it("Should restart itself", async () => { @@ -150,10 +129,7 @@ exit $UPEXIT console.log(`Launched prev, ID: ${prev.containerId}`); const restartCallExit = await callRestart(); - console.log( - `EXITED: ${mainContainerName} ${prev.containerId}`, - restartCallExit - ); + console.log(`EXITED: ${mainContainerName} ${prev.containerId}`, restartCallExit); expect(restartCallExit.error.code).to.equal( 137, "Restart call should exit with 137, killed by docker with SIGKILL" @@ -163,14 +139,9 @@ exit $UPEXIT const restart = await listContainer({ containerName: restartContainerName }); - console.log( - `Restart container ${restart.state}, ID: ${restart.containerId}` - ); + console.log(`Restart container ${restart.state}, ID: ${restart.containerId}`); const restartExit = await logUntilExited(restart.containerId, "restart"); - console.log( - `${restartContainerName} ${restart.containerId} exited`, - restartExit - ); + console.log(`${restartContainerName} ${restart.containerId} exited`, restartExit); // Query the next container that should be running const next = await listContainer({ containerName: mainContainerName }); @@ -180,18 +151,10 @@ exit $UPEXIT prev.containerId, `${mainContainerName} prev and next containers should NOT have the same ID` ); - assert.strictEqual( - next.state, - "running", - "Next container should be running" - ); + assert.strictEqual(next.state, "running", "Next container should be running"); // Make sure the next container has been updated - assert.strictEqual( - await getVersion(next.containerId), - versionNext, - "Final container should have the next version" - ); + assert.strictEqual(await getVersion(next.containerId), versionNext, "Final container should have the next version"); const restartInspect = await dockerContainerInspect(restartContainerName); @@ -236,10 +199,7 @@ exit $UPEXIT // The exit code should be 137 which means killed by docker with SIGKILL (kill -9) `kill -9 (128 + 9 = 137)` // https://success.docker.com/article/what-causes-a-container-to-exit-with-code-137 const restartCallExit = await callRestart(); - console.log( - `EXITED: ${mainContainerName} ${prev.containerId}`, - restartCallExit - ); + console.log(`EXITED: ${mainContainerName} ${prev.containerId}`, restartCallExit); expect(restartCallExit.error.code).to.equal( 137, "Restart call should exit with 137, killed by docker with SIGKILL" @@ -249,22 +209,15 @@ exit $UPEXIT const restart = await listContainer({ containerName: restartContainerName }); - console.log( - `Restart container ${restart.state}, ID: ${restart.containerId}` - ); + console.log(`Restart container ${restart.state}, ID: ${restart.containerId}`); const restartExit = await logUntilExited(restart.containerId, "restart"); - console.log( - `EXITED ${restartContainerName} ${restart.containerId}`, - restartExit - ); + console.log(`EXITED ${restartContainerName} ${restart.containerId}`, restartExit); // Query the next container that should be running // Because it had failed to be brought up, it will be the temp renamed container // cea8fecfa936_DAppNodeTest-main-service const [next] = await listPackageContainers(); - console.log( - `Next container ${next.containerName} ${next.state}, ID: ${next.containerId}` - ); + console.log(`Next container ${next.containerName} ${next.state}, ID: ${next.containerId}`); assert.strictEqual( next.containerName, "/" + mainContainerName, @@ -275,11 +228,7 @@ exit $UPEXIT prev.containerId, `${mainContainerName} prev and next containers should have the same ID ${prev.containerId}` ); - assert.strictEqual( - next.state, - "running", - "Next container should be running" - ); + assert.strictEqual(next.state, "running", "Next container should be running"); assert.strictEqual( await getVersion(next.containerId), @@ -314,16 +263,10 @@ exit $UPEXIT // Attach to prev container to see logs and know when it stops const restartCallExit = await callRestart(); - console.log( - `EXITED: ${mainContainerName} ${prev.containerId}`, - restartCallExit - ); + console.log(`EXITED: ${mainContainerName} ${prev.containerId}`, restartCallExit); // The restart call should have failed for a parsing error - expect(restartCallExit.error.code).to.equal( - 1, - "Wrong exit code in restart call" - ); + expect(restartCallExit.error.code).to.equal(1, "Wrong exit code in restart call"); expect(restartCallExit.stdout).to.include( `needs to be an object not '<type 'str'>'`, "restart call stdou should include a parsing error message" @@ -333,9 +276,7 @@ exit $UPEXIT const restart = await listContainer({ containerName: restartContainerName }); - console.log( - `Restart container ${restart.state}, ID: ${restart.containerId}` - ); + console.log(`Restart container ${restart.state}, ID: ${restart.containerId}`); assert.strictEqual( restart.state, "exited", @@ -343,20 +284,14 @@ exit $UPEXIT ); // Query the next container that should be running - const next = await retry(() => - listContainer({ containerName: mainContainerName }) - ); + const next = await retry(() => listContainer({ containerName: mainContainerName })); console.log(`Next container ${next.state}, ID: ${next.containerId}`); assert.strictEqual( next.containerId, prev.containerId, `${mainContainerName} prev and next containers should have the same ID ${prev.containerId}` ); - assert.strictEqual( - next.state, - "running", - "Next container should be running" - ); + assert.strictEqual(next.state, "running", "Next container should be running"); assert.strictEqual( await getVersion(next.containerId), @@ -414,9 +349,7 @@ function writeCompose({ * @param id */ async function getVersion(id: string) { - return await shell( - `docker inspect --format '{{ index .Config.Labels "${labelVersion}"}}' ${id}` - ); + return await shell(`docker inspect --format '{{ index .Config.Labels "${labelVersion}"}}' ${id}`); } interface ProcessResult { @@ -430,11 +363,8 @@ interface ProcessResult { * Await for the process to exit * @param id */ -async function runUntilExited( - cmd: string, - tag: string -): Promise<ProcessResult> { - return new Promise(resolve => { +async function runUntilExited(cmd: string, tag: string): Promise<ProcessResult> { + return new Promise((resolve) => { const proc = child.exec(cmd, (error, stdout, stderr) => { resolve({ error, stdout, stderr } as ProcessResult); }); @@ -449,7 +379,7 @@ function logWithTag(tag: string) { chunk .toString() .split("\n") - .map(line => `${tag} | ${line}`) + .map((line) => `${tag} | ${line}`) .join("\n") ); }; diff --git a/packages/dappmanager/test/unit/ethForward/decode.test.ts b/packages/dappmanager/test/unit/ethForward/decode.test.ts index a358f0dd3..ed8d87f5e 100644 --- a/packages/dappmanager/test/unit/ethForward/decode.test.ts +++ b/packages/dappmanager/test/unit/ethForward/decode.test.ts @@ -14,16 +14,13 @@ interface TestCases { describe("ethForward > util > decode", () => { describe("decodeContentHash", () => { const contentHashes: TestCases = { - "0xe30101701220aa4396c7e54ce85638b1f5a66f83b0b698a80e6ca3511ccc7e8551c6ae89ab40": - { - location: "ipfs", - hash: "QmZoHo1wi4G9VHX6xLmMBRdFpdHMkHnsqVXqV6Vsng9m8j" - } + "0xe30101701220aa4396c7e54ce85638b1f5a66f83b0b698a80e6ca3511ccc7e8551c6ae89ab40": { + location: "ipfs", + hash: "QmZoHo1wi4G9VHX6xLmMBRdFpdHMkHnsqVXqV6Vsng9m8j" + } }; - for (const [contentHashEncoded, expectedContent] of Object.entries( - contentHashes - )) { + for (const [contentHashEncoded, expectedContent] of Object.entries(contentHashes)) { it(`should decode ${contentHashEncoded}`, async () => { const content = decodeContentHash(contentHashEncoded); expect(content).to.deep.equal(expectedContent, "Wrong content"); diff --git a/packages/dappmanager/test/unit/ethForward/resolveDomain.test.int.ts b/packages/dappmanager/test/unit/ethForward/resolveDomain.test.int.ts index 0a7dbe5b1..655cbfd30 100644 --- a/packages/dappmanager/test/unit/ethForward/resolveDomain.test.int.ts +++ b/packages/dappmanager/test/unit/ethForward/resolveDomain.test.int.ts @@ -1,12 +1,7 @@ import "mocha"; import { expect } from "chai"; import { ethers } from "ethers"; -import { - Content, - EthForwardError, - EthForwardErrorCode, - Location -} from "../../../src/api/middlewares/ethForward/types.js"; +import { Content, EthForwardError, EthForwardErrorCode } from "../../../src/api/middlewares/ethForward/types.js"; import { resolveDomain } from "../../../src/api/middlewares/ethForward/resolveDomain.js"; /** @@ -19,8 +14,6 @@ import { resolveDomain } from "../../../src/api/middlewares/ethForward/resolveDo */ describe("ethForward > resolveDomain", () => { - const provider = new ethers.InfuraProvider(); - describe("resolveDomain with stable mainnet domains", () => { const ensDomains: { [hash: string]: Content } = { "mycrypto.dappnode.eth": { diff --git a/packages/dappmanager/test/unit/modules/globalEnvs.test.ts b/packages/dappmanager/test/unit/modules/globalEnvs.test.ts index d929b0ad1..26431e5c5 100644 --- a/packages/dappmanager/test/unit/modules/globalEnvs.test.ts +++ b/packages/dappmanager/test/unit/modules/globalEnvs.test.ts @@ -2,10 +2,7 @@ import "mocha"; import { expect } from "chai"; import fs from "fs"; import { createTestDir, cleanTestDir } from "../../testUtils.js"; -import { - computeGlobalEnvsFromDb, - writeGlobalEnvsToEnvFile -} from "@dappnode/db"; +import { computeGlobalEnvsFromDb, writeGlobalEnvsToEnvFile } from "@dappnode/db"; import { createGlobalEnvsEnvFile } from "@dappnode/utils"; import { params } from "@dappnode/params"; diff --git a/packages/dappmanager/test/unit/modules/passwordManager.test.ts b/packages/dappmanager/test/unit/modules/passwordManager.test.ts index 00ee472c3..06679d15e 100644 --- a/packages/dappmanager/test/unit/modules/passwordManager.test.ts +++ b/packages/dappmanager/test/unit/modules/passwordManager.test.ts @@ -2,14 +2,10 @@ import "mocha"; import { expect } from "chai"; import rewiremock from "rewiremock/node.js"; -/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ -function getPasswordManager( - shellMock: (cmd: string | string[]) => Promise<string>, - image: string -) { +function getPasswordManager(shellMock: (cmd: string | string[]) => Promise<string>, image: string) { return rewiremock.around( () => import("../../../src/calls/passwordManager.js"), - mock => { + (mock) => { mock(() => import("@dappnode/utils")) .with({ shell: shellMock }) .toBeUsed(); @@ -26,13 +22,10 @@ describe.skip("Module > passwordManager", () => { const passwordHash = `dappnode:$6$insecur3$rnEv9Amdjn3ctXxPYOlzj/cwvLT43GjWzkPECIHNqd8Vvza5bMG8QqMwEIBKYqnj609D.4ngi4qlmt29dLE.71:18004:0:99999:7:::`; it("Should check if the password is secure", async () => { - const { isPasswordSecure } = await getPasswordManager( - async (cmd: string | string[]) => { - if (cmd == grepCommand) return passwordHash; - throw Error(`Unknown command ${cmd}`); - }, - image - ); + const { isPasswordSecure } = await getPasswordManager(async (cmd: string | string[]) => { + if (cmd == grepCommand) return passwordHash; + throw Error(`Unknown command ${cmd}`); + }, image); const isSecure = await isPasswordSecure(); expect(isSecure).to.equal(false); @@ -40,15 +33,12 @@ describe.skip("Module > passwordManager", () => { it("Should change the password", async () => { let lastCmd; - const { changePassword } = await getPasswordManager( - async (cmd: string | string[]) => { - lastCmd = cmd; - if (cmd == grepCommand) return passwordHash; - if (cmd.includes("chpasswd")) return ""; - throw Error(`Unknown command ${cmd}`); - }, - image - ); + const { changePassword } = await getPasswordManager(async (cmd: string | string[]) => { + lastCmd = cmd; + if (cmd == grepCommand) return passwordHash; + if (cmd.includes("chpasswd")) return ""; + throw Error(`Unknown command ${cmd}`); + }, image); const newPassword = "secret-password"; await changePassword(newPassword); @@ -58,13 +48,10 @@ describe.skip("Module > passwordManager", () => { }); it("Should block changing the password when it's secure", async () => { - const { changePassword } = await getPasswordManager( - async (cmd: string | string[]) => { - if (cmd == grepCommand) return ""; - throw Error(`Unknown command ${cmd}`); - }, - image - ); + const { changePassword } = await getPasswordManager(async (cmd: string | string[]) => { + if (cmd == grepCommand) return ""; + throw Error(`Unknown command ${cmd}`); + }, image); let errorMessage = "---did not throw---"; try { @@ -73,19 +60,14 @@ describe.skip("Module > passwordManager", () => { errorMessage = e.message; } - expect(errorMessage).to.equal( - `The password can only be changed if it's the insecure default` - ); + expect(errorMessage).to.equal(`The password can only be changed if it's the insecure default`); }); it("Should block changing the password if the input contains problematic characters", async () => { - const { changePassword } = await getPasswordManager( - async (cmd: string | string[]) => { - if (cmd == grepCommand) return passwordHash; - throw Error(`Unknown command ${cmd}`); - }, - image - ); + const { changePassword } = await getPasswordManager(async (cmd: string | string[]) => { + if (cmd == grepCommand) return passwordHash; + throw Error(`Unknown command ${cmd}`); + }, image); let errorMessage = "---did not throw---"; try { @@ -94,8 +76,6 @@ describe.skip("Module > passwordManager", () => { errorMessage = e.message; } - expect(errorMessage).to.equal( - `Password must contain only ASCII characters and not the ' character` - ); + expect(errorMessage).to.equal(`Password must contain only ASCII characters and not the ' character`); }); }); diff --git a/packages/dappmanager/test/unit/utils/autoUpdateHelper.test.ts b/packages/dappmanager/test/unit/utils/autoUpdateHelper.test.ts index 7b5329940..e4300135c 100644 --- a/packages/dappmanager/test/unit/utils/autoUpdateHelper.test.ts +++ b/packages/dappmanager/test/unit/utils/autoUpdateHelper.test.ts @@ -37,10 +37,7 @@ describe("Util: autoUpdateHelper", () => { beforeEach("Make sure the autosettings are restarted", async () => { clearDbs(); - expect(db.autoUpdateSettings.get()).to.deep.equal( - {}, - "autoUpdateSettings are not empty" - ); + expect(db.autoUpdateSettings.get()).to.deep.equal({}, "autoUpdateSettings are not empty"); }); describe("Auto update settings", () => { @@ -97,10 +94,7 @@ describe("Util: autoUpdateHelper", () => { it("Should NOT allow the update if the delay is NOT completed", () => { const version = "0.2.6"; const timestamp = Date.now(); - expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal( - false, - "Should not allow on first check" - ); + expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal(false, "Should not allow on first check"); expect(db.autoUpdatePending.get()).to.deep.equal( { @@ -123,10 +117,7 @@ describe("Util: autoUpdateHelper", () => { it("Should allow the update if the delay is completed", () => { const version = "0.2.6"; const timestamp = Date.now() - (updateDelay + 1); - expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal( - false, - "Should not allow on first check" - ); + expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal(false, "Should not allow on first check"); expect(db.autoUpdatePending.get()).to.deep.equal( { @@ -157,10 +148,7 @@ describe("Util: autoUpdateHelper", () => { const version2 = "0.2.5"; const timestamp2 = Date.now() - 2 * updateDelay; - expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal( - false, - "Should not allow on first check" - ); + expect(isUpdateDelayCompleted(dnpName, version, timestamp)).to.equal(false, "Should not allow on first check"); expect(db.autoUpdatePending.get()).to.deep.equal( { @@ -174,10 +162,7 @@ describe("Util: autoUpdateHelper", () => { "Should have one entry with firstSeen set" ); - expect(isUpdateDelayCompleted(dnpName, version2, timestamp2)).to.equal( - false, - "Should not allow on first check" - ); + expect(isUpdateDelayCompleted(dnpName, version2, timestamp2)).to.equal(false, "Should not allow on first check"); expect(db.autoUpdatePending.get()).to.deep.equal( { @@ -486,10 +471,7 @@ describe("Util: autoUpdateHelper", () => { ]); const microDelay = 20; - expect(getCoreFeedbackMessage(currentCorePackagesBefore)).to.deep.equal( - {}, - "1. Should be empty" - ); + expect(getCoreFeedbackMessage(currentCorePackagesBefore)).to.deep.equal({}, "1. Should be empty"); const timestampIsUpdated = Date.now() - (updateDelay - microDelay); isUpdateDelayCompleted(coreDnpName, nextVersionId, timestampIsUpdated); @@ -521,13 +503,8 @@ describe("Util: autoUpdateHelper", () => { "3B. Should be completed" ); - const timestampIsCompletedNext = - Date.now() - (24 * 60 * 60 * 1000 - microDelay); - isUpdateDelayCompleted( - coreDnpName, - nextVersion2Id, - timestampIsCompletedNext - ); + const timestampIsCompletedNext = Date.now() - (24 * 60 * 60 * 1000 - microDelay); + isUpdateDelayCompleted(coreDnpName, nextVersion2Id, timestampIsCompletedNext); expect(getCoreFeedbackMessage(currentCorePackagesAfter)).to.deep.equal( { scheduled: timestampIsCompletedNext + updateDelay }, @@ -565,10 +542,7 @@ describe("Util: autoUpdateHelper", () => { clearCompletedCoreUpdatesIfAny(currentCorePackages, timestamp); - expect(db.autoUpdatePending.get()).to.deep.equal( - {}, - "Pending version should be removed" - ); + expect(db.autoUpdatePending.get()).to.deep.equal({}, "Pending version should be removed"); expect(db.autoUpdateRegistry.get()).to.deep.equal( { @@ -620,10 +594,7 @@ describe("Util: autoUpdateHelper", () => { "Pending version should still be there" ); - expect(db.autoUpdateRegistry.get()).to.deep.equal( - {}, - "Registry should be empty, no new version added" - ); + expect(db.autoUpdateRegistry.get()).to.deep.equal({}, "Registry should be empty, no new version added"); }); }); diff --git a/packages/dappmanager/test/unit/utils/sign.test.ts b/packages/dappmanager/test/unit/utils/sign.test.ts index 418264407..ea67c46de 100644 --- a/packages/dappmanager/test/unit/utils/sign.test.ts +++ b/packages/dappmanager/test/unit/utils/sign.test.ts @@ -1,11 +1,7 @@ import "mocha"; import { expect } from "chai"; import { ethers } from "ethers"; -import { - prepareMessageFromPackage, - signDataFromPackage, - hashMessage -} from "../../../src/utils/index.js"; +import { prepareMessageFromPackage, signDataFromPackage, hashMessage } from "../../../src/utils/index.js"; describe("Util / sign", () => { describe("prepareMessageFromPackage", () => { @@ -48,10 +44,7 @@ test.dnp.dappnode.eth const digest = hashMessage(message); const address = ethers.recoverAddress(digest, signature); - expect(address).to.deep.equal( - wallet.address, - "Recovered address does not match" - ); + expect(address).to.deep.equal(wallet.address, "Recovered address does not match"); }); }); }); diff --git a/packages/db/.eslintignore b/packages/db/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/db/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/db/.eslintrc.cjs b/packages/db/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/db/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/db/package.json b/packages/db/package.json index 35062370b..08f194929 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/dockerapi": "workspace:^0.1.0", diff --git a/packages/db/src/autoUpdateSettings.ts b/packages/db/src/autoUpdateSettings.ts index faf34f8cd..ac11a6706 100644 --- a/packages/db/src/autoUpdateSettings.ts +++ b/packages/db/src/autoUpdateSettings.ts @@ -1,9 +1,5 @@ import { dbCache, dbMain } from "./dbFactory.js"; -import { - AutoUpdateSettings, - AutoUpdatePending, - AutoUpdateRegistry, -} from "@dappnode/types"; +import { AutoUpdateSettings, AutoUpdatePending, AutoUpdateRegistry } from "@dappnode/types"; export const AUTO_UPDATE_SETTINGS = "auto-update-settings"; const AUTO_UPDATE_REGISTRY = "auto-update-registry"; @@ -11,17 +7,8 @@ const AUTO_UPDATE_PENDING = "auto-update-pending"; // auto-update-settings -export const autoUpdateSettings = dbMain.staticKey<AutoUpdateSettings>( - AUTO_UPDATE_SETTINGS, - {} -); +export const autoUpdateSettings = dbMain.staticKey<AutoUpdateSettings>(AUTO_UPDATE_SETTINGS, {}); -export const autoUpdatePending = dbCache.staticKey<AutoUpdatePending>( - AUTO_UPDATE_REGISTRY, - {} -); +export const autoUpdatePending = dbCache.staticKey<AutoUpdatePending>(AUTO_UPDATE_REGISTRY, {}); -export const autoUpdateRegistry = dbCache.staticKey<AutoUpdateRegistry>( - AUTO_UPDATE_PENDING, - {} -); +export const autoUpdateRegistry = dbCache.staticKey<AutoUpdateRegistry>(AUTO_UPDATE_PENDING, {}); diff --git a/packages/db/src/coreUpdate.ts b/packages/db/src/coreUpdate.ts index de01f2ba3..1ffdc6425 100644 --- a/packages/db/src/coreUpdate.ts +++ b/packages/db/src/coreUpdate.ts @@ -4,9 +4,7 @@ import { InstallPackageData, InstallPackageDataPaths } from "@dappnode/types"; const CORE_UPDATE_PACKAGES_DATA = "core-update-packages-data"; -const _coreUpdatePackagesData = dbCache.staticKey< - InstallPackageDataPaths[] | null ->(CORE_UPDATE_PACKAGES_DATA, null); +const _coreUpdatePackagesData = dbCache.staticKey<InstallPackageDataPaths[] | null>(CORE_UPDATE_PACKAGES_DATA, null); /** * Store packages install data to finalize a core update after the DAPPMANAGER @@ -15,9 +13,7 @@ const _coreUpdatePackagesData = dbCache.staticKey< */ export const coreUpdatePackagesData = { get: _coreUpdatePackagesData.get, - set: ( - packagesData: (InstallPackageData | InstallPackageDataPaths)[] | null - ): void => + set: (packagesData: (InstallPackageData | InstallPackageDataPaths)[] | null): void => _coreUpdatePackagesData.set( packagesData ? packagesData.map( @@ -32,9 +28,9 @@ export const coreUpdatePackagesData = { "imagePath", "isUpdate", "dockerTimeout", - "containersStatus", + "containersStatus" ]) ) : packagesData - ), + ) }; diff --git a/packages/db/src/dbFactory.ts b/packages/db/src/dbFactory.ts index 7746900bd..45b51db68 100644 --- a/packages/db/src/dbFactory.ts +++ b/packages/db/src/dbFactory.ts @@ -14,17 +14,12 @@ export const dbMain = dbFactory(params.DB_MAIN_PATH); */ export const dbCache = dbFactory(params.DB_CACHE_PATH); -export function dbFactory( - dbPath: string -): { - staticKey: <T>( - key: string, - defaultValue: T - ) => { get: () => T; set: (value: T) => void }; +export function dbFactory(dbPath: string): { + staticKey: <T>(key: string, defaultValue: T) => { get: () => T; set: (value: T) => void }; indexedByKey: <V, K>({ rootKey, getKey, - validate, + validate }: { rootKey: string; getKey: (keyArg: K) => string; @@ -54,17 +49,14 @@ export function dbFactory( * Factory methods */ - function staticKey<T>( - key: string, - defaultValue: T - ): { get: () => T; set: (value: T) => void } { + function staticKey<T>(key: string, defaultValue: T): { get: () => T; set: (value: T) => void } { return { get: (): T => jsonFileDb.read()[key] ?? defaultValue, set: (newValue: T): void => { const all = jsonFileDb.read(); all[key] = newValue; jsonFileDb.write(all); - }, + } }; } @@ -76,7 +68,7 @@ export function dbFactory( function indexedByKey<V, K>({ rootKey, getKey, - validate, + validate }: { rootKey: string; getKey: (keyArg: K) => string; @@ -89,8 +81,7 @@ export function dbFactory( set: (keyArg: K, value: V) => void; remove: (keyArg: K) => void; } { - const getRoot = (): { [key: string]: V } => - jsonFileDb.read()[rootKey] || {}; + const getRoot = (): { [key: string]: V } => jsonFileDb.read()[rootKey] || {}; return { getAll: getRoot, @@ -115,12 +106,12 @@ export function dbFactory( delete root[getKey(keyArg)]; all[rootKey] = root; jsonFileDb.write(all); - }, + } }; } // DB returns are of unkown type. External methods below are typed - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + // function getEntireDb(): any { // return Object.freeze(JSON.parse(JSON.stringify(db.getState()))); // } @@ -128,6 +119,6 @@ export function dbFactory( return { staticKey, indexedByKey, - clearDb, + clearDb }; } diff --git a/packages/db/src/dyndns.ts b/packages/db/src/dyndns.ts index af286788a..f37ec363b 100644 --- a/packages/db/src/dyndns.ts +++ b/packages/db/src/dyndns.ts @@ -7,22 +7,14 @@ const DOMAIN = "domain"; const DYNDNS_IDENTITY = "dyndns-identity"; const STATIC_IP = "static-ip"; -export const publicIp = interceptGlobalEnvOnSet( - dbMain.staticKey<string>(PUBLIC_IP, ""), - Object.keys({ PUBLIC_IP })[0] -); +export const publicIp = interceptGlobalEnvOnSet(dbMain.staticKey<string>(PUBLIC_IP, ""), Object.keys({ PUBLIC_IP })[0]); -export const domain = interceptGlobalEnvOnSet( - dbMain.staticKey<string>(DOMAIN, ""), - Object.keys({ DOMAIN })[0] -); +export const domain = interceptGlobalEnvOnSet(dbMain.staticKey<string>(DOMAIN, ""), Object.keys({ DOMAIN })[0]); -export const dyndnsIdentity = dbMain.staticKey<IdentityInterface>( - DYNDNS_IDENTITY, - { address: "", privateKey: "", publicKey: "" } -); +export const dyndnsIdentity = dbMain.staticKey<IdentityInterface>(DYNDNS_IDENTITY, { + address: "", + privateKey: "", + publicKey: "" +}); -export const staticIp = interceptGlobalEnvOnSet( - dbMain.staticKey<string>(STATIC_IP, ""), - Object.keys({ STATIC_IP })[0] -); +export const staticIp = interceptGlobalEnvOnSet(dbMain.staticKey<string>(STATIC_IP, ""), Object.keys({ STATIC_IP })[0]); diff --git a/packages/db/src/ethClient.ts b/packages/db/src/ethClient.ts index f51568fc3..75fbfe068 100644 --- a/packages/db/src/ethClient.ts +++ b/packages/db/src/ethClient.ts @@ -6,7 +6,7 @@ import { EthClientFallback, EthClientStatus, EthClientSyncedNotificationStatus, - EthClientInstallStatus, + EthClientInstallStatus } from "@dappnode/types"; // User chosen properties @@ -19,24 +19,16 @@ const ETH_CONS_CLIENT_INSTALL_STATUS = "eth-cons-client-install-status"; const ETH_EXEC_CLIENT_STATUS = "eth-exec-client-status"; const ETH_CONS_CLIENT_STATUS = "eth-cons-client-status"; // Cached temp status -const ETH_CLIENT_SYNCED_NOTIFICATION_STATUS = - "eth-client-synced-notification-status"; +const ETH_CLIENT_SYNCED_NOTIFICATION_STATUS = "eth-client-synced-notification-status"; -export const ethRemoteRpc = dbMain.staticKey<string>( - ETH_REMOTE_RPC, - params.ETH_MAINNET_RPC_URL_REMOTE -); +export const ethRemoteRpc = dbMain.staticKey<string>(ETH_REMOTE_RPC, params.ETH_MAINNET_RPC_URL_REMOTE); /** * New introduced in dappmanager v0.2.54 */ -export const ethClientRemote = interceptOnSet( - dbMain.staticKey<EthClientRemote | null>(ETH_CLIENT_REMOTE, null) -); +export const ethClientRemote = interceptOnSet(dbMain.staticKey<EthClientRemote | null>(ETH_CLIENT_REMOTE, null)); -export const ethClientFallback = interceptOnSet( - dbMain.staticKey<EthClientFallback>(ETH_CLIENT_FALLBACK, "off") -); +export const ethClientFallback = interceptOnSet(dbMain.staticKey<EthClientFallback>(ETH_CLIENT_FALLBACK, "off")); // Cached status, not critical @@ -47,8 +39,7 @@ export const ethExecClientInstallStatus = interceptOnSet( dbCache.indexedByKey<EthClientInstallStatus, string>({ rootKey: ETH_EXEC_CLIENT_INSTALL_STATUS, getKey: (target) => target, - validate: (id, installStatus) => - typeof id === "string" && typeof installStatus === "object", + validate: (id, installStatus) => typeof id === "string" && typeof installStatus === "object" }) ); @@ -59,8 +50,7 @@ export const ethConsClientInstallStatus = interceptOnSet( dbCache.indexedByKey<EthClientInstallStatus, string>({ rootKey: ETH_CONS_CLIENT_INSTALL_STATUS, getKey: (target) => target, - validate: (id, installStatus) => - typeof id === "string" && typeof installStatus === "object", + validate: (id, installStatus) => typeof id === "string" && typeof installStatus === "object" }) ); @@ -71,8 +61,7 @@ export const ethExecClientStatus = interceptOnSet( dbCache.indexedByKey<EthClientStatus, string>({ rootKey: ETH_EXEC_CLIENT_STATUS, getKey: (target) => target, - validate: (id, status) => - typeof id === "string" && typeof status === "object", + validate: (id, status) => typeof id === "string" && typeof status === "object" }) ); @@ -83,8 +72,7 @@ export const ethConsClientStatus = interceptOnSet( dbCache.indexedByKey<EthClientStatus, string>({ rootKey: ETH_CONS_CLIENT_STATUS, getKey: (target) => target, - validate: (id, status) => - typeof id === "string" && typeof status === "object", + validate: (id, status) => typeof id === "string" && typeof status === "object" }) ); @@ -104,15 +92,14 @@ function interceptOnSet< set: function (...args: any[]): void { dbSetter.set(...args); eventBus.requestSystemInfo.emit(); - }, + } }; } /** * Cache the status of the eth client install loop */ -export const ethClientSyncedNotificationStatus = - dbCache.staticKey<EthClientSyncedNotificationStatus>( - ETH_CLIENT_SYNCED_NOTIFICATION_STATUS, - null - ); +export const ethClientSyncedNotificationStatus = dbCache.staticKey<EthClientSyncedNotificationStatus>( + ETH_CLIENT_SYNCED_NOTIFICATION_STATUS, + null +); diff --git a/packages/db/src/ethicalMetrics.ts b/packages/db/src/ethicalMetrics.ts index 0112dc522..bd957d7e6 100644 --- a/packages/db/src/ethicalMetrics.ts +++ b/packages/db/src/ethicalMetrics.ts @@ -7,19 +7,10 @@ const NOTIFICATIONS = "notifications"; const ETHICAL_METRICS_MAIL = "ethical-metrics-mail"; const ETHICAL_METRICS_STATUS = "ethical-metrics-status"; -export const notifications = dbMain.staticKey<EthicalMetricsConfig | null>( - NOTIFICATIONS, - null -); +export const notifications = dbMain.staticKey<EthicalMetricsConfig | null>(NOTIFICATIONS, null); // Deprecated in favor of "notifications" -export const ethicalMetricsMail = dbMain.staticKey<string | null>( - ETHICAL_METRICS_MAIL, - null -); +export const ethicalMetricsMail = dbMain.staticKey<string | null>(ETHICAL_METRICS_MAIL, null); // Deprecated in favor of "notifications" -export const ethicalMetricsStatus = dbMain.staticKey<boolean>( - ETHICAL_METRICS_STATUS, - false -); +export const ethicalMetricsStatus = dbMain.staticKey<boolean>(ETHICAL_METRICS_STATUS, false); diff --git a/packages/db/src/fileTransferPath.ts b/packages/db/src/fileTransferPath.ts index bccef0948..27d14babd 100644 --- a/packages/db/src/fileTransferPath.ts +++ b/packages/db/src/fileTransferPath.ts @@ -4,6 +4,6 @@ const FILE_TRANSFER_PATH = "file-transfer-path"; export const fileTransferPath = dbCache.indexedByKey<string, string>({ rootKey: FILE_TRANSFER_PATH, - getKey: fileId => fileId, - validate: filePath => typeof filePath === "string" + getKey: (fileId) => fileId, + validate: (filePath) => typeof filePath === "string" }); diff --git a/packages/db/src/globalEnvs.ts b/packages/db/src/globalEnvs.ts index 0d35439e4..6701526c1 100644 --- a/packages/db/src/globalEnvs.ts +++ b/packages/db/src/globalEnvs.ts @@ -17,7 +17,7 @@ import { mevBoostPrater, mevBoostHolesky, consensusClientHolesky, - executionClientHolesky, + executionClientHolesky } from "./stakerConfig.js"; import { serverName } from "./system.js"; import { upnpAvailable } from "./upnp.js"; @@ -61,7 +61,7 @@ export function computeGlobalEnvsFromDb<B extends boolean>( [`${prefix}EXECUTION_CLIENT_LUKSO`]: executionClientLukso.get(), [`${prefix}MEVBOOST_LUKSO`]: mevBoostLukso.get(), [`${prefix}OP_ENABLE_HISTORICAL_RPC`]: opEnableHistoricalRpc.get(), - [`${prefix}OP_EXECUTION_CLIENT`]: opExecutionClient.get(), + [`${prefix}OP_EXECUTION_CLIENT`]: opExecutionClient.get() // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; } diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index f98df2cef..d57bf010e 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -21,10 +21,7 @@ export * from "./stakerConfig.js"; // Aditional low levels methods import { dbCache, dbMain } from "./dbFactory.js"; // Additional envs methods -export { - computeGlobalEnvsFromDb, - writeGlobalEnvsToEnvFile, -} from "./globalEnvs.js"; +export { computeGlobalEnvsFromDb, writeGlobalEnvsToEnvFile } from "./globalEnvs.js"; /** WARNING! Only clear cache DB if necessary */ export const clearCacheDb = dbCache.clearDb; diff --git a/packages/db/src/intercepGlobalEnvOnSet.ts b/packages/db/src/intercepGlobalEnvOnSet.ts index c6d7a78aa..8d8027b46 100644 --- a/packages/db/src/intercepGlobalEnvOnSet.ts +++ b/packages/db/src/intercepGlobalEnvOnSet.ts @@ -24,10 +24,9 @@ export function interceptGlobalEnvOnSet<T, U>( return { ...dbSetter, - set: async function(globEnvValue: U): Promise<void> { + set: async function (globEnvValue: U): Promise<void> { // Must be with prefix _DAPPNODE_GLOBAL_ - if (!globEnvKey.includes(params.GLOBAL_ENVS_PREFIX)) - globEnvKey = `${params.GLOBAL_ENVS_PREFIX}${globEnvKey}`; + if (!globEnvKey.includes(params.GLOBAL_ENVS_PREFIX)) globEnvKey = `${params.GLOBAL_ENVS_PREFIX}${globEnvKey}`; dbSetter.set(globEnvValue); // Update the global env file @@ -36,12 +35,10 @@ export function interceptGlobalEnvOnSet<T, U>( try { // Only attempt to update packages if the global env is not nullish if (globEnvValue !== null && globEnvValue !== undefined) - await updatePkgsWithGlobalEnvs(globEnvKey, globEnvValue as any); + await updatePkgsWithGlobalEnvs(globEnvKey, globEnvValue as string); } catch (err) { - logs.error( - `Error updating global env ${globEnvKey} to ${globEnvValue} in all dappnode packages: ${err}` - ); + logs.error(`Error updating global env ${globEnvKey} to ${globEnvValue} in all dappnode packages: ${err}`); } - }, + } }; } diff --git a/packages/db/src/ipfsClient.ts b/packages/db/src/ipfsClient.ts index c98dc3668..5912ff2ba 100644 --- a/packages/db/src/ipfsClient.ts +++ b/packages/db/src/ipfsClient.ts @@ -6,12 +6,6 @@ import { params } from "@dappnode/params"; const IPFS_CLIENT_TARGET = "ipfs-client-target"; const IPFS_GATEWAY = "ipfs-gateway"; -export const ipfsClientTarget = dbMain.staticKey<IpfsClientTarget>( - IPFS_CLIENT_TARGET, - IpfsClientTarget.local -); +export const ipfsClientTarget = dbMain.staticKey<IpfsClientTarget>(IPFS_CLIENT_TARGET, IpfsClientTarget.local); -export const ipfsGateway = dbMain.staticKey<string>( - IPFS_GATEWAY, - params.IPFS_REMOTE -); +export const ipfsGateway = dbMain.staticKey<string>(IPFS_GATEWAY, params.IPFS_REMOTE); diff --git a/packages/db/src/network.ts b/packages/db/src/network.ts index 448df7b24..f306de2ae 100644 --- a/packages/db/src/network.ts +++ b/packages/db/src/network.ts @@ -12,16 +12,10 @@ export const noNatLoopback = interceptGlobalEnvOnSet( Object.keys({ NO_NAT_LOOPBACK })[0] ); export const doubleNat = dbMain.staticKey<boolean>(DOUBLE_NAT, false); -export const alertToOpenPorts = dbMain.staticKey<boolean>( - ALERT_TO_OPEN_PORTS, - false -); +export const alertToOpenPorts = dbMain.staticKey<boolean>(ALERT_TO_OPEN_PORTS, false); export const internalIp = interceptGlobalEnvOnSet( dbMain.staticKey<string>(INTERNAL_IP, ""), Object.keys({ INTERNAL_IP })[0] ); -export const avahiPublishCmdShouldNotRun = dbMain.staticKey<boolean>( - AVAHI_SHOULD_BE_DISABLED, - false -); +export const avahiPublishCmdShouldNotRun = dbMain.staticKey<boolean>(AVAHI_SHOULD_BE_DISABLED, false); diff --git a/packages/db/src/notification.ts b/packages/db/src/notification.ts index cff35f313..2553dea88 100644 --- a/packages/db/src/notification.ts +++ b/packages/db/src/notification.ts @@ -5,16 +5,13 @@ import { PackageNotificationDb, PackageNotification } from "@dappnode/types"; const NOTIFICATION = "notification"; const NOTIFICATION_LAST_EMITTED_VERSION = "notification-last-emitted-version"; -export const notification = dbCache.indexedByKey<PackageNotificationDb, string>( - { - rootKey: NOTIFICATION, - // The `update-available-${dnpName}-${newVersion}` included dots, - // so for backwards compatibility they must be stripped - getKey: (id) => stripDots(id), - validate: (id, notification) => - typeof id === "string" && typeof notification === "object", - } -); +export const notification = dbCache.indexedByKey<PackageNotificationDb, string>({ + rootKey: NOTIFICATION, + // The `update-available-${dnpName}-${newVersion}` included dots, + // so for backwards compatibility they must be stripped + getKey: (id) => stripDots(id), + validate: (id, notification) => typeof id === "string" && typeof notification === "object" +}); export function notificationPush(id: string, n: PackageNotification): void { notification.set(id, { ...n, timestamp: Date.now(), viewed: false }); @@ -24,11 +21,8 @@ export function notificationPush(id: string, n: PackageNotification): void { * Register the last emitted version for a dnpName * Only emit notifications for versions above this one */ -export const notificationLastEmitVersion = dbCache.indexedByKey<string, string>( - { - rootKey: NOTIFICATION_LAST_EMITTED_VERSION, - getKey: (dnpName) => stripDots(dnpName), - validate: (dnpName, lastEmittedVersion) => - Boolean(dnpName) && typeof lastEmittedVersion === "string", - } -); +export const notificationLastEmitVersion = dbCache.indexedByKey<string, string>({ + rootKey: NOTIFICATION_LAST_EMITTED_VERSION, + getKey: (dnpName) => stripDots(dnpName), + validate: (dnpName, lastEmittedVersion) => Boolean(dnpName) && typeof lastEmittedVersion === "string" +}); diff --git a/packages/db/src/optimismConfig.ts b/packages/db/src/optimismConfig.ts index efc7a13c4..9ecde1d36 100644 --- a/packages/db/src/optimismConfig.ts +++ b/packages/db/src/optimismConfig.ts @@ -7,10 +7,7 @@ const OP_ENABLE_HISTORICAL_RPC = "op-enable-historical-rpc"; // Global env to be in the op-node package export const opExecutionClient = interceptGlobalEnvOnSet( - dbMain.staticKey<ExecutionClientOptimism | null | undefined>( - OP_EXECUTION_CLIENT, - null - ), + dbMain.staticKey<ExecutionClientOptimism | null | undefined>(OP_EXECUTION_CLIENT, null), Object.keys({ OP_EXECUTION_CLIENT })[0] ); diff --git a/packages/db/src/package.ts b/packages/db/src/package.ts index 1c8e45c36..766440c86 100644 --- a/packages/db/src/package.ts +++ b/packages/db/src/package.ts @@ -11,18 +11,17 @@ const PKG_ITEM_METADATA = "pkg-item-metadata"; export const pkgItemMetadata = dbCache.indexedByKey<PackageItemData, string>({ rootKey: PKG_ITEM_METADATA, getKey: (target) => target, - validate: (id, metadata) => - typeof id === "string" && typeof metadata === "object", + validate: (id, metadata) => typeof id === "string" && typeof metadata === "object" }); export const packageGettingStartedShow = dbCache.indexedByKey<boolean, string>({ rootKey: PACKAGE_GETTING_STARTED_SHOW, - getKey: (dnpName) => stripDots(dnpName), + getKey: (dnpName) => stripDots(dnpName) }); export const packageInstallTime = dbCache.indexedByKey<number, string>({ rootKey: PACKAGE_INSTALL_TIME, - getKey: (dnpName) => stripDots(dnpName), + getKey: (dnpName) => stripDots(dnpName) }); export function addPackageInstalledMetadata(dnpName: string): void { @@ -34,22 +33,16 @@ export function addPackageInstalledMetadata(dnpName: string): void { * Register the last emitted version for a dnpName * Only emit notifications for versions above this one */ -export const packageLatestKnownVersion = dbCache.indexedByKey< - UpdateAvailable, - string ->({ +export const packageLatestKnownVersion = dbCache.indexedByKey<UpdateAvailable, string>({ rootKey: PACKAGE_LATEST_KNOWN_VERSION, // Do NOT strip dots so the packages can be indexed by dnpName doing .getAll() - getKey: (dnpName) => dnpName, + getKey: (dnpName) => dnpName }); /** * Store data sent by the package and show it to the UI */ -export const packageSentData = dbCache.indexedByKey< - Record<string, string>, - string ->({ +export const packageSentData = dbCache.indexedByKey<Record<string, string>, string>({ rootKey: PACKAGE_SENT_DATA, - getKey: (dnpName) => dnpName, + getKey: (dnpName) => dnpName }); diff --git a/packages/db/src/system.ts b/packages/db/src/system.ts index 6bf8f88c7..eab27dc13 100644 --- a/packages/db/src/system.ts +++ b/packages/db/src/system.ts @@ -21,17 +21,11 @@ export const serverName = interceptGlobalEnvOnSet( // Domains -export const fullnodeDomainTarget = dbMain.staticKey<string>( - FULLNODE_DOMAIN_TARGET, - "" -); +export const fullnodeDomainTarget = dbMain.staticKey<string>(FULLNODE_DOMAIN_TARGET, ""); // Host password check -export const passwordIsSecure = dbMain.staticKey<boolean>( - PASSWORD_IS_SECURE, - false -); +export const passwordIsSecure = dbMain.staticKey<boolean>(PASSWORD_IS_SECURE, false); // Telegram bot status @@ -39,44 +33,29 @@ export const telegramStatus = dbMain.staticKey<boolean>(TELEGRAM_STATUS, false); // Telegram token -export const telegramToken = dbMain.staticKey<string | null>( - TELEGRAM_TOKEN, - null -); +export const telegramToken = dbMain.staticKey<string | null>(TELEGRAM_TOKEN, null); // Telegram channel Id -export const telegramChannelIds = dbMain.staticKey<string[]>( - TELEGRAM_CHANNEL_ID, - [] -); +export const telegramChannelIds = dbMain.staticKey<string[]>(TELEGRAM_CHANNEL_ID, []); // Telegram user Id i.e 1461924175 -export const telegramUserId = dbMain.staticKey<string | null>( - TELEGRAM_USER_ID, - null -); +export const telegramUserId = dbMain.staticKey<string | null>(TELEGRAM_USER_ID, null); // Is dappnode AWS instance -export const isDappnodeAws = dbMain.staticKey<boolean | null>( - IS_DAPPNODE_AWS, - null -); +export const isDappnodeAws = dbMain.staticKey<boolean | null>(IS_DAPPNODE_AWS, null); // Cache version information to detect updates -export const versionData = dbCache.staticKey<PackageVersionData>( - VERSION_DATA, - {} -); +export const versionData = dbCache.staticKey<PackageVersionData>(VERSION_DATA, {}); // Disk usage threshould records export const diskUsageThreshold = dbCache.indexedByKey<boolean, string>({ rootKey: DISK_USAGE_THRESHOLD, - getKey: (id) => id, + getKey: (id) => id }); // DAppNode Name appears on the UI diff --git a/packages/db/src/systemFlags.ts b/packages/db/src/systemFlags.ts index 02a102a0c..cf3ae3a51 100644 --- a/packages/db/src/systemFlags.ts +++ b/packages/db/src/systemFlags.ts @@ -3,12 +3,6 @@ import { dbMain } from "./dbFactory.js"; const IMPORTED_INSTALLATION_STATIC_IP = "imported-installation-staticIp"; const IS_VPN_DB_MIGRATED = "is-vpn-db-migrated"; -export const importedInstallationStaticIp = dbMain.staticKey<boolean>( - IMPORTED_INSTALLATION_STATIC_IP, - false -); +export const importedInstallationStaticIp = dbMain.staticKey<boolean>(IMPORTED_INSTALLATION_STATIC_IP, false); -export const isVpnDbMigrated = dbMain.staticKey<boolean>( - IS_VPN_DB_MIGRATED, - false -); +export const isVpnDbMigrated = dbMain.staticKey<boolean>(IS_VPN_DB_MIGRATED, false); diff --git a/packages/db/src/ui.ts b/packages/db/src/ui.ts index 8ab93641d..596737098 100644 --- a/packages/db/src/ui.ts +++ b/packages/db/src/ui.ts @@ -4,12 +4,9 @@ import { NewFeatureId, NewFeatureStatus } from "@dappnode/types"; const NEW_FEATURE_STATUS = "new-feature-status"; const SMOOTH_SHOWN = "smooth-shown"; -export const newFeatureStatus = dbMain.indexedByKey< - NewFeatureStatus, - NewFeatureId ->({ +export const newFeatureStatus = dbMain.indexedByKey<NewFeatureStatus, NewFeatureId>({ rootKey: NEW_FEATURE_STATUS, - getKey: (featureId) => featureId, + getKey: (featureId) => featureId }); -export const smoothShown = dbMain.staticKey<boolean>(SMOOTH_SHOWN, false); \ No newline at end of file +export const smoothShown = dbMain.staticKey<boolean>(SMOOTH_SHOWN, false); diff --git a/packages/db/src/updatePkgsWithGlobalEnvs.ts b/packages/db/src/updatePkgsWithGlobalEnvs.ts index fd9246746..a770664e4 100644 --- a/packages/db/src/updatePkgsWithGlobalEnvs.ts +++ b/packages/db/src/updatePkgsWithGlobalEnvs.ts @@ -1,11 +1,6 @@ import { eventBus } from "@dappnode/eventbus"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - getContainersStatus, - dockerComposeUpPackage, - listPackage, - listPackageContainers, -} from "@dappnode/dockerapi"; +import { getContainersStatus, dockerComposeUpPackage, listPackage, listPackageContainers } from "@dappnode/dockerapi"; import { packageInstalledHasPid } from "@dappnode/utils"; import { PackageEnvs } from "@dappnode/types"; import { params } from "@dappnode/params"; @@ -20,16 +15,11 @@ import { logs } from "@dappnode/logger"; * * TODO: find a proper way to restart pkgs with global envs defined in the env_file (through manifest > globalEnvs = {all: true}) */ -export async function updatePkgsWithGlobalEnvs( - globalEnvKey: string, - globEnvValue: string -): Promise<void> { +export async function updatePkgsWithGlobalEnvs(globalEnvKey: string, globEnvValue: string): Promise<void> { const packages = await listPackageContainers(); const pkgsWithGlobalEnv = packages.filter( - (pkg) => - pkg.defaultEnvironment && - Object.keys(pkg.defaultEnvironment).some((key) => key === globalEnvKey) + (pkg) => pkg.defaultEnvironment && Object.keys(pkg.defaultEnvironment).some((key) => key === globalEnvKey) ); if (pkgsWithGlobalEnv.length === 0) return; @@ -44,7 +34,7 @@ export async function updatePkgsWithGlobalEnvs( const serviceEnvs = service.getEnvs(); if (globalEnvKey in serviceEnvs) { environmentsByService.push({ - [pkg.serviceName]: { [globalEnvKey]: globEnvValue }, + [pkg.serviceName]: { [globalEnvKey]: globEnvValue } }); } } @@ -55,11 +45,9 @@ export async function updatePkgsWithGlobalEnvs( await packageSetEnvironment({ dnpName: pkg.dnpName, - environmentByService, + environmentByService }).catch((err) => { - logs.error( - `Error updating ${pkg.dnpName} with global env ${globalEnvKey}=${globEnvValue}` - ); + logs.error(`Error updating ${pkg.dnpName} with global env ${globalEnvKey}=${globEnvValue}`); logs.error(err); }); } @@ -72,7 +60,7 @@ export async function updatePkgsWithGlobalEnvs( */ async function packageSetEnvironment({ dnpName, - environmentByService, + environmentByService }: { dnpName: string; environmentByService: { [serviceName: string]: PackageEnvs }; @@ -84,9 +72,7 @@ async function packageSetEnvironment({ const compose = new ComposeFileEditor(dnp.dnpName, dnp.isCore); const services = compose.services(); - for (const [serviceName, environment] of Object.entries( - environmentByService - )) { + for (const [serviceName, environment] of Object.entries(environmentByService)) { const service = services[serviceName]; if (!service) throw Error(`No service ${serviceName} in dnp ${dnpName}`); service.mergeEnvs(environment); @@ -98,7 +84,7 @@ async function packageSetEnvironment({ // Packages sharing PID or must be recreated: // - Packages sharing PID must be recreated to ensure startup order await dockerComposeUpPackage({ dnpName }, false, containersStatus, { - forceRecreate: packageInstalledHasPid(compose.compose), + forceRecreate: packageInstalledHasPid(compose.compose) }); // Emit packages update diff --git a/packages/db/src/upnp.ts b/packages/db/src/upnp.ts index 607d35e55..2894b4e3a 100644 --- a/packages/db/src/upnp.ts +++ b/packages/db/src/upnp.ts @@ -12,14 +12,8 @@ export const upnpAvailable = interceptGlobalEnvOnSet( Object.keys({ UPNP_AVAILABLE })[0] ); -export const upnpPortMappings = dbCache.staticKey<UpnpPortMapping[]>( - UPNP_PORT_MAPPINGS, - [] -); +export const upnpPortMappings = dbCache.staticKey<UpnpPortMapping[]>(UPNP_PORT_MAPPINGS, []); export const portsToOpen = dbCache.staticKey<PackagePort[]>(PORTS_TO_OPEN, []); -export const isNatRenewalDisabled = dbCache.staticKey<boolean>( - IS_NAT_RENEWAL_DISABLED, - false -); +export const isNatRenewalDisabled = dbCache.staticKey<boolean>(IS_NAT_RENEWAL_DISABLED, false); diff --git a/packages/db/src/vpn.ts b/packages/db/src/vpn.ts index 34712077f..73c95a8e8 100644 --- a/packages/db/src/vpn.ts +++ b/packages/db/src/vpn.ts @@ -3,7 +3,4 @@ import { PackageVersionData } from "@dappnode/types"; const VERSION_DATA_VPN = "version-data-vpn"; -export const versionDataVpn = dbCache.staticKey<PackageVersionData>( - VERSION_DATA_VPN, - {} -); +export const versionDataVpn = dbCache.staticKey<PackageVersionData>(VERSION_DATA_VPN, {}); diff --git a/packages/db/test/unit/index.test.ts b/packages/db/test/unit/index.test.ts index a44d5def4..9394162d2 100644 --- a/packages/db/test/unit/index.test.ts +++ b/packages/db/test/unit/index.test.ts @@ -16,7 +16,7 @@ describe("db", () => { const staticValue = staticKey(STATIC_VALUE_KEY, 1); const indexedValue = indexedByKey<number, string>({ rootKey: INDEXED_VALUE_KEY, - getKey: (arg) => arg, + getKey: (arg) => arg }); // staticValue @@ -27,31 +27,19 @@ describe("db", () => { // indexedValue - expect(indexedValue.getAll()).to.deep.equal( - {}, - "indexedValue - wrong def getAll" - ); - expect(indexedValue.get("a")).to.deep.equal( - undefined, - "indexedValue - wrong def get('a')" - ); + expect(indexedValue.getAll()).to.deep.equal({}, "indexedValue - wrong def getAll"); + expect(indexedValue.get("a")).to.deep.equal(undefined, "indexedValue - wrong def get('a')"); indexedValue.set("a", 5); - expect(indexedValue.getAll()).to.deep.equal( - { a: 5 }, - "indexedValue - wrong getAll" - ); - expect(indexedValue.get("a")).to.deep.equal( - 5, - "indexedValue - wrong get('a')" - ); + expect(indexedValue.getAll()).to.deep.equal({ a: 5 }, "indexedValue - wrong getAll"); + expect(indexedValue.get("a")).to.deep.equal(5, "indexedValue - wrong get('a')"); expect(fs.readFileSync(dbPath, "utf8").trim()).to.equal( JSON.stringify( { [STATIC_VALUE_KEY]: 5, [INDEXED_VALUE_KEY]: { - a: 5, - }, + a: 5 + } }, null, 2 diff --git a/packages/dockerApi/.eslintignore b/packages/dockerApi/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/dockerApi/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/dockerApi/.eslintrc.cjs b/packages/dockerApi/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/dockerApi/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/dockerApi/package.json b/packages/dockerApi/package.json index fc991f4b9..53fe9f7f6 100644 --- a/packages/dockerApi/package.json +++ b/packages/dockerApi/package.json @@ -16,8 +16,7 @@ "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", "test:int": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/int --timeout 10000", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/hostscriptsservices": "workspace:^0.1.0", diff --git a/packages/dockerApi/src/api/container.ts b/packages/dockerApi/src/api/container.ts index cfc1a1476..2e409e050 100644 --- a/packages/dockerApi/src/api/container.ts +++ b/packages/dockerApi/src/api/container.ts @@ -5,15 +5,11 @@ import { docker } from "./docker.js"; * Inspect container * @param containerNameOrId "DAppNodePackage-geth.dnp.dappnode.eth" */ -export async function dockerContainerInspect( - containerNameOrId: string -): Promise<Docker.ContainerInspectInfo> { +export async function dockerContainerInspect(containerNameOrId: string): Promise<Docker.ContainerInspectInfo> { return await docker.getContainer(containerNameOrId).inspect(); } -export async function dockerContainerStart( - containerNameOrId: string -): Promise<Docker.ContainerInspectInfo> { +export async function dockerContainerStart(containerNameOrId: string): Promise<Docker.ContainerInspectInfo> { return await docker.getContainer(containerNameOrId).start(); } @@ -21,14 +17,10 @@ export async function dockerContainerStop( containerNameOrId: string, options?: DockerStopOptions ): Promise<Docker.ContainerInspectInfo> { - return await docker - .getContainer(containerNameOrId) - .stop({ t: options?.timeout }); + return await docker.getContainer(containerNameOrId).stop({ t: options?.timeout }); } -export async function dockerContainerKill( - containerNameOrId: string -): Promise<Docker.ContainerInspectInfo> { +export async function dockerContainerKill(containerNameOrId: string): Promise<Docker.ContainerInspectInfo> { return await docker.getContainer(containerNameOrId).kill(); } @@ -36,18 +28,14 @@ export async function dockerContainerRestart( containerNameOrId: string, options?: DockerStopOptions ): Promise<Docker.ContainerInspectInfo> { - return await docker - .getContainer(containerNameOrId) - .restart({ t: options?.timeout }); + return await docker.getContainer(containerNameOrId).restart({ t: options?.timeout }); } export async function dockerContainerRemove( containerNameOrId: string, options?: DockerRemoveOptions ): Promise<Docker.ContainerInspectInfo> { - return await docker - .getContainer(containerNameOrId) - .remove({ force: true, v: options?.volumes }); + return await docker.getContainer(containerNameOrId).remove({ force: true, v: options?.volumes }); } interface DockerStopOptions { diff --git a/packages/dockerApi/src/api/copyFileTo.ts b/packages/dockerApi/src/api/copyFileTo.ts index 074ba9abd..86db7e3a9 100644 --- a/packages/dockerApi/src/api/copyFileTo.ts +++ b/packages/dockerApi/src/api/copyFileTo.ts @@ -30,7 +30,7 @@ export async function copyFileToDockerContainer({ containerName, dataUri, filename, - toPath, + toPath }: { containerName: string; dataUri: string; @@ -42,17 +42,14 @@ export async function copyFileToDockerContainer({ if (!dataUri) throw Error("Argument dataUri must be defined"); if (!filename) throw Error("Argument filename must be defined"); // Allow only alphanumeric, underscores, hyphens, and dots to prevent command injection - if (!/^[a-zA-Z0-9._-]+$/.test(containerName)) - throw Error(`Invalid container name: ${containerName}`); + if (!/^[a-zA-Z0-9._-]+$/.test(containerName)) throw Error(`Invalid container name: ${containerName}`); // Validate file name and path to prevent directory traversal or command execution if (/[^a-zA-Z0-9._/-]/.test(toPath)) throw Error(`Invalid path: ${toPath}`); - if (/[^a-zA-Z0-9._/-]/.test(filename)) - throw Error(`Invalid file name: ${filename}`); + if (/[^a-zA-Z0-9._/-]/.test(filename)) throw Error(`Invalid file name: ${filename}`); // toPath is allowed to be empty, it will default to WORKDIR // if (!toPath) throw Error("Argument toPath must be defined") - if (filename.includes("/")) - throw Error(`filename must not be a path: ${filename}`); + if (filename.includes("/")) throw Error(`filename must not be a path: ${filename}`); // Construct relative paths to container // Fetch the WORKDIR from a docker inspect @@ -64,12 +61,10 @@ export async function copyFileToDockerContainer({ } // Intermediate step, the file is in local file system - if (!fs.existsSync(tempTransferDir)) - fs.mkdirSync(tempTransferDir, { recursive: true }); + if (!fs.existsSync(tempTransferDir)) fs.mkdirSync(tempTransferDir, { recursive: true }); const fromPath = path.join(tempTransferDir, filename); // Remove existing file if it exists - if (fs.existsSync(fromPath)) - fs.rmSync(fromPath, { recursive: true, force: true }); + if (fs.existsSync(fromPath)) fs.rmSync(fromPath, { recursive: true, force: true }); /** * Convert dataUri to local file @@ -85,27 +80,21 @@ export async function copyFileToDockerContainer({ const containerInspect = await dockerContainerInspect(containerName); const isInitiallyRunning = containerInspect.State.Running; - if (!isInitiallyRunning) - await dockerContainerStart(containerName); + if (!isInitiallyRunning) await dockerContainerStart(containerName); // Copy file from local file system to container await dockerCopyFileTo(containerName, fromPath, toPath); // Clean intermediate file - if (fs.existsSync(fromPath)) - fs.rmSync(fromPath, { recursive: true, force: true }); + if (fs.existsSync(fromPath)) fs.rmSync(fromPath, { recursive: true, force: true }); if (!isInitiallyRunning) - dockerContainerStop(containerName).catch( - (err) => logs.error(`Error stopping container ${containerName} after copying a file to it: ${err}`) + dockerContainerStop(containerName).catch((err) => + logs.error(`Error stopping container ${containerName} after copying a file to it: ${err}`) ); } -function dockerCopyFileTo( - id: string, - fromPath: string, - toPath: string -): Promise<string> { +function dockerCopyFileTo(id: string, fromPath: string, toPath: string): Promise<string> { return shell(`docker cp --follow-link ${fromPath} ${id}:${toPath}`); } diff --git a/packages/dockerApi/src/api/df.ts b/packages/dockerApi/src/api/df.ts index e88675312..f4a65dab4 100644 --- a/packages/dockerApi/src/api/df.ts +++ b/packages/dockerApi/src/api/df.ts @@ -12,9 +12,7 @@ const dockerDfMemo = memoize(() => docker.df(), { * NOTE: Result is cached for 15s + it only ran once at a time, * resolving multiple calls with the value (like runOnlyOneReturnToAll) */ -export async function dockerDf(options?: { - noCache: boolean; -}): Promise<DockerApiSystemDfReturn> { +export async function dockerDf(options?: { noCache: boolean }): Promise<DockerApiSystemDfReturn> { if (options && options.noCache) return await docker.df(); else return await dockerDfMemo(); } diff --git a/packages/dockerApi/src/api/disconnectConflictingContainerIfAny.ts b/packages/dockerApi/src/api/disconnectConflictingContainerIfAny.ts index 57a24ab06..9be39e766 100644 --- a/packages/dockerApi/src/api/disconnectConflictingContainerIfAny.ts +++ b/packages/dockerApi/src/api/disconnectConflictingContainerIfAny.ts @@ -14,9 +14,7 @@ export async function disconnectConflictingContainerIfAny( ): Promise<Dockerode.NetworkContainer | null> { const conflictingContainer = await findContainerByIP(network, ipAddress); if (conflictingContainer) { - logs.info( - `address ${ipAddress} already in used by ${conflictingContainer.Name}, freeing it` - ); + logs.info(`address ${ipAddress} already in used by ${conflictingContainer.Name}, freeing it`); await network.disconnect({ Container: conflictingContainer.Name }); } else logs.info("Conflicting container not found."); return conflictingContainer; diff --git a/packages/dockerApi/src/api/getArchive.ts b/packages/dockerApi/src/api/getArchive.ts index c7eb3ee4c..46844d6bf 100644 --- a/packages/dockerApi/src/api/getArchive.ts +++ b/packages/dockerApi/src/api/getArchive.ts @@ -13,10 +13,7 @@ import { Writable, pipeline } from "stream"; * @param containerNameOrId "DAppNodePackage-geth.dnp.dappnode.eth" * @param rootTarPath Path to tar */ -export async function dockerGetArchive( - containerNameOrId: string, - rootTarPath: string -): Promise<NodeJS.ReadableStream> { +export async function dockerGetArchive(containerNameOrId: string, rootTarPath: string): Promise<NodeJS.ReadableStream> { const container = docker.getContainer(containerNameOrId); const readableStream = await container.getArchive({ path: rootTarPath }); @@ -34,10 +31,7 @@ export async function dockerGetArchiveSingleFile( filePathAbsolute: string, fileContentSink: Writable ): Promise<void> { - const tarReadableStream = await dockerGetArchive( - containerNameOrId, - filePathAbsolute - ); + const tarReadableStream = await dockerGetArchive(containerNameOrId, filePathAbsolute); const targetFile = path.parse(filePathAbsolute).base; await tarExtractSingleFile(tarReadableStream, fileContentSink, targetFile); @@ -57,7 +51,7 @@ export async function tarExtractSingleFile( return new Promise((resolve, reject) => { let fileFound = false; - extract.on("entry", async function(header, stream, next) { + extract.on("entry", async function (header, stream, next) { if (!fileFound && header.name === targetFile && header.type === "file") { fileFound = true; @@ -76,7 +70,7 @@ export async function tarExtractSingleFile( } }); - extract.on("finish", function() { + extract.on("finish", function () { if (fileFound) resolve(); else reject(Error(`file ${targetFile} not found in tar`)); }); diff --git a/packages/dockerApi/src/api/infoArchive.ts b/packages/dockerApi/src/api/infoArchive.ts index 8cdec0319..0bd236e4f 100644 --- a/packages/dockerApi/src/api/infoArchive.ts +++ b/packages/dockerApi/src/api/infoArchive.ts @@ -15,19 +15,12 @@ import { docker } from "./docker.js"; * linkTarget: '/bin/busybox' * } */ -export async function dockerInfoArchive( - id: string, - path: string -): Promise<DockerInfoArchive> { +export async function dockerInfoArchive(id: string, path: string): Promise<DockerInfoArchive> { const container = docker.getContainer(id); const res = await container.infoArchive({ path }); const headers = res.headers; - const pathStatBase64 = - headers["x-docker-container-path-stat"] || - headers["X-DOCKER-CONTAINER-PATH-STAT"]; - const pathStatString = Buffer.from(pathStatBase64, "base64").toString( - "ascii" - ); + const pathStatBase64 = headers["x-docker-container-path-stat"] || headers["X-DOCKER-CONTAINER-PATH-STAT"]; + const pathStatString = Buffer.from(pathStatBase64, "base64").toString("ascii"); return JSON.parse(pathStatString); } diff --git a/packages/dockerApi/src/api/listContainers.ts b/packages/dockerApi/src/api/listContainers.ts index 9cd9a1125..7078ea052 100644 --- a/packages/dockerApi/src/api/listContainers.ts +++ b/packages/dockerApi/src/api/listContainers.ts @@ -1,9 +1,7 @@ import Docker from "dockerode"; import { docker } from "./docker.js"; -export function listContainers( - options: DockerApiListContainerOptions -): Promise<Docker.ContainerInfo[]> { +export function listContainers(options: DockerApiListContainerOptions): Promise<Docker.ContainerInfo[]> { // Change all default value from false to true return docker.listContainers({ all: true, ...options }); } diff --git a/packages/dockerApi/src/api/listImages.ts b/packages/dockerApi/src/api/listImages.ts index d5e586d02..56da25025 100644 --- a/packages/dockerApi/src/api/listImages.ts +++ b/packages/dockerApi/src/api/listImages.ts @@ -10,12 +10,8 @@ import { docker } from "./docker.js"; * } * } */ -export async function imagesList( - options?: DockerApiListImagesOptions -): Promise<Dockerode.ImageInfo[]> { - return docker.listImages(options as Dockerode.ListImagesOptions) as Promise< - Dockerode.ImageInfo[] - >; +export async function imagesList(options?: DockerApiListImagesOptions): Promise<Dockerode.ImageInfo[]> { + return docker.listImages(options as Dockerode.ListImagesOptions) as Promise<Dockerode.ImageInfo[]>; } export interface DockerApiListImagesOptions { diff --git a/packages/dockerApi/src/api/listVolumes.ts b/packages/dockerApi/src/api/listVolumes.ts index 7dc5516ac..879d4aed7 100644 --- a/packages/dockerApi/src/api/listVolumes.ts +++ b/packages/dockerApi/src/api/listVolumes.ts @@ -1,8 +1,6 @@ import { docker } from "./docker.js"; -export async function dockerVolumesList( - options?: DockerApiListVolumesOptions -): Promise<DockerVolumeListItem[]> { +export async function dockerVolumesList(options?: DockerApiListVolumesOptions): Promise<DockerVolumeListItem[]> { const { Volumes } = await docker.listVolumes({ filters: options }); // Return is not correctly typed, casting to actual tested values return Volumes as DockerVolumeListItem[]; diff --git a/packages/dockerApi/src/api/loadImage.ts b/packages/dockerApi/src/api/loadImage.ts index 95a3d2a78..25e718666 100644 --- a/packages/dockerApi/src/api/loadImage.ts +++ b/packages/dockerApi/src/api/loadImage.ts @@ -3,10 +3,7 @@ import { docker } from "./docker.js"; /** * Load .tar.xz image sending it to the docker daemon */ -export async function loadImage( - imagePath: string, - onProgress?: (event: DockerLoadProgress) => void -): Promise<void> { +export async function loadImage(imagePath: string, onProgress?: (event: DockerLoadProgress) => void): Promise<void> { return new Promise((resolve, reject) => { // Must disable quiet flag to receive progress updates docker.loadImage(imagePath, { quiet: "0" }, (err, stream) => { @@ -18,7 +15,7 @@ export async function loadImage( if (err) reject(err); else resolve(); }, - // eslint-disable-next-line @typescript-eslint/no-empty-function + onProgress || ((): void => {}) ); }); diff --git a/packages/dockerApi/src/api/logs.ts b/packages/dockerApi/src/api/logs.ts index 5b7b1a9b5..9c829a480 100644 --- a/packages/dockerApi/src/api/logs.ts +++ b/packages/dockerApi/src/api/logs.ts @@ -5,10 +5,7 @@ import { stripDockerApiLogsHeaderAndAnsi } from "../utils.js"; * Returns container's logs as a string with escape codes * @param containerNameOrId */ -export async function logContainer( - containerNameOrId: string, - options?: LogOptions -): Promise<string> { +export async function logContainer(containerNameOrId: string, options?: LogOptions): Promise<string> { const container = docker.getContainer(containerNameOrId); const res = await container.logs({ stdout: true, stderr: true, ...options }); // Return is incorrectly typed as NodeJS.ReadableStream, but it's string diff --git a/packages/dockerApi/src/api/network.ts b/packages/dockerApi/src/api/network.ts index 13acecf17..e40c6b8fa 100644 --- a/packages/dockerApi/src/api/network.ts +++ b/packages/dockerApi/src/api/network.ts @@ -13,15 +13,14 @@ export async function getNetworkAliasesIpsMapNotThrow( ): Promise<Map<string, { aliases: string[]; ip: string }>> { try { const network = docker.getNetwork(networkName); - const networkInfo: Dockerode.NetworkInspectInfo = - (await network.inspect()) as Dockerode.NetworkInspectInfo; + const networkInfo: Dockerode.NetworkInspectInfo = (await network.inspect()) as Dockerode.NetworkInspectInfo; const containersInfo = Object.values(networkInfo.Containers ?? []); return await getContainerAliasesIpsForNetwork(containersInfo, networkName); } catch (e) { // This should not stop migration, as it is not critical - logs.error(`Aliases map could not be generated for network ${networkName}`); + logs.error(`Aliases map could not be generated for network ${networkName}: ${e}`); return new Map<string, { aliases: string[]; ip: string }>(); } } @@ -32,44 +31,31 @@ async function getContainerAliasesIpsForNetwork( ): Promise<Map<string, { aliases: string[]; ip: string }>> { const fetchAliasesTasks = containersInfo.map(async (containerInfo) => { try { - const aliases: string[] = - (await getNetworkContainerConfig(containerInfo.Name, networkName)) - ?.Aliases ?? []; + const aliases: string[] = (await getNetworkContainerConfig(containerInfo.Name, networkName))?.Aliases ?? []; return { name: containerInfo.Name, aliases, - ip: containerInfo.IPv4Address, + ip: containerInfo.IPv4Address }; } catch (error) { - console.error( - `Failed to get aliases for container ${containerInfo.Name}:`, - error - ); + console.error(`Failed to get aliases for container ${containerInfo.Name}:`, error); return { name: containerInfo.Name, aliases: [], ip: "" }; } }); const containersAliases = await Promise.all(fetchAliasesTasks); - return new Map( - containersAliases.map(({ name, aliases, ip }) => [name, { aliases, ip }]) - ); + return new Map(containersAliases.map(({ name, aliases, ip }) => [name, { aliases, ip }])); } /** * Disconnect all docker containers from a docker network * @param network "dncore_network" */ -export async function disconnectAllContainersFromNetwork( - network: Dockerode.Network -): Promise<void> { - const containers = ((await network.inspect()) as Dockerode.NetworkInspectInfo) - .Containers; +export async function disconnectAllContainersFromNetwork(network: Dockerode.Network): Promise<void> { + const containers = ((await network.inspect()) as Dockerode.NetworkInspectInfo).Containers; if (containers) await Promise.all( - Object.values(containers).map( - async (c) => - await network.disconnect({ Container: c.Name, Force: true }) - ) + Object.values(containers).map(async (c) => await network.disconnect({ Container: c.Name, Force: true })) ); } @@ -87,7 +73,7 @@ export async function dockerNetworkConnect( const network = docker.getNetwork(networkName); await network.connect({ Container: containerName, - EndpointConfig: endpointConfig, + EndpointConfig: endpointConfig }); } @@ -106,7 +92,7 @@ export async function dockerNetworkConnectNotThrow( const network = docker.getNetwork(networkName); await network.connect({ Container: containerName, - EndpointConfig: endpointConfig, + EndpointConfig: endpointConfig }); } catch (e) { logs.debug(e); @@ -119,15 +105,12 @@ export async function dockerNetworkConnectNotThrow( * @param containerName "3613f73ba0e4" or "fullcontainername" * @param aliases `["network-alias"]` */ -export async function dockerNetworkDisconnect( - networkName: string, - containerName: string -): Promise<void> { +export async function dockerNetworkDisconnect(networkName: string, containerName: string): Promise<void> { const network = docker.getNetwork(networkName); await network.disconnect({ Container: containerName, // Force the container to disconnect from the network - Force: true, + Force: true }); } @@ -161,13 +144,11 @@ export async function dockerCreateNetwork(networkName: string): Promise<void> { // collisions. CheckDuplicate: true, // Default plugin - Driver: "bridge", + Driver: "bridge" }); } -export async function dockerListNetworks(): Promise< - Dockerode.NetworkInspectInfo[] -> { +export async function dockerListNetworks(): Promise<Dockerode.NetworkInspectInfo[]> { return await docker.listNetworks(); } diff --git a/packages/dockerApi/src/api/volume.ts b/packages/dockerApi/src/api/volume.ts index 96731d2f5..694af3078 100644 --- a/packages/dockerApi/src/api/volume.ts +++ b/packages/dockerApi/src/api/volume.ts @@ -1,9 +1,7 @@ import Docker from "dockerode"; import { docker } from "./docker.js"; -export async function dockerVolumeInspect( - volumeName: string -): Promise<Docker.VolumeInspectInfo> { +export async function dockerVolumeInspect(volumeName: string): Promise<Docker.VolumeInspectInfo> { const volume = docker.getVolume(volumeName); return await volume.inspect(); } diff --git a/packages/dockerApi/src/cleanOldImages.ts b/packages/dockerApi/src/cleanOldImages.ts index 202f1a989..a92661184 100644 --- a/packages/dockerApi/src/cleanOldImages.ts +++ b/packages/dockerApi/src/cleanOldImages.ts @@ -6,17 +6,14 @@ import { imagesList, imageRemove } from "./api/index.js"; * If the images were removed successfuly the dappmanger will print logs: * Untagged: package.dnp.dappnode.eth:0.1.6 */ -export async function dockerCleanOldImages( - dnpName: string, - version: string -): Promise<void> { +export async function dockerCleanOldImages(dnpName: string, version: string): Promise<void> { // Filtering by `reference` requires the repo name to be exact // This prevents catching all images of a multi-service package const repoImages = await imagesList(); const imagesToDelete = repoImages.filter( - image => + (image) => image.RepoTags && - image.RepoTags.every(tag => { + image.RepoTags.every((tag) => { const [imageName, imageVersion] = tag.split(":"); return ( (imageName === dnpName || diff --git a/packages/dockerApi/src/compose/cli.ts b/packages/dockerApi/src/compose/cli.ts index c021107cd..ddae08262 100644 --- a/packages/dockerApi/src/compose/cli.ts +++ b/packages/dockerApi/src/compose/cli.ts @@ -24,7 +24,7 @@ async function execDockerCompose( // service names MUST go after the options ...(serviceNames || []), // Adding <&- to prevent interactive mode - "<&-", + "<&-" ]); } @@ -37,10 +37,7 @@ export interface DockerComposeUpOptions { removeOrphans?: boolean; } -export function dockerComposeUp( - dcPath: string, - options: DockerComposeUpOptions = {} -): Promise<string> { +export function dockerComposeUp(dcPath: string, options: DockerComposeUpOptions = {}): Promise<string> { // --detach is invalid with --no-start if (options.noStart) options.detach = false; return execDockerCompose( @@ -51,7 +48,7 @@ export function dockerComposeUp( detach: options.detach ?? true, forceRecreate: options.forceRecreate, timeout: options.timeout, - removeOrphans: options.removeOrphans, + removeOrphans: options.removeOrphans }, options.serviceNames ); @@ -85,10 +82,7 @@ export function dockerComposeStart(dcPath: string): Promise<string> { /** * --timeout TIMEOUT Specify a shutdown timeout in seconds. */ -export function dockerComposeStop( - dcPath: string, - options: { timeout?: number } = {} -): Promise<string> { +export function dockerComposeStop(dcPath: string, options: { timeout?: number } = {}): Promise<string> { return execDockerCompose(dcPath, "stop", options); } diff --git a/packages/dockerApi/src/dockerComposeUp.ts b/packages/dockerApi/src/dockerComposeUp.ts index 28c645021..bed5813bd 100644 --- a/packages/dockerApi/src/dockerComposeUp.ts +++ b/packages/dockerApi/src/dockerComposeUp.ts @@ -1,19 +1,11 @@ import fs from "fs"; import { params } from "@dappnode/params"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - dockerComposeDown, - dockerComposeUp, - DockerComposeUpOptions, -} from "./compose/index.js"; +import { dockerComposeDown, dockerComposeUp, DockerComposeUpOptions } from "./compose/index.js"; import { listPackageNoThrow } from "./list/index.js"; import { getDockerTimeoutMax } from "./utils.js"; import { logs } from "@dappnode/logger"; -import { - ContainersStatus, - InstalledPackageData, - PackageContainer, -} from "@dappnode/types"; +import { ContainersStatus, InstalledPackageData, PackageContainer } from "@dappnode/types"; import { getDockerComposePathSmart } from "@dappnode/utils"; interface ComposeUpArgs { @@ -41,26 +33,17 @@ export async function dockerComposeUpPackage( // because it adds a lot of complexity to create a new module for it. // Add timeout option if not previously specified - const timeout = containersStatus - ? getDockerTimeoutMax(Object.values(containersStatus)) - : undefined; - if (timeout && dockerComposeUpOptions && !dockerComposeUpOptions.timeout) - dockerComposeUpOptions.timeout = timeout; + const timeout = containersStatus ? getDockerTimeoutMax(Object.values(containersStatus)) : undefined; + if (timeout && dockerComposeUpOptions && !dockerComposeUpOptions.timeout) dockerComposeUpOptions.timeout = timeout; // Check the current status of package's container if any const serviceNames: string[] = readComposeServiceNames(composePath); const servicesToStart = serviceNames.filter( - (serviceName) => - containersStatus && - containersStatus[serviceName]?.targetStatus !== "stopped" + (serviceName) => containersStatus && containersStatus[serviceName]?.targetStatus !== "stopped" ); try { - if ( - upAll || - serviceNames.length === servicesToStart.length || - dnpName === params.coreDnpName - ) { + if (upAll || serviceNames.length === servicesToStart.length || dnpName === params.coreDnpName) { // Run docker-compose up on all services for: // - packages with all services running // - core package, it must be executed always. No matter the previous status @@ -70,21 +53,17 @@ export async function dockerComposeUpPackage( // then start only those that are running await dockerComposeUp(composePath, { ...dockerComposeUpOptions, - noStart: true, + noStart: true }); if (servicesToStart.length > 0) { await dockerComposeUp(composePath, { ...dockerComposeUpOptions, - serviceNames: servicesToStart, + serviceNames: servicesToStart }); } } } catch (e) { - if ( - e.message.includes( - "Renaming a container with the same name as its current name" - ) - ) { + if (e.message.includes("Renaming a container with the same name as its current name")) { // Catch error: Error response from daemon: Renaming a container with the same name as its current name // Ref: https://github.com/docker/compose/issues/6704 logs.info("Catch error renaming container with the same name"); @@ -109,7 +88,7 @@ function readComposeServiceNames(composePath: string): string[] { */ export async function getContainersStatus({ dnpName, - dnp, + dnp }: { dnpName: string; dnp?: InstalledPackageData | null; @@ -128,7 +107,7 @@ export async function getContainersStatus({ dnp.containers.map(async (container) => { containersStatus[container.serviceName] = { targetStatus: await getContainerTargetStatus(container), - dockerTimeout: container.dockerTimeout, + dockerTimeout: container.dockerTimeout }; }) ); @@ -143,9 +122,7 @@ export async function getContainersStatus({ * - Not started: status === created * @param container */ -async function getContainerTargetStatus( - container: PackageContainer -): Promise<"stopped" | "running"> { +async function getContainerTargetStatus(container: PackageContainer): Promise<"stopped" | "running"> { if (params.corePackagesThatMustBeRunning.includes(container.dnpName)) { return "running"; } diff --git a/packages/dockerApi/src/fileTransfer.ts b/packages/dockerApi/src/fileTransfer.ts index c01cad8eb..57208fe47 100644 --- a/packages/dockerApi/src/fileTransfer.ts +++ b/packages/dockerApi/src/fileTransfer.ts @@ -19,26 +19,17 @@ export async function dockerGetFileOrDirBasedOnExtension( ): Promise<void> { if (options?.isSingleFile) { // Download single file - await dockerGetArchiveSingleFile( - containerNameOrId, - filePathAbsolute, - fileContentSink - ); + await dockerGetArchiveSingleFile(containerNameOrId, filePathAbsolute, fileContentSink); } else { // Download path as tar - const tarReadableStream = await dockerGetArchive( - containerNameOrId, - filePathAbsolute - ); + const tarReadableStream = await dockerGetArchive(containerNameOrId, filePathAbsolute); await promisify(pipeline)(tarReadableStream, fileContentSink); } } type FileType = "file" | "directory"; -export async function dockerGetPathType( - filePathAbsolute: string -): Promise<FileType> { +export async function dockerGetPathType(filePathAbsolute: string): Promise<FileType> { if (path.parse(filePathAbsolute).ext) { return "file"; } else { diff --git a/packages/dockerApi/src/getContainersAndVolumesToRemove.ts b/packages/dockerApi/src/getContainersAndVolumesToRemove.ts index 64ad6e70d..df77028ab 100644 --- a/packages/dockerApi/src/getContainersAndVolumesToRemove.ts +++ b/packages/dockerApi/src/getContainersAndVolumesToRemove.ts @@ -36,6 +36,6 @@ export function getContainersAndVolumesToRemove( return { containersToRemove: uniq(containersToRemove), - volumesToRemove: uniq(volumesToRemove), + volumesToRemove: uniq(volumesToRemove) }; } diff --git a/packages/dockerApi/src/getDockerImageManifest.ts b/packages/dockerApi/src/getDockerImageManifest.ts index 86f0790bd..2df828ec5 100644 --- a/packages/dockerApi/src/getDockerImageManifest.ts +++ b/packages/dockerApi/src/getDockerImageManifest.ts @@ -5,8 +5,6 @@ interface ImageManifest { Layers: string[]; // ["14ec119e6215a169a53a8c9cdfb56ca873e10f2e5ea0a37692bfa71601f18ec7/layer.tar"] RepoTags: string[]; // ["package.dnp.dappnode.eth:0.2.0"]; } -export async function getDockerImageManifest( - imagePath: string -): Promise<ImageManifest[]> { +export async function getDockerImageManifest(imagePath: string): Promise<ImageManifest[]> { return shell(`tar -xOf ${imagePath} manifest.json`).then(JSON.parse); } diff --git a/packages/dockerApi/src/getHostVolumeSizes.ts b/packages/dockerApi/src/getHostVolumeSizes.ts index d22f5c263..ccd4ef73a 100644 --- a/packages/dockerApi/src/getHostVolumeSizes.ts +++ b/packages/dockerApi/src/getHostVolumeSizes.ts @@ -19,9 +19,7 @@ interface VolSizes { * bitcoin_data: "823203" * } */ -export async function getHostVolumeSizes( - volDevicePaths: VolDevicePaths -): Promise<VolSizes> { +export async function getHostVolumeSizes(volDevicePaths: VolDevicePaths): Promise<VolSizes> { // if there are no volDevicePaths, return early if (isEmpty(volDevicePaths)) return {}; @@ -73,12 +71,9 @@ async function duHostMountpoints(mountpointPath: string): Promise<SizeByPath> { // -d 2 = Show directories of max depth 2 // -B 1 = User SIZE-byte blocks of 1, bytes const duOutput = await shellHost(`du -- -d 2 -B 1 ${mountpointPath}`); - return parseDuOutput(duOutput, mountpointPath).reduce( - (obj: SizeByPath, { size, path }) => { - return { ...obj, [path]: size }; - }, - {} - ); + return parseDuOutput(duOutput, mountpointPath).reduce((obj: SizeByPath, { size, path }) => { + return { ...obj, [path]: size }; + }, {}); } import path from "path"; @@ -102,20 +97,15 @@ export interface DuResult { * { size: "824212", path: "." } * ] */ -export function parseDuOutput( - output: string, - relativeFrom?: string -): DuResult[] { +export function parseDuOutput(output: string, relativeFrom?: string): DuResult[] { return output .trim() .split("\n") .map((line) => { const [size, subpath] = line.trim().split(/\s+/); return { - path: path.normalize( - relativeFrom ? path.relative(relativeFrom, subpath) : subpath - ), - size, + path: path.normalize(relativeFrom ? path.relative(relativeFrom, subpath) : subpath), + size }; }); } diff --git a/packages/dockerApi/src/list/isPortMappingDeletable.ts b/packages/dockerApi/src/list/isPortMappingDeletable.ts index a8d4bdb1f..2a9ce40cd 100644 --- a/packages/dockerApi/src/list/isPortMappingDeletable.ts +++ b/packages/dockerApi/src/list/isPortMappingDeletable.ts @@ -6,17 +6,12 @@ import { PortMapping } from "@dappnode/types"; * @param port * @param defaultPorts */ -export function isPortMappingDeletable( - port: PortMapping, - defaultPorts: PortMapping[] | undefined -): boolean { +export function isPortMappingDeletable(port: PortMapping, defaultPorts: PortMapping[] | undefined): boolean { return ( // Assume if no defaultPorts they were empty, so all ports = deletable !Array.isArray(defaultPorts) || !defaultPorts.find( - (defaultPort) => - defaultPort.container == port.container && - defaultPort.protocol == port.protocol + (defaultPort) => defaultPort.container == port.container && defaultPort.protocol == port.protocol ) ); } diff --git a/packages/dockerApi/src/list/listContainers.ts b/packages/dockerApi/src/list/listContainers.ts index d0a6c0909..c55197a91 100644 --- a/packages/dockerApi/src/list/listContainers.ts +++ b/packages/dockerApi/src/list/listContainers.ts @@ -7,20 +7,14 @@ import { parseContainerInfo } from "./parseContainerInfo.js"; * [NOTE] On a full DAppNode will 14 containers the call takes 17ms on average * @returns */ -export async function listPackageContainers(filters?: { - containerName: string; -}): Promise<PackageContainer[]> { - const containers = await dockerApiListContainers( - filters ? { filters: { name: [filters.containerName] } } : {} - ); +export async function listPackageContainers(filters?: { containerName: string }): Promise<PackageContainer[]> { + const containers = await dockerApiListContainers(filters ? { filters: { name: [filters.containerName] } } : {}); - return containers - .map(parseContainerInfo) - .filter((pkg) => pkg.isDnp || pkg.isCore); + return containers.map(parseContainerInfo).filter((pkg) => pkg.isDnp || pkg.isCore); } export async function listPackageContainerNoThrow({ - containerName, + containerName }: { containerName: string; }): Promise<PackageContainer | null> { @@ -30,19 +24,12 @@ export async function listPackageContainerNoThrow({ // Return an exact match for // - containerName "DAppNodePackage-geth.dnp.dappnode.eth" // - name: "geth.dnp.dappnode.eth" - const matches = containers.filter( - (container) => container.containerName === containerName - ); - if (matches.length > 1) - throw Error(`Multiple matches found for ${containerName}`); + const matches = containers.filter((container) => container.containerName === containerName); + if (matches.length > 1) throw Error(`Multiple matches found for ${containerName}`); return matches[0] || null; } -export async function listContainer({ - containerName, -}: { - containerName: string; -}): Promise<PackageContainer> { +export async function listContainer({ containerName }: { containerName: string }): Promise<PackageContainer> { const container = await listPackageContainerNoThrow({ containerName }); if (!container) throw Error(`${containerName} package not found`); return container; diff --git a/packages/dockerApi/src/list/listPackages.ts b/packages/dockerApi/src/list/listPackages.ts index 0e028bd7d..bee6fd478 100644 --- a/packages/dockerApi/src/list/listPackages.ts +++ b/packages/dockerApi/src/list/listPackages.ts @@ -10,11 +10,7 @@ export async function listPackages(): Promise<InstalledPackageData[]> { return groupPackagesFromContainers(containers); } -export async function listPackageNoThrow({ - dnpName, -}: { - dnpName: string; -}): Promise<InstalledPackageData | null> { +export async function listPackageNoThrow({ dnpName }: { dnpName: string }): Promise<InstalledPackageData | null> { if (!dnpName) return null; // Optimize call are request only containers mapping to this package @@ -25,11 +21,7 @@ export async function listPackageNoThrow({ return dnps.find((d) => d.dnpName === dnpName) || null; } -export async function listPackage({ - dnpName, -}: { - dnpName: string; -}): Promise<InstalledPackageData> { +export async function listPackage({ dnpName }: { dnpName: string }): Promise<InstalledPackageData> { const dnp = await listPackageNoThrow({ dnpName }); if (!dnp) throw Error(`No DNP was found for name ${dnpName}`); return dnp; diff --git a/packages/dockerApi/src/list/parseContainerInfo.ts b/packages/dockerApi/src/list/parseContainerInfo.ts index c8120bc7b..6eaa921ed 100644 --- a/packages/dockerApi/src/list/parseContainerInfo.ts +++ b/packages/dockerApi/src/list/parseContainerInfo.ts @@ -1,22 +1,10 @@ import { ContainerInfo } from "dockerode"; import { params } from "@dappnode/params"; -import { - PackageContainer, - VolumeMapping, - ContainerState, -} from "@dappnode/types"; -import { - parsePortMappings, - parseVolumeMappings, - readContainerLabels, -} from "@dappnode/dockercompose"; +import { PackageContainer, VolumeMapping, ContainerState } from "@dappnode/types"; +import { parsePortMappings, parseVolumeMappings, readContainerLabels } from "@dappnode/dockercompose"; import { parseExitCodeFromStatus } from "./parseExitCodeFromStatus.js"; import { ensureUniquePortsFromDockerApi } from "../utils.js"; -import { - fileToGatewayUrl, - normalizeHash, - parseEnvironment, -} from "@dappnode/utils"; +import { fileToGatewayUrl, normalizeHash, parseEnvironment } from "@dappnode/utils"; const CONTAINER_NAME_PREFIX = params.CONTAINER_NAME_PREFIX; const CONTAINER_CORE_NAME_PREFIX = params.CONTAINER_CORE_NAME_PREFIX; @@ -26,45 +14,34 @@ export function parseContainerInfo(container: ContainerInfo): PackageContainer { const labels = readContainerLabels(container.Labels); const containerName = (container.Names[0] || "").replace("/", ""); - const dnpName = - labels.dnpName || parseDnpNameFromContainerName(containerName); + const dnpName = labels.dnpName || parseDnpNameFromContainerName(containerName); - const defaultEnvironment = - labels.defaultEnvironment && parseEnvironment(labels.defaultEnvironment); - const defaultPorts = - labels.defaultPorts && parsePortMappings(labels.defaultPorts); - const defaultVolumes = - labels.defaultVolumes && parseVolumeMappings(labels.defaultVolumes); + const defaultEnvironment = labels.defaultEnvironment && parseEnvironment(labels.defaultEnvironment); + const defaultPorts = labels.defaultPorts && parsePortMappings(labels.defaultPorts); + const defaultVolumes = labels.defaultVolumes && parseVolumeMappings(labels.defaultVolumes); const dockerTimeout = labels.dockerTimeout; const state = container.State as ContainerState; const exitCode = parseExitCodeFromStatus(container.Status); const containerNetworks = container.NetworkSettings?.Networks || {}; - const networks = Object.entries(containerNetworks).map( - ([networkName, network]) => ({ - name: networkName, - ip: network.IPAddress, - // NOTE: /containers/json will always return Aliases: null even if there are aliases - // aliases: network.Aliases || [] - }) - ); + const networks = Object.entries(containerNetworks).map(([networkName, network]) => ({ + name: networkName, + ip: network.IPAddress + // NOTE: /containers/json will always return Aliases: null even if there are aliases + // aliases: network.Aliases || [] + })); return { // Identification containerId: container.Id, containerName, - serviceName: - labels.serviceName || container.Labels["com.docker.compose.service"], + serviceName: labels.serviceName || container.Labels["com.docker.compose.service"], instanceName: labels.instanceName || "", dnpName, version: labels.version || (container.Image || "").split(":")[1] || "0.0.0", - isDnp: - Boolean(labels.dnpName) || containerName.includes(CONTAINER_NAME_PREFIX), - isCore: - typeof labels.isCore === "boolean" - ? labels.isCore - : containerName.includes(CONTAINER_CORE_NAME_PREFIX), + isDnp: Boolean(labels.dnpName) || containerName.includes(CONTAINER_NAME_PREFIX), + isCore: typeof labels.isCore === "boolean" ? labels.isCore : containerName.includes(CONTAINER_CORE_NAME_PREFIX), // Docker data created: container.Created, @@ -76,7 +53,7 @@ export function parseContainerInfo(container: ContainerInfo): PackageContainer { host: Source, // "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", container: Destination, // "/etc/nginx/vhost.d" // "Name" will be undefined if it's not a named volumed - ...(Name ? { name: Name } : {}), // "nginxproxydnpdappnodeeth_vhost.d" + ...(Name ? { name: Name } : {}) // "nginxproxydnpdappnodeeth_vhost.d" }) ), networks, @@ -96,7 +73,7 @@ export function parseContainerInfo(container: ContainerInfo): PackageContainer { defaultEnvironment, defaultPorts, defaultVolumes, - dockerTimeout, + dockerTimeout }; } diff --git a/packages/dockerApi/src/list/parseExitCodeFromStatus.ts b/packages/dockerApi/src/list/parseExitCodeFromStatus.ts index a2344b06d..436614951 100644 --- a/packages/dockerApi/src/list/parseExitCodeFromStatus.ts +++ b/packages/dockerApi/src/list/parseExitCodeFromStatus.ts @@ -16,8 +16,7 @@ const prefix = "exited ("; * ``` */ export function parseExitCodeFromStatus(status: string): number | null { - if (typeof status !== "string" || !status.toLowerCase().startsWith(prefix)) - return null; + if (typeof status !== "string" || !status.toLowerCase().startsWith(prefix)) return null; const rest = status.slice(prefix.length); const closingParensIndex = rest.indexOf(")"); diff --git a/packages/dockerApi/src/list/parsePackageFromContainer.ts b/packages/dockerApi/src/list/parsePackageFromContainer.ts index 161834cb7..ae60f0c58 100644 --- a/packages/dockerApi/src/list/parsePackageFromContainer.ts +++ b/packages/dockerApi/src/list/parsePackageFromContainer.ts @@ -4,9 +4,7 @@ import { InstalledPackageData, PackageContainer } from "@dappnode/types"; /** * Return containers grouped by parent package. Necessary for multi-service packages */ -export function groupPackagesFromContainers( - containers: PackageContainer[] -): InstalledPackageData[] { +export function groupPackagesFromContainers(containers: PackageContainer[]): InstalledPackageData[] { const dnpMap = new Map<string, InstalledPackageData>(); for (const container of containers) { let dnp = dnpMap.get(container.dnpName); @@ -23,9 +21,9 @@ export function groupPackagesFromContainers( "origin", "chain", "domainAlias", - "canBeFullnode", + "canBeFullnode" ]), - containers: [], + containers: [] }; dnpMap.set(container.dnpName, dnp); } diff --git a/packages/dockerApi/src/removeNamedVolume.ts b/packages/dockerApi/src/removeNamedVolume.ts index 93a656556..ca0ac4f6a 100644 --- a/packages/dockerApi/src/removeNamedVolume.ts +++ b/packages/dockerApi/src/removeNamedVolume.ts @@ -15,22 +15,14 @@ import { logs } from "@dappnode/logger"; */ export async function removeNamedVolume(volName: string): Promise<void> { const volInfo = await dockerVolumeInspect(volName); - if ( - volInfo.Options && - volInfo.Options.device && - volInfo.Driver === "local" && - volInfo.Options.o === "bind" - ) { + if (volInfo.Options && volInfo.Options.device && volInfo.Driver === "local" && volInfo.Options.o === "bind") { const devicePath = volInfo.Options.device; // WARNING: Make sure the device path is correct because // it could cause mayhem if empty or if it has a wrong value if (!devicePath) throw Error(`devicePath is empty`); if (!devicePath.includes(params.MOUNTPOINT_DEVICE_PREFIX)) - throw Error( - `devicePath must contain the volume tag '${params.MOUNTPOINT_DEVICE_PREFIX}': ${devicePath}` - ); - if (devicePath.length < 10) - throw Error(`devicePath is too short: ${devicePath}`); + throw Error(`devicePath must contain the volume tag '${params.MOUNTPOINT_DEVICE_PREFIX}': ${devicePath}`); + if (devicePath.length < 10) throw Error(`devicePath is too short: ${devicePath}`); // Using the `bash -c '$CMD' notation because otherwise the // '*' is expanded in the parent nsenter cmd, not in `rm -rf` diff --git a/packages/dockerApi/src/utils.ts b/packages/dockerApi/src/utils.ts index 5bfb9ea20..9d8598536 100644 --- a/packages/dockerApi/src/utils.ts +++ b/packages/dockerApi/src/utils.ts @@ -35,7 +35,7 @@ import { isPortMappingDeletable } from "./list/isPortMappingDeletable.js"; export function stripDockerApiLogsHeaderAndAnsi(logs: string): string { const pattern = [ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))" ].join("|"); const regex = new RegExp(pattern, "g"); @@ -60,9 +60,7 @@ function stripDockerApiLogHeader(line: string): string { * Returns the maximum dockerTimeout param from the container or undefined if none * @param containers */ -export function getDockerTimeoutMax( - containers: { dockerTimeout?: number }[] -): number | undefined { +export function getDockerTimeoutMax(containers: { dockerTimeout?: number }[]): number | undefined { let timeout: number | undefined = undefined; for (const container of containers) { @@ -123,13 +121,13 @@ export function ensureUniquePortsFromDockerApi( ({ ...(PublicPort ? { host: PublicPort } : {}), container: PrivatePort, - protocol: Type === "udp" ? PortProtocol.UDP : PortProtocol.TCP, + protocol: Type === "udp" ? PortProtocol.UDP : PortProtocol.TCP }) ) .map( (port): PortMapping => ({ ...port, - deletable: isPortMappingDeletable(port, defaultPorts), + deletable: isPortMappingDeletable(port, defaultPorts) }) ); diff --git a/packages/dockerApi/src/volumesData.ts b/packages/dockerApi/src/volumesData.ts index ce3a08a4c..ec8f8fed8 100644 --- a/packages/dockerApi/src/volumesData.ts +++ b/packages/dockerApi/src/volumesData.ts @@ -1,11 +1,7 @@ import { dockerDf, dockerVolumesList } from "./api/index.js"; import { listPackageContainers } from "./list/index.js"; import { parseDevicePath } from "@dappnode/dockercompose"; -import { - VolumeData, - VolumeOwnershipData, - PackageContainer, -} from "@dappnode/types"; +import { VolumeData, VolumeOwnershipData, PackageContainer } from "@dappnode/types"; import { detectMountpoints } from "@dappnode/hostscriptsservices"; /** @@ -16,15 +12,12 @@ import { detectMountpoints } from "@dappnode/hostscriptsservices"; * ``` * https://github.com/docker/compose/blob/854c14a5bcf566792ee8a972325c37590521656b/compose/cli/command.py#L178 */ -export const normalizeProjectName = (name: string): string => - name.replace(/[^-_a-z0-9]/gi, "").toLowerCase(); +export const normalizeProjectName = (name: string): string => name.replace(/[^-_a-z0-9]/gi, "").toLowerCase(); /** * Returns only ownership data of each volume against all installed packages */ -export async function getVolumesOwnershipData(): Promise< - VolumeOwnershipData[] -> { +export async function getVolumesOwnershipData(): Promise<VolumeOwnershipData[]> { const volumes = await dockerVolumesList(); const containers = await listPackageContainers(); @@ -43,9 +36,7 @@ export async function getVolumeSystemData(): Promise<VolumeData[]> { const containers = await listPackageContainers(); // This expensive function won't be called on empty volDevicePaths - const callDetectMountpoints = volumes.some( - (vol) => (vol.Options || {}).device - ); + const callDetectMountpoints = volumes.some((vol) => (vol.Options || {}).device); const mountpoints = callDetectMountpoints ? await detectMountpoints() : []; // TODO: Calling getHostVolumeSizes() is deactivated until UX is sorted out @@ -67,10 +58,7 @@ export async function getVolumeSystemData(): Promise<VolumeData[]> { const isOrphan = !refCount && !ownershipData.owner; // Custom mountpoint data - const pathParts = - vol.Options && vol.Options.device - ? parseDevicePath(vol.Options.device) - : undefined; + const pathParts = vol.Options && vol.Options.device ? parseDevicePath(vol.Options.device) : undefined; return { // Real volume and owner name to call delete on @@ -82,9 +70,7 @@ export async function getVolumeSystemData(): Promise<VolumeData[]> { refCount, isOrphan, mountpoint: pathParts ? pathParts.mountpoint : "", - fileSystem: pathParts - ? mountpoints.find((fs) => fs.mountpoint === pathParts.mountpoint) - : undefined, + fileSystem: pathParts ? mountpoints.find((fs) => fs.mountpoint === pathParts.mountpoint) : undefined }; }); } @@ -95,15 +81,13 @@ export function parseVolumeOwnershipData( ): VolumeOwnershipData { // Get the volume owner // TODO: Weak, derived from project name, may be exploited - const ownerContainer = containers.find((container) => - isVolumeOwner(container, vol) - ); + const ownerContainer = containers.find((container) => isVolumeOwner(container, vol)); return { // Real volume and owner name to call delete on name: vol.Name, // Do not assign to a fallback user, if the container has no owner it can be deleted by any user - owner: ownerContainer?.dnpName, + owner: ownerContainer?.dnpName }; } @@ -137,10 +121,7 @@ function parseVolumeLabels(labels?: { [labelName: string]: string }): { * Check if `dnp` is owner of `vol`, * meaning they have the same docker-compose project */ -export function isVolumeOwner( - dnp: { dnpName: string }, - vol: { Labels: { [key: string]: string } } -): boolean { +export function isVolumeOwner(dnp: { dnpName: string }, vol: { Labels: { [key: string]: string } }): boolean { const { normalizedOwnerName } = parseVolumeLabels(vol.Labels || {}); return normalizeProjectName(dnp.dnpName) === normalizedOwnerName; } diff --git a/packages/dockerApi/test/int/getNetworkAliasesMap.int.test.ts b/packages/dockerApi/test/int/getNetworkAliasesMap.int.test.ts index 699a808d3..85f326c12 100644 --- a/packages/dockerApi/test/int/getNetworkAliasesMap.int.test.ts +++ b/packages/dockerApi/test/int/getNetworkAliasesMap.int.test.ts @@ -8,11 +8,7 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn const testNetworkName = "docker_network_test"; const testNetworkSubnet = "172.40.0.0/16"; const testImage = "alpine:latest"; - const testContainerNames = [ - "test_container_1", - "test_container_2", - "test_container_3", - ]; + const testContainerNames = ["test_container_1", "test_container_2", "test_container_3"]; let testNetwork: Network; before(async () => { @@ -24,8 +20,8 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn Driver: "bridge", IPAM: { Driver: "default", - Config: [{ Subnet: testNetworkSubnet }], - }, + Config: [{ Subnet: testNetworkSubnet }] + } }); // Pull image and wait for completion @@ -49,7 +45,7 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn const container = await docker.createContainer({ Image: testImage, // Ensure the image is correctly referenced Cmd: ["sleep", "infinity"], // Use a command that is available in alpine - name: cn, + name: cn }); await container.start(); return container; @@ -65,8 +61,8 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn await testNetwork.connect({ Container: container.id, EndpointConfig: { - Aliases: [`alias_${containerName}`], - }, + Aliases: [`alias_${containerName}`] + } }); }) ); @@ -82,9 +78,7 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn expect(testContainerNames).to.include(key); // Check if the aliases array contains an alias starting with 'alias_test' - const hasTestAlias = value.aliases.some((alias) => - alias.startsWith("alias_test") - ); + const hasTestAlias = value.aliases.some((alias) => alias.startsWith("alias_test")); expect(hasTestAlias).to.be.true; }); }); @@ -99,7 +93,6 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn testContainerNames.map(async (cn) => { const container = docker.getContainer(cn); if (container) { - // eslint-disable-next-line @typescript-eslint/no-empty-function await container.remove({ force: true }).catch(() => {}); } }) @@ -107,7 +100,6 @@ describe("Ensure docker network config migration => getDockerNetworkNameFromSubn // Remove docker network if (testNetwork) { - // eslint-disable-next-line @typescript-eslint/no-empty-function await testNetwork.remove().catch(() => {}); } } diff --git a/packages/dockerApi/test/testUtils.ts b/packages/dockerApi/test/testUtils.ts index ea4d26853..4a655d652 100644 --- a/packages/dockerApi/test/testUtils.ts +++ b/packages/dockerApi/test/testUtils.ts @@ -1,8 +1,4 @@ -import { - InstalledPackageData, - PackageContainer, - VolumeMapping, -} from "@dappnode/types"; +import { InstalledPackageData, PackageContainer, VolumeMapping } from "@dappnode/types"; /** * Mock data @@ -32,7 +28,7 @@ export const mockContainer: PackageContainer = { defaultVolumes: [], dependencies: {}, origin: "", - avatarUrl: "", + avatarUrl: "" }; export const mockDnp: InstalledPackageData = { @@ -44,10 +40,10 @@ export const mockDnp: InstalledPackageData = { dependencies: {}, origin: "", avatarUrl: "", - containers: [mockContainer], + containers: [mockContainer] }; export const mockVolume: VolumeMapping = { host: "mock/mock/mock", - container: "mock/mock/mock", + container: "mock/mock/mock" }; diff --git a/packages/dockerApi/test/unit/dataUriToFile.test.ts b/packages/dockerApi/test/unit/dataUriToFile.test.ts index 9a0b492d2..0d2b45ab7 100644 --- a/packages/dockerApi/test/unit/dataUriToFile.test.ts +++ b/packages/dockerApi/test/unit/dataUriToFile.test.ts @@ -21,22 +21,19 @@ describe("Util: dataUriToFile", () => { // Check PNG signature const pngSignature = "89504e470d0a1a0a"; // Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 - expect(dataBuffer.toString("hex").slice(0, pngSignature.length)).to.equal( - pngSignature - ); + expect(dataBuffer.toString("hex").slice(0, pngSignature.length)).to.equal(pngSignature); }); it("should convert a JSON dataUri a valid json file", () => { const pathTo = `${testDir}/filedemo.json`; - const dataUri = - "data:application/json;base64,ewogICJuYW1lIjogIkFkYW0iLAogICJhZ2UiOiAyMwp9Cg=="; + const dataUri = "data:application/json;base64,ewogICJuYW1lIjogIkFkYW0iLAogICJhZ2UiOiAyMwp9Cg=="; dataUriToFile(dataUri, pathTo); // Verify written file const jsonData = JSON.parse(fs.readFileSync(pathTo, "utf8")); expect(jsonData).to.deep.equal({ name: "Adam", - age: 23, + age: 23 }); }); }); diff --git a/packages/dockerApi/test/unit/dockerApiSamples/containers.ts b/packages/dockerApi/test/unit/dockerApiSamples/containers.ts index 5daed2675..9f2fa3519 100644 --- a/packages/dockerApi/test/unit/dockerApiSamples/containers.ts +++ b/packages/dockerApi/test/unit/dockerApiSamples/containers.ts @@ -16,11 +16,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "5407d28e2cca82b4e83351b2f55d07469703223e2296934f5034a8922e99d76d", Image: "otpweb.dnp.dappnode.eth:0.0.3", - ImageID: - "sha256:5d1ec8daf089f9f84619441d736a2d0759352b59db1753d5397757d9578c432b", + ImageID: "sha256:5d1ec8daf089f9f84619441d736a2d0759352b59db1753d5397757d9578c432b", Labels: { - "com.docker.compose.config-hash": - "0d6bf9740d1622779193d37edf33e28ddb79bfc46ac6ea6c75132cea31df2e65", + "com.docker.compose.config-hash": "0d6bf9740d1622779193d37edf33e28ddb79bfc46ac6ea6c75132cea31df2e65", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "otpwebdnpdappnodeeth", @@ -37,8 +35,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "2531ac0ff8694fe54f6fb3587811bcfebcaecc382dead7e85e8ffd6cfd2c4705", + EndpointID: "2531ac0ff8694fe54f6fb3587811bcfebcaecc382dead7e85e8ffd6cfd2c4705", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -48,8 +45,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:09", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -72,11 +68,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "8a382e9a3b8ac449388470d06b98486b4fc965980fc5b72fd1c1cc77ae070484", Image: "nginx-proxy.dnp.dappnode.eth:0.0.3", - ImageID: - "sha256:c242241205d1c6eda03ce9d1bd01a3c3ef57313dd08245f704f698a850c0f44f", + ImageID: "sha256:c242241205d1c6eda03ce9d1bd01a3c3ef57313dd08245f704f698a850c0f44f", Labels: { - "com.docker.compose.config-hash": - "10e1a8c31de331f37740c753a39cbc86883447afded4c1e68a535dbba86aa227", + "com.docker.compose.config-hash": "10e1a8c31de331f37740c753a39cbc86883447afded4c1e68a535dbba86aa227", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "nginxproxydnpdappnodeeth", @@ -112,8 +106,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "nginxproxydnpdappnodeeth_vhost.d", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", + Source: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", Type: "volume" }, { @@ -140,8 +133,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "ec0a59a1019c2f72943b5d9032484a0ba67385e054cb36772f20a32b7d70efa4", + EndpointID: "ec0a59a1019c2f72943b5d9032484a0ba67385e054cb36772f20a32b7d70efa4", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -151,8 +143,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:06", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -182,11 +173,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "951426e3fa2cbfd49a5198840764383af3961c2b29ba33a6b5f3dd45b953db9f", Image: "vipnode.dnp.dappnode.eth:0.0.2", - ImageID: - "sha256:12c0721978f35ab4ca9dc3d13dee086c7c36dee954cb95fdfb49a58d52c2f8f5", + ImageID: "sha256:12c0721978f35ab4ca9dc3d13dee086c7c36dee954cb95fdfb49a58d52c2f8f5", Labels: { - "com.docker.compose.config-hash": - "117f4d9eff400b81a4b6ec81ff21d046833001116cce050d0600891da3a24888", + "com.docker.compose.config-hash": "117f4d9eff400b81a4b6ec81ff21d046833001116cce050d0600891da3a24888", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "vipnodednpdappnodeeth", @@ -202,8 +191,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "dncore_ethchaindnpdappnodeeth_data", Propagation: "", RW: false, - Source: - "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", + Source: "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", Type: "volume" } ], @@ -212,8 +200,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "c1b6f11f0ea3d45bd9d80c058e8018796809d000822b819a4eff465fcedc8dc0", + EndpointID: "c1b6f11f0ea3d45bd9d80c058e8018796809d000822b819a4eff465fcedc8dc0", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -223,8 +210,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:05", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -240,11 +226,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "539c5a2a32342365867689478b540d8d75c23d2dc1700bbed3b6171d754bb890", Image: "wifi.dnp.dappnode.eth:0.2.0", - ImageID: - "sha256:6ff4fc3d3200d3e56973b5eec60b0adfcd2ba890767e66d0295b7fd0c4e2d6f1", + ImageID: "sha256:6ff4fc3d3200d3e56973b5eec60b0adfcd2ba890767e66d0295b7fd0c4e2d6f1", Labels: { - "com.docker.compose.config-hash": - "56b102ddac3685802f0e1943c555b29d73ed7e6e6d7abd66e11232fe900023c9", + "com.docker.compose.config-hash": "56b102ddac3685802f0e1943c555b29d73ed7e6e6d7abd66e11232fe900023c9", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -278,8 +262,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -295,11 +278,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "02b71c411d1d2e503afad679ab1c16a3e5cf086d5a298476fb30548b62d716f0", Image: "admin.dnp.dappnode.eth:0.2.3", - ImageID: - "sha256:d524055bf341ca0729920893feb7ff68c4f0308ddce2af7fa9e78b707f7a26c7", + ImageID: "sha256:d524055bf341ca0729920893feb7ff68c4f0308ddce2af7fa9e78b707f7a26c7", Labels: { - "com.docker.compose.config-hash": - "c6c60533a7e09f813907dcdb20d026194bb81303798799c31308a63d7ce2b826", + "com.docker.compose.config-hash": "c6c60533a7e09f813907dcdb20d026194bb81303798799c31308a63d7ce2b826", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -324,8 +305,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "076493fb103dc5295f587bcab6df39e83ee6b71409ad735f9c18801a3e46254b", + EndpointID: "076493fb103dc5295f587bcab6df39e83ee6b71409ad735f9c18801a3e46254b", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -337,8 +317,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:09", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -367,11 +346,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "514b892b5e537f77515ee3278915a5fd1bf80228e8df6ed64b35c1a0fbdfbec0", Image: "vpn.dnp.dappnode.eth:0.2.0", - ImageID: - "sha256:02a7d21fa690d87a5facaf40f3ebee9e6c3ca8dee8b432af26a1a11753350dbd", + ImageID: "sha256:02a7d21fa690d87a5facaf40f3ebee9e6c3ca8dee8b432af26a1a11753350dbd", Labels: { - "com.docker.compose.config-hash": - "178eee2b5d804afa79b3502a7158445b704399c735a7d3f305622dd7c9b95b1c", + "com.docker.compose.config-hash": "178eee2b5d804afa79b3502a7158445b704399c735a7d3f305622dd7c9b95b1c", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -447,8 +424,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "bd086d83ba265fce4d93349448b8cedfe5bb7565ccd89cf2fad3d3dba7d441d9", + EndpointID: "bd086d83ba265fce4d93349448b8cedfe5bb7565ccd89cf2fad3d3dba7d441d9", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -460,8 +436,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:04", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -484,11 +459,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "51eaaba5c184da5605bf5ce1af4026592cdb3be1d6ff209a5cf0e3cf09c3f6a4", Image: "dappmanager.dnp.dappnode.eth:0.2.3", - ImageID: - "sha256:2ff401547f016466c6d99ec54647025cd842e1a31e5bff53742ba14eaabbdfbb", + ImageID: "sha256:2ff401547f016466c6d99ec54647025cd842e1a31e5bff53742ba14eaabbdfbb", Labels: { - "com.docker.compose.config-hash": - "263de2c2d31b95658c69686680b78c9af71c0957f2e56c04acad3958cc4e6f16", + "com.docker.compose.config-hash": "263de2c2d31b95658c69686680b78c9af71c0957f2e56c04acad3958cc4e6f16", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -511,8 +484,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "dncore_dappmanagerdnpdappnodeeth_data", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/dncore_dappmanagerdnpdappnodeeth_data/_data", + Source: "/var/lib/docker/volumes/dncore_dappmanagerdnpdappnodeeth_data/_data", Type: "volume" }, { @@ -529,8 +501,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "98db1673a9e729ba76c4349c13fbaa4e7113d0fe0ba9d1c46035c125e051bc0a", + EndpointID: "98db1673a9e729ba76c4349c13fbaa4e7113d0fe0ba9d1c46035c125e051bc0a", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -542,8 +513,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:07", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -559,11 +529,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "3dd5e6cd5756b7349636515bb0f50f3c9e35d75909ab9dfcb9c76cb9e54ab9c7", Image: "bind.dnp.dappnode.eth:0.2.0", - ImageID: - "sha256:af8539f3b3f2f5637afab068da01a3fdbe631ff812631ebeb70c713448b8dde0", + ImageID: "sha256:af8539f3b3f2f5637afab068da01a3fdbe631ff812631ebeb70c713448b8dde0", Labels: { - "com.docker.compose.config-hash": - "1b53894c004445d1f33cbd15bd4ff44f589d5e0c4d58bebda4d76beb6ede6cf9", + "com.docker.compose.config-hash": "1b53894c004445d1f33cbd15bd4ff44f589d5e0c4d58bebda4d76beb6ede6cf9", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -587,8 +555,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "c0b656885a60356361e325a2e53c3043a2e485293c8e0346a37932b24c998ae6", + EndpointID: "c0b656885a60356361e325a2e53c3043a2e485293c8e0346a37932b24c998ae6", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -600,8 +567,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:02", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -625,11 +591,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "e1766fd7a9d8110398b66c7b0f68fe625ee856f49526b987a54537028448476b", Image: "ethchain.dnp.dappnode.eth:0.2.1", - ImageID: - "sha256:646da4b970b2fb100012bced7abe4e8c442987edb2072f8e4f3bd298dded9950", + ImageID: "sha256:646da4b970b2fb100012bced7abe4e8c442987edb2072f8e4f3bd298dded9950", Labels: { - "com.docker.compose.config-hash": - "31118f2e2d1579af7b8cc3d858317631f4d5f804ba1d8e1cee7036947589d6c9", + "com.docker.compose.config-hash": "31118f2e2d1579af7b8cc3d858317631f4d5f804ba1d8e1cee7036947589d6c9", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -637,16 +601,13 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ "com.docker.compose.version": "1.22.0", "dappnode.dnp.default.environment": '["EXTRA_OPTS=--warp-barrier 8540000","EXTRA_OPTS_GETH=","DEFAULT_CLIENT=PARITY"]', - "dappnode.dnp.default.ports": - '["30303:30303","30303:30303/udp","30304:30304/udp"]', + "dappnode.dnp.default.ports": '["30303:30303","30303:30303/udp","30304:30304/udp"]', "dappnode.dnp.default.volumes": '["ethchaindnpdappnodeeth_data:/root/.local/share/io.parity.ethereum","ethchaindnpdappnodeeth_geth:/root/.ethereum/","ethchaindnpdappnodeeth_identity:/root/identity/"]', "dappnode.dnp.dependencies": "{}", - "dappnode.dnp.avatar": - "/ipfs/QmQnHxr4YAVdtqzHnsDYvmXizxptSYyaj3YwTjoiLshVwF", + "dappnode.dnp.avatar": "/ipfs/QmQnHxr4YAVdtqzHnsDYvmXizxptSYyaj3YwTjoiLshVwF", "dappnode.dnp.chain": "ethereum", - "dappnode.dnp.origin": - "/ipfs/QmeBfnwgsNcEmbmxENBWtgkv5YZsAhiaDsoYd7nMTV1wKV", + "dappnode.dnp.origin": "/ipfs/QmeBfnwgsNcEmbmxENBWtgkv5YZsAhiaDsoYd7nMTV1wKV", "dappnode.dnp.isCore": "true" }, Mounts: [ @@ -657,8 +618,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "dncore_ethchaindnpdappnodeeth_data", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", + Source: "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", Type: "volume" } ], @@ -667,8 +627,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "9e123105252472ccbf966d30829f33715efb58d4afcce2daa54ae6ca3b18a617", + EndpointID: "9e123105252472ccbf966d30829f33715efb58d4afcce2daa54ae6ca3b18a617", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -680,8 +639,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:06", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -716,11 +674,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "a4ae8b09bc9b2037ff76f99436ddf1890e1215c2a17533ab73445726b41b2bef", Image: "ipfs.dnp.dappnode.eth:0.2.2", - ImageID: - "sha256:163a33c60906e36833306c0c5fb4e742a84173c254cdf571d450370bbfd50751", + ImageID: "sha256:163a33c60906e36833306c0c5fb4e742a84173c254cdf571d450370bbfd50751", Labels: { - "com.docker.compose.config-hash": - "53e42eef9f08ede81dc7d3a05e64b9c64400250fc881962b0f9ebd0b485363a5", + "com.docker.compose.config-hash": "53e42eef9f08ede81dc7d3a05e64b9c64400250fc881962b0f9ebd0b485363a5", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -746,8 +702,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "dncore_ipfsdnpdappnodeeth_export", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/dncore_ipfsdnpdappnodeeth_export/_data", + Source: "/var/lib/docker/volumes/dncore_ipfsdnpdappnodeeth_export/_data", Type: "volume" } ], @@ -756,8 +711,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "db3741f01bc559ab2613aac8a14625bb79745613a8ef30a79bcd732fcecc4dfd", + EndpointID: "db3741f01bc559ab2613aac8a14625bb79745613a8ef30a79bcd732fcecc4dfd", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -769,8 +723,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:05", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -817,11 +770,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "12cf3e376374f665d05a78bb20641cd9d5e36b7ab418b0ebec7c77b6798156c0", Image: "ethforward.dnp.dappnode.eth:0.2.1", - ImageID: - "sha256:8e3f5f9ed14abb6c5fe008fa595136cdaaf1c94e7544b5c4f3750275d2c90b28", + ImageID: "sha256:8e3f5f9ed14abb6c5fe008fa595136cdaaf1c94e7544b5c4f3750275d2c90b28", Labels: { - "com.docker.compose.config-hash": - "4510ed11939156c0bf4e0784a3c661a866beb9dab0c699a0d65dbd7b5e9ce175", + "com.docker.compose.config-hash": "4510ed11939156c0bf4e0784a3c661a866beb9dab0c699a0d65dbd7b5e9ce175", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", @@ -834,8 +785,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "f880d10e3f26d3266f604eeb1d1435886a872e6438262adf8abc632d8c1e5ff1", + EndpointID: "f880d10e3f26d3266f604eeb1d1435886a872e6438262adf8abc632d8c1e5ff1", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -847,8 +797,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:03", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -864,11 +813,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "f789e9b7f00d7292c0db1f83b4dac063ce4a84d2bb3d55d12f9f492b7cbcbb2c", Image: "swarm.dnp.dappnode.eth:0.1.0", - ImageID: - "sha256:82cf739f2893f5f02c6c5295d28250dead81f2025734e1a2c963df126ea2ec54", + ImageID: "sha256:82cf739f2893f5f02c6c5295d28250dead81f2025734e1a2c963df126ea2ec54", Labels: { - "com.docker.compose.config-hash": - "5e698cef3803472edc1fcc3bba0fe16c24f3b65a8b97b57551f555a2a732b99f", + "com.docker.compose.config-hash": "5e698cef3803472edc1fcc3bba0fe16c24f3b65a8b97b57551f555a2a732b99f", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "swarmdnpdappnodeeth", @@ -893,8 +840,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "125ccd94b2a75f0cd40862a09b71e1aac702f59f2cfa42fa00263d159103f8d8", + EndpointID: "125ccd94b2a75f0cd40862a09b71e1aac702f59f2cfa42fa00263d159103f8d8", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -904,8 +850,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:07", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -934,11 +879,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "b7f32fcefcd4bfb34d0c293378993e4a40eb3e62d8a928c4f183065834a10fb2", Image: "letsencrypt-nginx.dnp.dappnode.eth:0.0.4", - ImageID: - "sha256:1658e6d884c600b347f91f62a64331d3cb7dce89148b4a69d86fac3ad36626f4", + ImageID: "sha256:1658e6d884c600b347f91f62a64331d3cb7dce89148b4a69d86fac3ad36626f4", Labels: { - "com.docker.compose.config-hash": - "ca8fea4d0f0081049a83a348ccf203dc04fd7301b79634e5eb1282b88a16753e", + "com.docker.compose.config-hash": "ca8fea4d0f0081049a83a348ccf203dc04fd7301b79634e5eb1282b88a16753e", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "letsencryptnginxdnpdappnodeeth", @@ -963,8 +906,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "nginxproxydnpdappnodeeth_vhost.d", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", + Source: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", Type: "volume" }, { @@ -991,8 +933,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "c0f21fc23fa535a659b3feb92464c366e287cc50f6208f8a6670674c78b4c00f", + EndpointID: "c0f21fc23fa535a659b3feb92464c366e287cc50f6208f8a6670674c78b4c00f", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -1002,8 +943,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:08", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -1019,18 +959,15 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "c944a1549ba675b7229b55370cfd2f54dca1f86050fbef7df4ba453398f93c24", Image: "ipfs-replicator.dnp.dappnode.eth:0.1.0", - ImageID: - "sha256:09835191918920701cea65129dd5e0f2d758341fd1a0fe3d6cb40ec7de1954fb", + ImageID: "sha256:09835191918920701cea65129dd5e0f2d758341fd1a0fe3d6cb40ec7de1954fb", Labels: { - "com.docker.compose.config-hash": - "da6f3c5917724f786a965648350452b52b3aba9274616705d86c350978b183cd", + "com.docker.compose.config-hash": "da6f3c5917724f786a965648350452b52b3aba9274616705d86c350978b183cd", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "ipfsreplicatordnpdappnodeeth", "com.docker.compose.service": "ipfs-replicator.dnp.dappnode.eth", "com.docker.compose.version": "1.20.1", - "dappnode.dnp.origin": - "/ipfs/QmYfVW2LNHH8ZXa6KJmfFAz5zCQ8YHh2ZPt6aQmezJcbL7" + "dappnode.dnp.origin": "/ipfs/QmYfVW2LNHH8ZXa6KJmfFAz5zCQ8YHh2ZPt6aQmezJcbL7" }, Mounts: [ { @@ -1040,8 +977,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Name: "ipfsreplicatordnpdappnodeeth_pin-data", Propagation: "", RW: true, - Source: - "/var/lib/docker/volumes/ipfsreplicatordnpdappnodeeth_pin-data/_data", + Source: "/var/lib/docker/volumes/ipfsreplicatordnpdappnodeeth_pin-data/_data", Type: "volume" } ], @@ -1050,8 +986,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "88ccad37b5c38e3504017442ed9b04c4fcb25ca1f72292ddf24e089af510e08b", + EndpointID: "88ccad37b5c38e3504017442ed9b04c4fcb25ca1f72292ddf24e089af510e08b", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -1061,8 +996,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:04", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -1079,19 +1013,16 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "ffc3f4ed380ad42b7f847228862ad4de4ab471229bb5e1ed0aef46d4561309d2", Image: "goerli-geth.dnp.dappnode.eth:0.2.2", - ImageID: - "sha256:5dc0c9530448276bd102accaad853a252dd8089f2900c9f2c756fae0b6f6d8ec", + ImageID: "sha256:5dc0c9530448276bd102accaad853a252dd8089f2900c9f2c756fae0b6f6d8ec", Labels: { - "com.docker.compose.config-hash": - "acaf0f292fa641ac114e9a62dd9581b167379a433cad7f0f796ae1e8c427aab2", + "com.docker.compose.config-hash": "acaf0f292fa641ac114e9a62dd9581b167379a433cad7f0f796ae1e8c427aab2", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "goerligethdnpdappnodeeth", "com.docker.compose.service": "goerli-geth.dnp.dappnode.eth", "com.docker.compose.version": "1.20.1", "dappnode.dnp.chain": "ethereum", - portsToClose: - '[{"number":32769,"type":"TCP"},{"number":32771,"type":"UDP"},{"number":32770,"type":"UDP"}]' + portsToClose: '[{"number":32769,"type":"TCP"},{"number":32771,"type":"UDP"},{"number":32770,"type":"UDP"}]' }, Mounts: [ { @@ -1110,8 +1041,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "5efa0a2388a402fd3ecd7ae5ab0d503c4f528767d0e00e59f255013d5405f1f4", + EndpointID: "5efa0a2388a402fd3ecd7ae5ab0d503c4f528767d0e00e59f255013d5405f1f4", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -1121,8 +1051,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:03", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -1157,11 +1086,9 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "94bde8655e2d8daca033486ef46e7d270c4f4b6f6c18b820d80c2cbf211130bd", Image: "ln.dnp.dappnode.eth:0.1.1", - ImageID: - "sha256:41214dd9be6c51b33b6872f174151c69f83409d33a9eaa7ee78032faa1b03c69", + ImageID: "sha256:41214dd9be6c51b33b6872f174151c69f83409d33a9eaa7ee78032faa1b03c69", Labels: { - "com.docker.compose.config-hash": - "a458dcb93640f82123abf4e5beccb7dcb1773f6ef58af65b322581da551491b1", + "com.docker.compose.config-hash": "a458dcb93640f82123abf4e5beccb7dcb1773f6ef58af65b322581da551491b1", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "lndnpdappnodeeth", @@ -1186,8 +1113,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "f6bdd575b22ce0df36bdb408ea9c1f3ae291ab398f5aecc79f63ffd8e6f3fe41", + EndpointID: "f6bdd575b22ce0df36bdb408ea9c1f3ae291ab398f5aecc79f63ffd8e6f3fe41", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -1197,8 +1123,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:00:02", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -1233,19 +1158,16 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ }, Id: "d01badf202548868538e0435163e66a12f5bbb253e82150ed951e89a4c13690d", Image: "wamp.dnp.dappnode.eth:0.2.0", - ImageID: - "sha256:d8e65977f9e219b3b305b7f554e19141819c4749cebf5ec3d44c23ee0a748ac1", + ImageID: "sha256:d8e65977f9e219b3b305b7f554e19141819c4749cebf5ec3d44c23ee0a748ac1", Labels: { - "com.docker.compose.config-hash": - "7886a2bf0a84e2766732c8506bed5817890f583d8f26908dd5c1c01300fac623", + "com.docker.compose.config-hash": "7886a2bf0a84e2766732c8506bed5817890f583d8f26908dd5c1c01300fac623", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dncore", "com.docker.compose.service": "wamp.dnp.dappnode.eth", "com.docker.compose.version": "1.22.0", "org.label-schema.build-date": "", - "org.label-schema.description": - "Quickstart template for application development with Crossbar.io", + "org.label-schema.description": "Quickstart template for application development with Crossbar.io", "org.label-schema.name": "Crossbar.io Starter Template", "org.label-schema.schema-version": "1.0", "org.label-schema.url": "http://crossbar.io", @@ -1260,8 +1182,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Networks: { [dncoreNetwork]: { Aliases: null, - EndpointID: - "24f23c27b47c38ecf9f4a64c18084312ec3ed4529b160346765d915692298ab5", + EndpointID: "24f23c27b47c38ecf9f4a64c18084312ec3ed4529b160346765d915692298ab5", Gateway: "172.33.0.1", GlobalIPv6Address: "", GlobalIPv6PrefixLen: 0, @@ -1273,8 +1194,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPv6Gateway: "", Links: null, MacAddress: "02:42:ac:21:01:08", - NetworkID: - "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" + NetworkID: "71794cdb4278aafb8339d8200a56a971e36e350eb67aa90b7443b52b831c1f25" } } }, @@ -1299,8 +1219,7 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ Id: "ba4765113dd6016da8b35dfe367493186f3bfd34d88eca03ccf894f7045710fa", Names: ["/DAppNodePackage-grafana.dms.dnp.dappnode.eth"], Image: "grafana.dms.dnp.dappnode.eth:1.0.1", - ImageID: - "sha256:269651b5aa5472d188fda97a937fd0bf861edc7a73122d66591af0e464559f70", + ImageID: "sha256:269651b5aa5472d188fda97a937fd0bf861edc7a73122d66591af0e464559f70", Command: "/run.sh grafana-server --homepath=/usr/share/grafana --config=/etc/grafana/grafana.ini --packaging=docker", Created: 1618303536, @@ -1313,19 +1232,15 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ } ], Labels: { - "com.docker.compose.config-hash": - "2e0732ce7e64078b071b27e65b7d60e4c05913b8e9aa3d7a1f525d7ae80ed5f7", + "com.docker.compose.config-hash": "2e0732ce7e64078b071b27e65b7d60e4c05913b8e9aa3d7a1f525d7ae80ed5f7", "com.docker.compose.container-number": "1", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "dmsdnpdappnodeeth", - "com.docker.compose.project.config_files": - "/usr/src/app/dnp_repo/dms.dnp.dappnode.eth/docker-compose.yml", - "com.docker.compose.project.working_dir": - "/usr/src/app/dnp_repo/dms.dnp.dappnode.eth", + "com.docker.compose.project.config_files": "/usr/src/app/dnp_repo/dms.dnp.dappnode.eth/docker-compose.yml", + "com.docker.compose.project.working_dir": "/usr/src/app/dnp_repo/dms.dnp.dappnode.eth", "com.docker.compose.service": "grafana", "com.docker.compose.version": "1.25.5", - "dappnode.dnp.avatar": - "/ipfs/QmaZZVsVqaWwVLe36HhvKj3QEPt7hM1GL8kemNvsZd5F5x", + "dappnode.dnp.avatar": "/ipfs/QmaZZVsVqaWwVLe36HhvKj3QEPt7hM1GL8kemNvsZd5F5x", "dappnode.dnp.default.volumes": '["grafana_data:/var/lib/grafana"]', "dappnode.dnp.dependencies": "{}", "dappnode.dnp.dnpName": "dms.dnp.dappnode.eth", @@ -1345,10 +1260,8 @@ export const dockerApiResponseContainers: Docker.ContainerInfo[] = [ IPAMConfig: null, Links: null, Aliases: null, - NetworkID: - "e843eba0ca739a4008669e413147785777da160262ed5d46e27e625329c65ce8", - EndpointID: - "e072374b357cdef2a5cc8c9581b58c834bd58f9851bf93583fc4f85a2dd61952", + NetworkID: "e843eba0ca739a4008669e413147785777da160262ed5d46e27e625329c65ce8", + EndpointID: "e072374b357cdef2a5cc8c9581b58c834bd58f9851bf93583fc4f85a2dd61952", Gateway: "172.33.0.1", IPAddress: "172.33.0.3", IPPrefixLen: 16, diff --git a/packages/dockerApi/test/unit/getHostVolumeSizes.test.ts b/packages/dockerApi/test/unit/getHostVolumeSizes.test.ts index d8568e893..10f38bb81 100644 --- a/packages/dockerApi/test/unit/getHostVolumeSizes.test.ts +++ b/packages/dockerApi/test/unit/getHostVolumeSizes.test.ts @@ -3,7 +3,6 @@ import { expect } from "chai"; import rewiremock from "rewiremock/node.js"; describe.skip("getHostVolumeSizes", () => { - /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ async function getMock(shellHost: (cmd: string) => Promise<string>) { const mock = await rewiremock.around( () => import("../../src/getHostVolumeSizes.js"), @@ -30,11 +29,10 @@ describe.skip("getHostVolumeSizes", () => { const volName = "bitcoin_data"; const volDevicePaths = { - [volName]: - "/mnt/volume_ams3_01/dappnode-volumes/bitcoin.dnp.dappnode.eth/bitcoin_data", + [volName]: "/mnt/volume_ams3_01/dappnode-volumes/bitcoin.dnp.dappnode.eth/bitcoin_data" }; const expectedVolSizes = { - [volName]: "824204410", + [volName]: "824204410" }; const volSizes = await getHostVolumeSizes(volDevicePaths); diff --git a/packages/dockerApi/test/unit/network.test.ts b/packages/dockerApi/test/unit/network.test.ts index 5b38ec6f8..636d6408d 100644 --- a/packages/dockerApi/test/unit/network.test.ts +++ b/packages/dockerApi/test/unit/network.test.ts @@ -4,7 +4,7 @@ import { docker, dockerCreateNetwork, dockerNetworkConnect, - getNetworkAliasesIpsMapNotThrow, + getNetworkAliasesIpsMapNotThrow } from "../../src/index.js"; import Dockerode from "dockerode"; @@ -14,38 +14,31 @@ describe("dockerApi => network", function () { const dockerNetworkName = "dncore_test"; const dockerImageTest = "alpine:latest"; - const containerNames = [ - "test_container_1", - "test_container_2", - "test_container_3", - ]; // Define container names + const containerNames = ["test_container_1", "test_container_2", "test_container_3"]; // Define container names before(async () => { // Pull image and wait for completion await new Promise<void>((resolve, reject) => { - docker.pull( - dockerImageTest, - (err: Error, stream: NodeJS.ReadableStream) => { - if (err) { - reject(err); - } else { - docker.modem.followProgress(stream, (err) => { - if (err) { - reject(err); - } else { - resolve(); - } - }); - } + docker.pull(dockerImageTest, (err: Error, stream: NodeJS.ReadableStream) => { + if (err) { + reject(err); + } else { + docker.modem.followProgress(stream, (err) => { + if (err) { + reject(err); + } else { + resolve(); + } + }); } - ); + }); }); await Promise.all( containerNames.map(async (cn) => { const container = await docker.createContainer({ Image: dockerImageTest, Cmd: ["tail", "-f", "/dev/null"], // Keep the container running - name: cn, + name: cn }); await container.start(); }) @@ -56,8 +49,7 @@ describe("dockerApi => network", function () { await dockerCreateNetwork(dockerNetworkName); const network = docker.getNetwork(dockerNetworkName); - const networkInspect = - (await network.inspect()) as Dockerode.NetworkInspectInfo; + const networkInspect = (await network.inspect()) as Dockerode.NetworkInspectInfo; expect(networkInspect.Name).to.deep.equal(dockerNetworkName); }); @@ -66,19 +58,16 @@ describe("dockerApi => network", function () { containerNames.map( async (cn) => await dockerNetworkConnect(dockerNetworkName, cn, { - Aliases: [cn], + Aliases: [cn] }) ) ); const network = docker.getNetwork(dockerNetworkName); - const networkInspect = - (await network.inspect()) as Dockerode.NetworkInspectInfo; + const networkInspect = (await network.inspect()) as Dockerode.NetworkInspectInfo; const containersInNetwork = networkInspect.Containers; if (!containersInNetwork) throw Error(`Expected containers in network`); - const containersNames = Object.values(containersInNetwork).map( - (c) => c.Name - ); + const containersNames = Object.values(containersInNetwork).map((c) => c.Name); expect(containersNames).to.have.deep.members(containerNames); }); @@ -101,15 +90,12 @@ describe("dockerApi => network", function () { }); it("should disconnect all docker containers from a docker network", async () => { - await disconnectAllContainersFromNetwork( - docker.getNetwork(dockerNetworkName) - ); + await disconnectAllContainersFromNetwork(docker.getNetwork(dockerNetworkName)); }); after(async () => { // remove containers - for (const cn of containerNames) - await docker.getContainer(cn).remove({ force: true }); + for (const cn of containerNames) await docker.getContainer(cn).remove({ force: true }); // remove docker network await docker.getNetwork(dockerNetworkName).remove(); diff --git a/packages/dockerApi/test/unit/parseContainerInfo.test.ts b/packages/dockerApi/test/unit/parseContainerInfo.test.ts index 9e7fe6513..2b031090b 100644 --- a/packages/dockerApi/test/unit/parseContainerInfo.test.ts +++ b/packages/dockerApi/test/unit/parseContainerInfo.test.ts @@ -1,16 +1,13 @@ import "mocha"; import { expect } from "chai"; import { PackageContainer, PortProtocol } from "@dappnode/types"; -import { - parseContainerInfo, - parseDnpNameFromContainerName, -} from "../../src/index.js"; +import { parseContainerInfo, parseDnpNameFromContainerName } from "../../src/index.js"; import { dockerApiResponseContainers } from "./dockerApiSamples/containers.js"; describe("modules / docker / parseDnpNameFromContainerName", () => { const testCases = { "DAppNodeCore-api.wireguard.dnp.dappnode.eth": "wireguard.dnp.dappnode.eth", - "DAppNodePackage-geth.dnp.dappnode.eth": "geth.dnp.dappnode.eth", + "DAppNodePackage-geth.dnp.dappnode.eth": "geth.dnp.dappnode.eth" }; for (const [containerName, dnpName] of Object.entries(testCases)) { @@ -27,8 +24,7 @@ describe("modules / docker / parseContainerInfo", function () { const expectedContainers: PackageContainer[] = [ { - containerId: - "5407d28e2cca82b4e83351b2f55d07469703223e2296934f5034a8922e99d76d", + containerId: "5407d28e2cca82b4e83351b2f55d07469703223e2296934f5034a8922e99d76d", containerName: "DAppNodePackage-otpweb.dnp.dappnode.eth", serviceName: "otpweb.dnp.dappnode.eth", instanceName: "", @@ -43,8 +39,8 @@ describe("modules / docker / parseContainerInfo", function () { { container: 80, protocol: PortProtocol.TCP, - deletable: true, - }, + deletable: true + } ], volumes: [], networks: [{ name: "dncore_network", ip: "172.33.0.9" }], @@ -53,15 +49,14 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest", - "letsencrypt-nginx.dnp.dappnode.eth": "latest", + "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, defaultPorts: [], avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "8a382e9a3b8ac449388470d06b98486b4fc965980fc5b72fd1c1cc77ae070484", + containerId: "8a382e9a3b8ac449388470d06b98486b4fc965980fc5b72fd1c1cc77ae070484", containerName: "DAppNodePackage-nginx-proxy.dnp.dappnode.eth", serviceName: "nginx-proxy.dnp.dappnode.eth", instanceName: "", @@ -77,39 +72,39 @@ describe("modules / docker / parseContainerInfo", function () { host: 443, container: 443, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { host: 80, container: 80, protocol: PortProtocol.TCP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/root/certs", - container: "/etc/nginx/certs", + container: "/etc/nginx/certs" }, { host: "", container: "/etc/nginx/dhparam", - name: "1f6ceacbdb011451622aa4a5904309765dc2bfb0f4affe163f4e22cba4f7725b", + name: "1f6ceacbdb011451622aa4a5904309765dc2bfb0f4affe163f4e22cba4f7725b" }, { host: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", container: "/etc/nginx/vhost.d", - name: "nginxproxydnpdappnodeeth_vhost.d", + name: "nginxproxydnpdappnodeeth_vhost.d" }, { host: "/var/run/docker.sock", - container: "/tmp/docker.sock", + container: "/tmp/docker.sock" }, { host: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_html/_data", container: "/usr/share/nginx/html", - name: "nginxproxydnpdappnodeeth_html", - }, + name: "nginxproxydnpdappnodeeth_html" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.6" }], state: "running", @@ -117,11 +112,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "951426e3fa2cbfd49a5198840764383af3961c2b29ba33a6b5f3dd45b953db9f", + containerId: "951426e3fa2cbfd49a5198840764383af3961c2b29ba33a6b5f3dd45b953db9f", containerName: "DAppNodePackage-vipnode.dnp.dappnode.eth", serviceName: "vipnode.dnp.dappnode.eth", instanceName: "", @@ -137,8 +131,8 @@ describe("modules / docker / parseContainerInfo", function () { { host: "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", container: "/app/.ethchain", - name: "dncore_ethchaindnpdappnodeeth_data", - }, + name: "dncore_ethchaindnpdappnodeeth_data" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.5" }], state: "running", @@ -146,11 +140,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "539c5a2a32342365867689478b540d8d75c23d2dc1700bbed3b6171d754bb890", + containerId: "539c5a2a32342365867689478b540d8d75c23d2dc1700bbed3b6171d754bb890", containerName: "DAppNodeCore-wifi.dnp.dappnode.eth", serviceName: "wifi.dnp.dappnode.eth", instanceName: "", @@ -165,8 +158,8 @@ describe("modules / docker / parseContainerInfo", function () { volumes: [ { host: "/var/run/docker.sock", - container: "/var/run/docker.sock", - }, + container: "/var/run/docker.sock" + } ], networks: [{ name: "dncore_network", ip: "" }], state: "exited", @@ -174,11 +167,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: 137, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "02b71c411d1d2e503afad679ab1c16a3e5cf086d5a298476fb30548b62d716f0", + containerId: "02b71c411d1d2e503afad679ab1c16a3e5cf086d5a298476fb30548b62d716f0", containerName: "DAppNodeCore-admin.dnp.dappnode.eth", serviceName: "admin.dnp.dappnode.eth", instanceName: "", @@ -194,20 +186,20 @@ describe("modules / docker / parseContainerInfo", function () { host: 8090, container: 8090, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { container: 80, protocol: PortProtocol.TCP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/dncore_vpndnpdappnodeeth_shared/_data", container: "/usr/www/openvpn/cred", - name: "dncore_vpndnpdappnodeeth_shared", - }, + name: "dncore_vpndnpdappnodeeth_shared" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.9" }], state: "running", @@ -215,11 +207,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "514b892b5e537f77515ee3278915a5fd1bf80228e8df6ed64b35c1a0fbdfbec0", + containerId: "514b892b5e537f77515ee3278915a5fd1bf80228e8df6ed64b35c1a0fbdfbec0", containerName: "DAppNodeCore-vpn.dnp.dappnode.eth", serviceName: "vpn.dnp.dappnode.eth", instanceName: "", @@ -235,41 +226,41 @@ describe("modules / docker / parseContainerInfo", function () { host: 1194, container: 1194, protocol: PortProtocol.UDP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/dncore_vpndnpdappnodeeth_config/_data", container: "/etc/openvpn", - name: "dncore_vpndnpdappnodeeth_config", + name: "dncore_vpndnpdappnodeeth_config" }, { host: "/etc/hostname", - container: "/etc/vpnname", + container: "/etc/vpnname" }, { host: "/lib/modules", - container: "/lib/modules", + container: "/lib/modules" }, { host: "/usr/src/dappnode/config", - container: "/usr/src/app/config", + container: "/usr/src/app/config" }, { host: "/var/lib/docker/volumes/dncore_vpndnpdappnodeeth_data/_data", container: "/usr/src/app/secrets", - name: "dncore_vpndnpdappnodeeth_data", + name: "dncore_vpndnpdappnodeeth_data" }, { host: "/var/run/docker.sock", - container: "/var/run/docker.sock", + container: "/var/run/docker.sock" }, { host: "/var/lib/docker/volumes/dncore_vpndnpdappnodeeth_shared/_data", container: "/var/spool/openvpn", - name: "dncore_vpndnpdappnodeeth_shared", - }, + name: "dncore_vpndnpdappnodeeth_shared" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.4" }], state: "running", @@ -277,11 +268,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "51eaaba5c184da5605bf5ce1af4026592cdb3be1d6ff209a5cf0e3cf09c3f6a4", + containerId: "51eaaba5c184da5605bf5ce1af4026592cdb3be1d6ff209a5cf0e3cf09c3f6a4", containerName: "DAppNodeCore-dappmanager.dnp.dappnode.eth", serviceName: "dappmanager.dnp.dappnode.eth", instanceName: "", @@ -296,17 +286,17 @@ describe("modules / docker / parseContainerInfo", function () { volumes: [ { host: "/usr/src/dappnode/DNCORE", - container: "/usr/src/app/DNCORE", + container: "/usr/src/app/DNCORE" }, { host: "/var/lib/docker/volumes/dncore_dappmanagerdnpdappnodeeth_data/_data", container: "/usr/src/app/dnp_repo", - name: "dncore_dappmanagerdnpdappnodeeth_data", + name: "dncore_dappmanagerdnpdappnodeeth_data" }, { host: "/var/run/docker.sock", - container: "/var/run/docker.sock", - }, + container: "/var/run/docker.sock" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.7" }], state: "running", @@ -314,11 +304,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "3dd5e6cd5756b7349636515bb0f50f3c9e35d75909ab9dfcb9c76cb9e54ab9c7", + containerId: "3dd5e6cd5756b7349636515bb0f50f3c9e35d75909ab9dfcb9c76cb9e54ab9c7", containerName: "DAppNodeCore-bind.dnp.dappnode.eth", serviceName: "bind.dnp.dappnode.eth", instanceName: "", @@ -333,15 +322,15 @@ describe("modules / docker / parseContainerInfo", function () { { container: 53, protocol: PortProtocol.UDP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/dncore_binddnpdappnodeeth_data/_data", container: "/etc/bind", - name: "dncore_binddnpdappnodeeth_data", - }, + name: "dncore_binddnpdappnodeeth_data" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.2" }], state: "running", @@ -349,11 +338,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "e1766fd7a9d8110398b66c7b0f68fe625ee856f49526b987a54537028448476b", + containerId: "e1766fd7a9d8110398b66c7b0f68fe625ee856f49526b987a54537028448476b", containerName: "DAppNodeCore-ethchain.dnp.dappnode.eth", serviceName: "ethchain.dnp.dappnode.eth", instanceName: "", @@ -369,81 +357,79 @@ describe("modules / docker / parseContainerInfo", function () { host: 30303, container: 30303, protocol: PortProtocol.TCP, - deletable: false, + deletable: false }, { host: 30303, container: 30303, protocol: PortProtocol.UDP, - deletable: false, + deletable: false }, { host: 30304, container: 30304, protocol: PortProtocol.UDP, - deletable: false, - }, + deletable: false + } ], volumes: [ { host: "/var/lib/docker/volumes/dncore_ethchaindnpdappnodeeth_data/_data", container: "/root/.local/share/io.parity.ethereum", - name: "dncore_ethchaindnpdappnodeeth_data", - }, + name: "dncore_ethchaindnpdappnodeeth_data" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.6" }], state: "running", running: true, exitCode: null, dependencies: {}, - avatarUrl: - "https://gateway.ipfs.dappnode.io/ipfs/QmQnHxr4YAVdtqzHnsDYvmXizxptSYyaj3YwTjoiLshVwF", + avatarUrl: "https://gateway.ipfs.dappnode.io/ipfs/QmQnHxr4YAVdtqzHnsDYvmXizxptSYyaj3YwTjoiLshVwF", origin: "/ipfs/QmeBfnwgsNcEmbmxENBWtgkv5YZsAhiaDsoYd7nMTV1wKV", chain: "ethereum", canBeFullnode: false, defaultEnvironment: { EXTRA_OPTS: "--warp-barrier 8540000", EXTRA_OPTS_GETH: "", - DEFAULT_CLIENT: "PARITY", + DEFAULT_CLIENT: "PARITY" }, defaultPorts: [ { host: 30303, container: 30303, - protocol: PortProtocol.TCP, + protocol: PortProtocol.TCP }, { host: 30303, container: 30303, - protocol: PortProtocol.UDP, + protocol: PortProtocol.UDP }, { host: 30304, container: 30304, - protocol: PortProtocol.UDP, - }, + protocol: PortProtocol.UDP + } ], defaultVolumes: [ { host: "ethchaindnpdappnodeeth_data", container: "/root/.local/share/io.parity.ethereum", - name: "ethchaindnpdappnodeeth_data", + name: "ethchaindnpdappnodeeth_data" }, { host: "ethchaindnpdappnodeeth_geth", container: "/root/.ethereum", - name: "ethchaindnpdappnodeeth_geth", + name: "ethchaindnpdappnodeeth_geth" }, { host: "ethchaindnpdappnodeeth_identity", container: "/root/identity", - name: "ethchaindnpdappnodeeth_identity", - }, - ], + name: "ethchaindnpdappnodeeth_identity" + } + ] }, { - containerId: - "a4ae8b09bc9b2037ff76f99436ddf1890e1215c2a17533ab73445726b41b2bef", + containerId: "a4ae8b09bc9b2037ff76f99436ddf1890e1215c2a17533ab73445726b41b2bef", containerName: "DAppNodeCore-ipfs.dnp.dappnode.eth", serviceName: "ipfs.dnp.dappnode.eth", instanceName: "", @@ -458,42 +444,42 @@ describe("modules / docker / parseContainerInfo", function () { { container: 5001, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { container: 8080, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { container: 8081, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { host: 4001, container: 4001, protocol: PortProtocol.TCP, - deletable: false, + deletable: false }, { host: 4002, container: 4002, protocol: PortProtocol.UDP, - deletable: false, - }, + deletable: false + } ], volumes: [ { host: "/var/lib/docker/volumes/dncore_ipfsdnpdappnodeeth_data/_data", container: "/data/ipfs", - name: "dncore_ipfsdnpdappnodeeth_data", + name: "dncore_ipfsdnpdappnodeeth_data" }, { host: "/var/lib/docker/volumes/dncore_ipfsdnpdappnodeeth_export/_data", container: "/export", - name: "dncore_ipfsdnpdappnodeeth_export", - }, + name: "dncore_ipfsdnpdappnodeeth_export" + } ], networks: [{ name: "dncore_network", ip: "172.33.1.5" }], state: "running", @@ -503,21 +489,20 @@ describe("modules / docker / parseContainerInfo", function () { { container: 4001, host: 4001, - protocol: PortProtocol.TCP, + protocol: PortProtocol.TCP }, { container: 4002, host: 4002, - protocol: PortProtocol.UDP, - }, + protocol: PortProtocol.UDP + } ], dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "12cf3e376374f665d05a78bb20641cd9d5e36b7ab418b0ebec7c77b6798156c0", + containerId: "12cf3e376374f665d05a78bb20641cd9d5e36b7ab418b0ebec7c77b6798156c0", containerName: "DAppNodeCore-ethforward.dnp.dappnode.eth", serviceName: "ethforward.dnp.dappnode.eth", instanceName: "", @@ -536,11 +521,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "f789e9b7f00d7292c0db1f83b4dac063ce4a84d2bb3d55d12f9f492b7cbcbb2c", + containerId: "f789e9b7f00d7292c0db1f83b4dac063ce4a84d2bb3d55d12f9f492b7cbcbb2c", containerName: "DAppNodePackage-swarm.dnp.dappnode.eth", serviceName: "swarm.dnp.dappnode.eth", instanceName: "", @@ -556,21 +540,21 @@ describe("modules / docker / parseContainerInfo", function () { host: 30399, container: 30399, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { host: 30399, container: 30399, protocol: PortProtocol.UDP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/swarmdnpdappnodeeth_swarm/_data", container: "/root/.ethereum", - name: "swarmdnpdappnodeeth_swarm", - }, + name: "swarmdnpdappnodeeth_swarm" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.7" }], state: "running", @@ -578,11 +562,10 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "b7f32fcefcd4bfb34d0c293378993e4a40eb3e62d8a928c4f183065834a10fb2", + containerId: "b7f32fcefcd4bfb34d0c293378993e4a40eb3e62d8a928c4f183065834a10fb2", containerName: "DAppNodePackage-letsencrypt-nginx.dnp.dappnode.eth", serviceName: "letsencrypt-nginx.dnp.dappnode.eth", instanceName: "", @@ -597,36 +580,35 @@ describe("modules / docker / parseContainerInfo", function () { volumes: [ { host: "/root/certs", - container: "/etc/nginx/certs", + container: "/etc/nginx/certs" }, { host: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_vhost.d/_data", container: "/etc/nginx/vhost.d", - name: "nginxproxydnpdappnodeeth_vhost.d", + name: "nginxproxydnpdappnodeeth_vhost.d" }, { host: "/var/lib/docker/volumes/nginxproxydnpdappnodeeth_html/_data", container: "/usr/share/nginx/html", - name: "nginxproxydnpdappnodeeth_html", + name: "nginxproxydnpdappnodeeth_html" }, { host: "/var/run/docker.sock", - container: "/var/run/docker.sock", - }, + container: "/var/run/docker.sock" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.8" }], state: "running", running: true, exitCode: null, dependencies: { - "nginx-proxy.dnp.dappnode.eth": "latest", + "nginx-proxy.dnp.dappnode.eth": "latest" }, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "c944a1549ba675b7229b55370cfd2f54dca1f86050fbef7df4ba453398f93c24", + containerId: "c944a1549ba675b7229b55370cfd2f54dca1f86050fbef7df4ba453398f93c24", containerName: "DAppNodePackage-ipfs-replicator.dnp.dappnode.eth", serviceName: "ipfs-replicator.dnp.dappnode.eth", instanceName: "", @@ -642,8 +624,8 @@ describe("modules / docker / parseContainerInfo", function () { { host: "/var/lib/docker/volumes/ipfsreplicatordnpdappnodeeth_pin-data/_data", container: "/usr/src/app/data", - name: "ipfsreplicatordnpdappnodeeth_pin-data", - }, + name: "ipfsreplicatordnpdappnodeeth_pin-data" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.4" }], state: "running", @@ -652,11 +634,10 @@ describe("modules / docker / parseContainerInfo", function () { dependencies: {}, avatarUrl: "", origin: "/ipfs/QmYfVW2LNHH8ZXa6KJmfFAz5zCQ8YHh2ZPt6aQmezJcbL7", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "ffc3f4ed380ad42b7f847228862ad4de4ab471229bb5e1ed0aef46d4561309d2", + containerId: "ffc3f4ed380ad42b7f847228862ad4de4ab471229bb5e1ed0aef46d4561309d2", containerName: "DAppNodePackage-goerli-geth.dnp.dappnode.eth", serviceName: "goerli-geth.dnp.dappnode.eth", instanceName: "", @@ -672,27 +653,27 @@ describe("modules / docker / parseContainerInfo", function () { host: 32769, container: 30303, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { host: 32771, container: 30303, protocol: PortProtocol.UDP, - deletable: true, + deletable: true }, { host: 32770, container: 30304, protocol: PortProtocol.UDP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/goerligethdnpdappnodeeth_goerli/_data", container: "/goerli", - name: "goerligethdnpdappnodeeth_goerli", - }, + name: "goerligethdnpdappnodeeth_goerli" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.3" }], state: "running", @@ -701,11 +682,10 @@ describe("modules / docker / parseContainerInfo", function () { dependencies: {}, avatarUrl: "", chain: "ethereum", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "94bde8655e2d8daca033486ef46e7d270c4f4b6f6c18b820d80c2cbf211130bd", + containerId: "94bde8655e2d8daca033486ef46e7d270c4f4b6f6c18b820d80c2cbf211130bd", containerName: "DAppNodePackage-ln.dnp.dappnode.eth", serviceName: "ln.dnp.dappnode.eth", instanceName: "", @@ -720,40 +700,39 @@ describe("modules / docker / parseContainerInfo", function () { { container: 80, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { host: 9735, container: 9735, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { container: 10009, protocol: PortProtocol.TCP, - deletable: true, - }, + deletable: true + } ], volumes: [ { host: "/var/lib/docker/volumes/lndnpdappnodeeth_lndconfig_data/_data", container: "/root/.lnd", - name: "lndnpdappnodeeth_lndconfig_data", - }, + name: "lndnpdappnodeeth_lndconfig_data" + } ], networks: [{ name: "dncore_network", ip: "172.33.0.2" }], state: "running", running: true, exitCode: null, dependencies: { - "bitcoin.dnp.dappnode.eth": "latest", + "bitcoin.dnp.dappnode.eth": "latest" }, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "d01badf202548868538e0435163e66a12f5bbb253e82150ed951e89a4c13690d", + containerId: "d01badf202548868538e0435163e66a12f5bbb253e82150ed951e89a4c13690d", containerName: "DAppNodeCore-wamp.dnp.dappnode.eth", serviceName: "wamp.dnp.dappnode.eth", instanceName: "", @@ -768,13 +747,13 @@ describe("modules / docker / parseContainerInfo", function () { { container: 8000, protocol: PortProtocol.TCP, - deletable: true, + deletable: true }, { container: 8080, protocol: PortProtocol.TCP, - deletable: true, - }, + deletable: true + } ], volumes: [], networks: [{ name: "dncore_network", ip: "172.33.1.8" }], @@ -783,22 +762,20 @@ describe("modules / docker / parseContainerInfo", function () { exitCode: null, dependencies: {}, avatarUrl: "", - canBeFullnode: false, + canBeFullnode: false }, { - avatarUrl: - "https://gateway.ipfs.dappnode.io/ipfs/QmaZZVsVqaWwVLe36HhvKj3QEPt7hM1GL8kemNvsZd5F5x", + avatarUrl: "https://gateway.ipfs.dappnode.io/ipfs/QmaZZVsVqaWwVLe36HhvKj3QEPt7hM1GL8kemNvsZd5F5x", canBeFullnode: false, - containerId: - "ba4765113dd6016da8b35dfe367493186f3bfd34d88eca03ccf894f7045710fa", + containerId: "ba4765113dd6016da8b35dfe367493186f3bfd34d88eca03ccf894f7045710fa", containerName: "DAppNodePackage-grafana.dms.dnp.dappnode.eth", created: 1618303536, defaultVolumes: [ { container: "/var/lib/grafana", host: "grafana_data", - name: "grafana_data", - }, + name: "grafana_data" + } ], dependencies: {}, dnpName: "dms.dnp.dappnode.eth", @@ -812,16 +789,16 @@ describe("modules / docker / parseContainerInfo", function () { networks: [ { ip: "172.33.0.3", - name: "dncore_network", - }, + name: "dncore_network" + } ], ports: [ { container: 3000, deletable: true, - protocol: PortProtocol.TCP, - }, + protocol: PortProtocol.TCP + } ], running: true, serviceName: "grafana", @@ -831,10 +808,10 @@ describe("modules / docker / parseContainerInfo", function () { { container: "/var/lib/grafana", host: "/var/lib/docker/volumes/dmsdnpdappnodeeth_grafana_data/_data", - name: "dmsdnpdappnodeeth_grafana_data", - }, - ], - }, + name: "dmsdnpdappnodeeth_grafana_data" + } + ] + } ]; // Remove all values that are undefined diff --git a/packages/dockerApi/test/unit/parseExitCodeFromStatus.test.ts b/packages/dockerApi/test/unit/parseExitCodeFromStatus.test.ts index 0365be108..5feaa5e63 100644 --- a/packages/dockerApi/test/unit/parseExitCodeFromStatus.test.ts +++ b/packages/dockerApi/test/unit/parseExitCodeFromStatus.test.ts @@ -16,9 +16,9 @@ describe("docker / parseExitCodeFromStatus", () => { { id: "Empty", status: "", exitCode: null }, { id: "Not a string", - status: (undefined as unknown) as string, - exitCode: null, - }, + status: undefined as unknown as string, + exitCode: null + } ]; for (const { id, status, exitCode } of testCases) { diff --git a/packages/dockerApi/test/unit/unix.test.ts b/packages/dockerApi/test/unit/unix.test.ts index 9162fd232..7c34b1001 100644 --- a/packages/dockerApi/test/unit/unix.test.ts +++ b/packages/dockerApi/test/unit/unix.test.ts @@ -30,7 +30,7 @@ describe("utils > unix", () => { { size: "1980410", path: "test" }, { size: "596410", path: "src/calls" }, { size: "3224410", path: "src" }, - { size: "659048410", path: "." }, + { size: "659048410", path: "." } ]; const result = parseDuOutput(output); @@ -49,7 +49,7 @@ describe("utils > unix", () => { const expectedResult: DuResult[] = [ { size: "824204410", path: "bitcoin.dnp.dappnode.eth/bitcoin_data" }, { size: "824208410", path: "bitcoin.dnp.dappnode.eth" }, - { size: "824212410", path: "." }, + { size: "824212410", path: "." } ]; const result = parseDuOutput(output, relativeFrom); diff --git a/packages/dockerApi/test/unit/utils.test.ts b/packages/dockerApi/test/unit/utils.test.ts index caf09021c..fb5c22f4c 100644 --- a/packages/dockerApi/test/unit/utils.test.ts +++ b/packages/dockerApi/test/unit/utils.test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import { getDockerTimeoutMax, ensureUniquePortsFromDockerApi, - stripDockerApiLogsHeaderAndAnsi, + stripDockerApiLogsHeaderAndAnsi } from "../../src/index.js"; import { PackageContainer } from "@dappnode/types"; import { mockContainer } from "../testUtils.js"; @@ -31,9 +31,7 @@ info Webserver on 80, /usr/src/app/dist`; }); it("Should not strip anything from clean logs", () => { - const logSampleClean = stripDockerApiLogsHeaderAndAnsi( - logSampleCleanExpected - ); + const logSampleClean = stripDockerApiLogsHeaderAndAnsi(logSampleCleanExpected); expect(logSampleClean).to.equal(logSampleCleanExpected); }); }); @@ -43,12 +41,12 @@ info Webserver on 80, /usr/src/app/dist`; const containers: PackageContainer[] = [ { ...mockContainer, - dockerTimeout: 120, + dockerTimeout: 120 }, { ...mockContainer, - dockerTimeout: 60, - }, + dockerTimeout: 60 + } ]; const timeout = getDockerTimeoutMax(containers); expect(timeout).to.equal(120); @@ -62,50 +60,50 @@ info Webserver on 80, /usr/src/app/dist`; IP: "0.0.0.0", PrivatePort: 30303, PublicPort: 49969, - Type: "tcp", + Type: "tcp" }, { IP: "::", PrivatePort: 30303, PublicPort: 49969, - Type: "tcp", + Type: "tcp" }, { IP: "0.0.0.0", PrivatePort: 30303, PublicPort: 49939, - Type: "udp", + Type: "udp" }, { IP: "::", PrivatePort: 30303, PublicPort: 49939, - Type: "udp", + Type: "udp" }, { IP: "0.0.0.0", PrivatePort: 30304, PublicPort: 49968, - Type: "tcp", + Type: "tcp" }, { IP: "::", PrivatePort: 30304, PublicPort: 49968, - Type: "tcp", + Type: "tcp" }, { IP: "0.0.0.0", PrivatePort: 30304, PublicPort: 49938, - Type: "udp", + Type: "udp" }, { IP: "::", PrivatePort: 30304, PublicPort: 49938, - Type: "udp", - }, + Type: "udp" + } ]; const expectedPorts = [ @@ -113,32 +111,29 @@ info Webserver on 80, /usr/src/app/dist`; host: 49969, container: 30303, protocol: "TCP", - deletable: true, + deletable: true }, { host: 49939, container: 30303, protocol: "UDP", - deletable: true, + deletable: true }, { host: 49968, container: 30304, protocol: "TCP", - deletable: true, + deletable: true }, { host: 49938, container: 30304, protocol: "UDP", - deletable: true, - }, + deletable: true + } ]; - const dockerApiPortsParsed = ensureUniquePortsFromDockerApi( - dockerApiPorts, - undefined - ); + const dockerApiPortsParsed = ensureUniquePortsFromDockerApi(dockerApiPorts, undefined); expect(dockerApiPortsParsed).to.eql(expectedPorts); }); }); diff --git a/packages/dockerApi/test/unit/volumesData.test.ts b/packages/dockerApi/test/unit/volumesData.test.ts index 0088bc29e..0ea2bf5ad 100644 --- a/packages/dockerApi/test/unit/volumesData.test.ts +++ b/packages/dockerApi/test/unit/volumesData.test.ts @@ -1,9 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - parseVolumeOwnershipData, - normalizeProjectName, -} from "../../src/index.js"; +import { parseVolumeOwnershipData, normalizeProjectName } from "../../src/index.js"; import { PackageContainer, VolumeOwnershipData } from "@dappnode/types"; describe("docker > volumes data", () => { @@ -11,7 +8,7 @@ describe("docker > volumes data", () => { const cases: { [dnpName: string]: string } = { "main.dnp.dappnode.eth": "maindnpdappnodeeth", "dependency.dnp.dappnode.eth": "dependencydnpdappnodeeth", - "lightning-network.dnp.dappnode.eth": "lightning-networkdnpdappnodeeth", + "lightning-network.dnp.dappnode.eth": "lightning-networkdnpdappnodeeth" }; for (const dnpName in cases) { it(`Normalize project name ${dnpName}`, () => { @@ -24,8 +21,7 @@ describe("docker > volumes data", () => { it("Should parse ownership data of a shared volume", () => { const containers: PackageContainer[] = [ { - containerId: - "38e0f958856d16076bb241fa72d80bded9b4fd1101e5a7dbe29be68e9a61434d", + containerId: "38e0f958856d16076bb241fa72d80bded9b4fd1101e5a7dbe29be68e9a61434d", containerName: "DAppNodePackage-main.dnp.dappnode.eth", dnpName: "main.dnp.dappnode.eth", serviceName: "main.dnp.dappnode.eth", @@ -41,18 +37,18 @@ describe("docker > volumes data", () => { { host: "/var/lib/docker/volumes/maindnpdappnodeeth_changeme-main/_data", container: "/temp", - name: "maindnpdappnodeeth_changeme-main", + name: "maindnpdappnodeeth_changeme-main" }, { host: "/var/lib/docker/volumes/maindnpdappnodeeth_data/_data", container: "/usr", - name: "maindnpdappnodeeth_data", + name: "maindnpdappnodeeth_data" }, { host: "/var/lib/docker/volumes/dependencydnpdappnodeeth_data/_data", container: "/usrdep", - name: "dependencydnpdappnodeeth_data", - }, + name: "dependencydnpdappnodeeth_data" + } ], networks: [], state: "running", @@ -61,11 +57,10 @@ describe("docker > volumes data", () => { dependencies: {}, avatarUrl: "", origin: "QmQc7QS7n7311Sc9EhjPqLkpgGWMNNdC2kcYa5GSQUB4jf", - canBeFullnode: false, + canBeFullnode: false }, { - containerId: - "c44f7803a4192db211367f5558dfee0ec48b3b800e5638e06bb43edf8b74cd1c", + containerId: "c44f7803a4192db211367f5558dfee0ec48b3b800e5638e06bb43edf8b74cd1c", containerName: "DAppNodePackage-dependency.dnp.dappnode.eth", dnpName: "dependency.dnp.dappnode.eth", serviceName: "dependency.dnp.dappnode.eth", @@ -80,13 +75,13 @@ describe("docker > volumes data", () => { volumes: [ { host: "/home/lion/Code/dappnode/DNP_DAPPMANAGER/packages/dappmanager/test_mountpoints/dnplifecycle-dep/testBind", - container: "/temp", + container: "/temp" }, { host: "/var/lib/docker/volumes/dependencydnpdappnodeeth_data/_data", container: "/usr", - name: "dependencydnpdappnodeeth_data", - }, + name: "dependencydnpdappnodeeth_data" + } ], networks: [], state: "running", @@ -95,8 +90,8 @@ describe("docker > volumes data", () => { dependencies: {}, avatarUrl: "", origin: "QmNpp6BbDd4MG5agdvNHwTnRew1uhPPehTUYyvtpbDLgEr", - canBeFullnode: false, - }, + canBeFullnode: false + } ]; const vol_dependencydnpdappnodeeth_data = { @@ -105,24 +100,20 @@ describe("docker > volumes data", () => { Labels: { "com.docker.compose.project": "dependencydnpdappnodeeth", "com.docker.compose.version": "1.22.0", - "com.docker.compose.volume": "data", + "com.docker.compose.volume": "data" }, - Mountpoint: - "/var/lib/docker/volumes/dependencydnpdappnodeeth_data/_data", + Mountpoint: "/var/lib/docker/volumes/dependencydnpdappnodeeth_data/_data", Name: "dependencydnpdappnodeeth_data", Options: null, - Scope: "local", + Scope: "local" }; const expectedVolOwnershipData: VolumeOwnershipData = { name: "dependencydnpdappnodeeth_data", - owner: "dependency.dnp.dappnode.eth", + owner: "dependency.dnp.dappnode.eth" }; - const volOwnershipData = parseVolumeOwnershipData( - vol_dependencydnpdappnodeeth_data, - containers - ); + const volOwnershipData = parseVolumeOwnershipData(vol_dependencydnpdappnodeeth_data, containers); expect(volOwnershipData).to.deep.equal(expectedVolOwnershipData); }); diff --git a/packages/dockerCompose/.eslintignore b/packages/dockerCompose/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/dockerCompose/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/dockerCompose/.eslintrc.cjs b/packages/dockerCompose/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/dockerCompose/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/dockerCompose/package.json b/packages/dockerCompose/package.json index bf623d850..4e09cfab6 100644 --- a/packages/dockerCompose/package.json +++ b/packages/dockerCompose/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/types": "workspace:^0.1.0", diff --git a/packages/dockerCompose/src/clean.ts b/packages/dockerCompose/src/clean.ts index 97c6b6bbc..d4132096d 100644 --- a/packages/dockerCompose/src/clean.ts +++ b/packages/dockerCompose/src/clean.ts @@ -16,14 +16,12 @@ export function cleanCompose(compose: Compose): Compose { services: mapValues(compose.services, (service) => ({ ...omitBy(service, isOmitable), // Add mandatory properties for the ts compiler - ...pick(service, ["container_name", "image"]), - })), + ...pick(service, ["container_name", "image"]) + })) }; } /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ export function isOmitable(value: any): boolean { - return ( - value === undefined || value === null || (isObject(value) && isEmpty(value)) - ); + return value === undefined || value === null || (isObject(value) && isEmpty(value)); } diff --git a/packages/dockerCompose/src/devicePath.ts b/packages/dockerCompose/src/devicePath.ts index 663ffae91..a76ae30ee 100644 --- a/packages/dockerCompose/src/devicePath.ts +++ b/packages/dockerCompose/src/devicePath.ts @@ -22,19 +22,12 @@ export function getDevicePath({ volumeName: string; }): string { if (!path.isAbsolute(mountpoint)) - throw Error( - `mountpoint path for '${dnpName} - ${volumeName}' must be an absolute path: ${mountpoint}` - ); + throw Error(`mountpoint path for '${dnpName} - ${volumeName}' must be an absolute path: ${mountpoint}`); const stripCharacters = (s: string): string => s.replace(/[`~!@#$%^&*()|+=?;:'",<>{}[\]\\/]/gi, "").replace(/\.+/, "."); - return path.join( - mountpoint, - params.MOUNTPOINT_DEVICE_PREFIX, - stripCharacters(dnpName), - stripCharacters(volumeName) - ); + return path.join(mountpoint, params.MOUNTPOINT_DEVICE_PREFIX, stripCharacters(dnpName), stripCharacters(volumeName)); } /** @@ -58,9 +51,7 @@ export function parseDevicePath(devicePath: string): } | undefined { // The docker API is not perfectly typed, devicePath may be undefined - const [mountpoint, dnpNameAndVolumeName] = (devicePath || "").split( - "/" + params.MOUNTPOINT_DEVICE_PREFIX + "/" - ); + const [mountpoint, dnpNameAndVolumeName] = (devicePath || "").split("/" + params.MOUNTPOINT_DEVICE_PREFIX + "/"); if (!dnpNameAndVolumeName) return; const [dnpName, volumeName] = (dnpNameAndVolumeName || "").split("/"); if (!volumeName) return; @@ -73,9 +64,7 @@ export function parseDevicePath(devicePath: string): }; } -export function parseDevicePathMountpoint( - devicePath: string -): string | undefined { +export function parseDevicePathMountpoint(devicePath: string): string | undefined { const pathParts = parseDevicePath(devicePath); return pathParts ? pathParts.mountpoint : undefined; } diff --git a/packages/dockerCompose/src/editor.ts b/packages/dockerCompose/src/editor.ts index 09d291d8f..db0c8a04a 100644 --- a/packages/dockerCompose/src/editor.ts +++ b/packages/dockerCompose/src/editor.ts @@ -1,16 +1,6 @@ import fs from "fs"; import path from "path"; -import { - mapValues, - omitBy, - isObject, - isEmpty, - pick, - pull, - uniq, - concat, - omit, -} from "lodash-es"; +import { mapValues, omitBy, isObject, isEmpty, pick, pull, uniq, concat, omit } from "lodash-es"; import { ContainerLabelsRaw } from "./types.js"; import { Manifest, @@ -22,13 +12,9 @@ import { GlobalEnvsPrefixed, PortMapping, UserSettings, - ComposeServiceNetworksObj, + ComposeServiceNetworksObj } from "@dappnode/types"; -import { - stringifyPortMappings, - parsePortMappings, - mergePortMappings, -} from "./ports.js"; +import { stringifyPortMappings, parsePortMappings, mergePortMappings } from "./ports.js"; import { parseServiceNetworks } from "./networks.js"; import { verifyCompose } from "./verify.js"; import { parseUserSettings, applyUserSettings } from "./userSettings.js"; @@ -39,7 +25,7 @@ import { yamlParse, parseEnvironment, mergeEnvs, - stringifyEnvironment, + stringifyEnvironment } from "@dappnode/utils"; import { params } from "@dappnode/params"; @@ -53,18 +39,14 @@ export class ComposeServiceEditor { } private getGlobalEnvsFilePath(isCore: boolean): string { - return isCore - ? params.GLOBAL_ENVS_PATH_FOR_CORE - : params.GLOBAL_ENVS_PATH_FOR_DNP; + return isCore ? params.GLOBAL_ENVS_PATH_FOR_CORE : params.GLOBAL_ENVS_PATH_FOR_DNP; } - private edit( - serviceEditor: (service: ComposeService) => Partial<ComposeService> - ): void { + private edit(serviceEditor: (service: ComposeService) => Partial<ComposeService>): void { const service = this.parent.compose.services[this.serviceName]; this.parent.compose.services[this.serviceName] = { ...service, - ...serviceEditor(service), + ...serviceEditor(service) }; } @@ -78,48 +60,33 @@ export class ComposeServiceEditor { setPortMapping(newPortMappings: PortMapping[]): void { this.edit(() => ({ - ports: stringifyPortMappings(newPortMappings), + ports: stringifyPortMappings(newPortMappings) })); } mergePortMapping(newPortMappings: PortMapping[]): void { this.edit((service) => ({ - ports: stringifyPortMappings( - mergePortMappings( - newPortMappings, - parsePortMappings(service.ports || []) - ) - ), + ports: stringifyPortMappings(mergePortMappings(newPortMappings, parsePortMappings(service.ports || []))) })); } mergeEnvs(newEnvs: PackageEnvs): void { this.edit((service) => ({ - environment: stringifyEnvironment( - mergeEnvs(newEnvs, parseEnvironment(service.environment || [])) - ), + environment: stringifyEnvironment(mergeEnvs(newEnvs, parseEnvironment(service.environment || []))) })); } - removeNetworkAliases( - networkName: string, - aliasesToRemove: string[], - serviceNetwork: ComposeServiceNetwork - ): void { + removeNetworkAliases(networkName: string, aliasesToRemove: string[], serviceNetwork: ComposeServiceNetwork): void { this.edit((service) => { const networks = parseServiceNetworks(service.networks || {}); // Network and service network aliases must exist if (!networks[networkName] || !serviceNetwork.aliases) - throw Error( - "Error removing alias: Network or serviceNetwork does not exist" - ); + throw Error("Error removing alias: Network or serviceNetwork does not exist"); - const serviceNetworNewAliases = serviceNetwork.aliases.filter( - (item) => !aliasesToRemove.includes(item) - ); + const serviceNetworNewAliases = serviceNetwork.aliases.filter((item) => !aliasesToRemove.includes(item)); const serviceNetworkUpdated = { ...serviceNetwork, - aliases: serviceNetworNewAliases, + aliases: serviceNetworNewAliases }; return { @@ -127,32 +94,23 @@ export class ComposeServiceEditor { ...networks, [networkName]: { ...(networks[networkName] || {}), - ...serviceNetworkUpdated, - }, - }, + ...serviceNetworkUpdated + } + } }; }); } - addNetworkAliases( - networkName: string, - newAliases: string[], - serviceNetwork: ComposeServiceNetwork - ): void { + addNetworkAliases(networkName: string, newAliases: string[], serviceNetwork: ComposeServiceNetwork): void { this.edit((service) => { const networks = parseServiceNetworks(service.networks || {}); // Network and service network aliases must exist if (!networks[networkName] || !serviceNetwork) - throw Error( - "Error adding alias: Network or serviceNetwork does not exist" - ); - const aliasesUpdated = uniq([ - ...(serviceNetwork.aliases || []), - ...newAliases, - ]); + throw Error("Error adding alias: Network or serviceNetwork does not exist"); + const aliasesUpdated = uniq([...(serviceNetwork.aliases || []), ...newAliases]); const serviceNetworkUpdated = { ...serviceNetwork, - aliases: aliasesUpdated, + aliases: aliasesUpdated }; return { @@ -160,9 +118,9 @@ export class ComposeServiceEditor { ...networks, [networkName]: { ...(networks[networkName] || {}), - ...serviceNetworkUpdated, - }, - }, + ...serviceNetworkUpdated + } + } }; }); } @@ -186,24 +144,16 @@ export class ComposeServiceEditor { // Add the defined global envs to the selected services for (const globEnv of manifestGlobalEnvs) { if (!globEnv.services.includes(this.serviceName)) continue; - const globalEnvsFromManifestPrefixed = globEnv.envs.map( - (env) => `${params.GLOBAL_ENVS_PREFIX}${env}` - ); - - if ( - globalEnvsFromManifestPrefixed.some( - (env) => !(env in globalEnvsFromDbPrefixed) - ) - ) + const globalEnvsFromManifestPrefixed = globEnv.envs.map((env) => `${params.GLOBAL_ENVS_PREFIX}${env}`); + + if (globalEnvsFromManifestPrefixed.some((env) => !(env in globalEnvsFromDbPrefixed))) throw Error( - `Global envs allowed are ${Object.keys( - globalEnvsFromDbPrefixed - ).join(", ")}. Got ${globEnv.envs.join(", ")}` + `Global envs allowed are ${Object.keys(globalEnvsFromDbPrefixed).join( + ", " + )}. Got ${globEnv.envs.join(", ")}` ); - this.mergeEnvs( - pick(globalEnvsFromDbPrefixed, globalEnvsFromManifestPrefixed) - ); + this.mergeEnvs(pick(globalEnvsFromDbPrefixed, globalEnvsFromManifestPrefixed)); } } else if ((manifestGlobalEnvs || {}).all) { // Add global env_file on request @@ -213,7 +163,7 @@ export class ComposeServiceEditor { addEnvFile(envFile: string): void { this.edit((service) => ({ - env_file: uniq(concat(service.env_file || [], envFile)), + env_file: uniq(concat(service.env_file || [], envFile)) })); } @@ -222,13 +172,13 @@ export class ComposeServiceEditor { */ omitDnpEnvFile(): void { this.edit((service) => ({ - env_file: pull(service.env_file || [], `${this.serviceName}.env`), + env_file: pull(service.env_file || [], `${this.serviceName}.env`) })); } mergeLabels(labels: ContainerLabelsRaw): void { this.edit((service) => ({ - labels: { ...service.labels, ...labels }, + labels: { ...service.labels, ...labels } })); } @@ -236,11 +186,7 @@ export class ComposeServiceEditor { * Add a network to a service, makes sure it's defined in the main networks section * If the network is not define uses `networkConfig` or defualts to external network */ - addNetwork( - networkName: string, - serviceNetwork?: ComposeServiceNetwork, - networkConfig?: ComposeNetwork - ): void { + addNetwork(networkName: string, serviceNetwork?: ComposeServiceNetwork, networkConfig?: ComposeNetwork): void { // Add network to service this.edit((service) => { const networks = parseServiceNetworks(service.networks || {}); @@ -249,9 +195,9 @@ export class ComposeServiceEditor { ...networks, [networkName]: { ...(networks[networkName] || {}), - ...(serviceNetwork || {}), - }, - }, + ...(serviceNetwork || {}) + } + } }; }); @@ -259,7 +205,7 @@ export class ComposeServiceEditor { if (!this.parent.compose.networks) this.parent.compose.networks = {}; if (!this.parent.compose.networks[networkName]) this.parent.compose.networks[networkName] = networkConfig || { - external: true, + external: true }; } @@ -274,8 +220,7 @@ export class ComposeServiceEditor { }); // Remove network from networks section - if (this.parent.compose.networks) - delete this.parent.compose.networks[networkName]; + if (this.parent.compose.networks) delete this.parent.compose.networks[networkName]; } } @@ -296,13 +241,13 @@ export class ComposeEditor { } /** - * Converts an array of network names to an object with empty values - */ + * Converts an array of network names to an object with empty values + */ static convertNetworkArrayToObject(networks: string[]): ComposeServiceNetworksObj { return networks.reduce( (acc, networkName) => ({ ...acc, - [networkName]: {}, + [networkName]: {} }), {} ); @@ -315,10 +260,7 @@ export class ComposeEditor { } services(): { [serviceName: string]: ComposeServiceEditor } { - return mapValues( - this.compose.services, - (_service, serviceName) => new ComposeServiceEditor(this, serviceName) - ); + return mapValues(this.compose.services, (_service, serviceName) => new ComposeServiceEditor(this, serviceName)); } output(): Compose { @@ -334,10 +276,7 @@ export class ComposeEditor { this.compose.services = mapValues(this.compose.services, (service) => { // To be backwards compatible write ENVs as array // Previous DAPPMANAGERs cannot in object form, blocking all docker actions + updates - if ( - typeof service.environment === "object" && - !Array.isArray(service.environment) - ) + if (typeof service.environment === "object" && !Array.isArray(service.environment)) service.environment = stringifyEnvironment(service.environment); // Remove hardcoded DNS @@ -346,7 +285,7 @@ export class ComposeEditor { return { ...omitBy(service, (el) => isObject(el) && isEmpty(el)), // Add mandatory properties for the ts compiler - ...pick(service, ["container_name", "image"]), + ...pick(service, ["container_name", "image"]) }; }); @@ -364,10 +303,7 @@ export class ComposeEditor { return this.compose.networks?.[networkName] ?? null; } - applyUserSettings( - userSettings: UserSettings, - { dnpName }: { dnpName: string } - ): void { + applyUserSettings(userSettings: UserSettings, { dnpName }: { dnpName: string }): void { this.compose = applyUserSettings(this.compose, userSettings, { dnpName }); } @@ -397,10 +333,7 @@ export class ComposeFileEditor extends ComposeEditor { * Reads a local compose file and get user settings if file exists * If file does not exist, return empty user settings */ - static getUserSettingsIfExist( - dnpName: string, - isCore: boolean - ): UserSettings { + static getUserSettingsIfExist(dnpName: string, isCore: boolean): UserSettings { try { return new ComposeFileEditor(dnpName, isCore).getUserSettings(); } catch (e) { diff --git a/packages/dockerCompose/src/labelsDb.ts b/packages/dockerCompose/src/labelsDb.ts index c4308e444..5ded3b17d 100644 --- a/packages/dockerCompose/src/labelsDb.ts +++ b/packages/dockerCompose/src/labelsDb.ts @@ -6,7 +6,7 @@ import { ChainDriver, ChainDriverSpecs, ChainDriverType, - chainDriversTypes, + chainDriversTypes } from "@dappnode/types"; import { pick, omitBy, mapValues } from "lodash-es"; @@ -27,22 +27,19 @@ const parseJsonSafe = <T>(value: string | undefined): T | undefined => { try { return JSON.parse(value); } catch (e) { + console.error("Error parsing JSON", e); return undefined; } }; const writeString = (data: string | undefined): string | undefined => data; -const writeNumber = (num: number | undefined): string | undefined => - num === undefined ? undefined : String(num); +const writeNumber = (num: number | undefined): string | undefined => (num === undefined ? undefined : String(num)); const writeBool = (data: boolean | undefined): string | undefined => data === true ? "true" : data === false ? "false" : undefined; -const writeJson = (data: Record<string, unknown> | string[]): string => - JSON.stringify(data); +const writeJson = (data: Record<string, unknown> | string[]): string => JSON.stringify(data); const labelParseFns: { - [K in keyof Required<ContainerLabelTypes>]: ( - labelValue: string | undefined - ) => ContainerLabelTypes[K] | undefined; + [K in keyof Required<ContainerLabelTypes>]: (labelValue: string | undefined) => ContainerLabelTypes[K] | undefined; } = { "dappnode.dnp.dnpName": parseString, "dappnode.dnp.version": parseString, @@ -56,12 +53,7 @@ const labelParseFns: { return value as ChainDriverType; } const valueParsed = parseJsonSafe(value); - if ( - valueParsed && - chainDriversTypes.includes( - (valueParsed as ChainDriverSpecs).driver as ChainDriverType - ) - ) + if (valueParsed && chainDriversTypes.includes((valueParsed as ChainDriverSpecs).driver as ChainDriverType)) return valueParsed as ChainDriver; return undefined; }, @@ -70,13 +62,11 @@ const labelParseFns: { "dappnode.dnp.dockerTimeout": parseNumber, "dappnode.dnp.default.environment": (value) => parseJsonSafe(value), "dappnode.dnp.default.ports": (value) => parseJsonSafe(value), - "dappnode.dnp.default.volumes": (value) => parseJsonSafe(value), + "dappnode.dnp.default.volumes": (value) => parseJsonSafe(value) }; const labelStringifyFns: { - [K in keyof Required<ContainerLabelTypes>]: ( - data: ContainerLabelTypes[K] - ) => string | undefined; + [K in keyof Required<ContainerLabelTypes>]: (data: ContainerLabelTypes[K]) => string | undefined; } = { "dappnode.dnp.dnpName": writeString, "dappnode.dnp.version": writeString, @@ -94,48 +84,30 @@ const labelStringifyFns: { "dappnode.dnp.dockerTimeout": writeNumber, "dappnode.dnp.default.environment": writeJson, "dappnode.dnp.default.ports": writeJson, - "dappnode.dnp.default.volumes": writeJson, + "dappnode.dnp.default.volumes": writeJson }; -function parseContainerLabels( - labelsRaw: ContainerLabelsRaw -): Partial<ContainerLabelTypes> { +function parseContainerLabels(labelsRaw: ContainerLabelsRaw): Partial<ContainerLabelTypes> { return mapValues(labelParseFns, (labelParseFn, label) => labelParseFn(labelsRaw[label]) ) as Partial<ContainerLabelTypes>; } -function stringifyContainerLabels( - labels: Partial<ContainerLabelTypes> -): ContainerLabelsRaw { - const labelsRaw = mapValues( - pick(labelStringifyFns, Object.keys(labels)), - (labelStringifyFn, label) => - (labelStringifyFn as <T>(data: T) => string)( - labels[label as keyof ContainerLabelTypes] - ) +function stringifyContainerLabels(labels: Partial<ContainerLabelTypes>): ContainerLabelsRaw { + const labelsRaw = mapValues(pick(labelStringifyFns, Object.keys(labels)), (labelStringifyFn, label) => + (labelStringifyFn as <T>(data: T) => string)(labels[label as keyof ContainerLabelTypes]) ) as ContainerLabelsRaw; return omitBy(labelsRaw, (value) => value === undefined); } -type ServiceDefaultSettings = Pick< - ComposeService, - "environment" | "ports" | "volumes" ->; +type ServiceDefaultSettings = Pick<ComposeService, "environment" | "ports" | "volumes">; -export function writeDefaultsToLabels({ - environment, - ports, - volumes, -}: ServiceDefaultSettings): ContainerLabelsRaw { +export function writeDefaultsToLabels({ environment, ports, volumes }: ServiceDefaultSettings): ContainerLabelsRaw { return stringifyContainerLabels({ "dappnode.dnp.default.environment": - environment && - (Array.isArray(environment) - ? environment - : stringifyEnvironment(environment)), + environment && (Array.isArray(environment) ? environment : stringifyEnvironment(environment)), "dappnode.dnp.default.ports": ports, - "dappnode.dnp.default.volumes": volumes, + "dappnode.dnp.default.volumes": volumes }); } @@ -170,7 +142,7 @@ export function readContainerLabels(labelsRaw: ContainerLabelsRaw): Partial<{ dockerTimeout: labelValues["dappnode.dnp.dockerTimeout"], defaultEnvironment: labelValues["dappnode.dnp.default.environment"], defaultPorts: labelValues["dappnode.dnp.default.ports"], - defaultVolumes: labelValues["dappnode.dnp.default.volumes"], + defaultVolumes: labelValues["dappnode.dnp.default.volumes"] }; } @@ -184,7 +156,7 @@ export function writeMetadataToLabels({ origin, isCore, isMain, - dockerTimeout, + dockerTimeout }: { dnpName: string; version: string; @@ -207,6 +179,6 @@ export function writeMetadataToLabels({ "dappnode.dnp.chain": chain, "dappnode.dnp.isCore": isCore, "dappnode.dnp.isMain": isMain, - "dappnode.dnp.dockerTimeout": dockerTimeout, + "dappnode.dnp.dockerTimeout": dockerTimeout }); } diff --git a/packages/dockerCompose/src/networks.ts b/packages/dockerCompose/src/networks.ts index 89aeb03a0..98e178659 100644 --- a/packages/dockerCompose/src/networks.ts +++ b/packages/dockerCompose/src/networks.ts @@ -1,15 +1,10 @@ -import { - ComposeServiceNetworks, - ComposeServiceNetworksObj, -} from "@dappnode/types"; +import { ComposeServiceNetworks, ComposeServiceNetworksObj } from "@dappnode/types"; /** * Parse service networks to object form * @param networks */ -export function parseServiceNetworks( - networks: ComposeServiceNetworks -): ComposeServiceNetworksObj { +export function parseServiceNetworks(networks: ComposeServiceNetworks): ComposeServiceNetworksObj { if (Array.isArray(networks)) { const networksObj: ComposeServiceNetworksObj = {}; for (const networkName of networks) { diff --git a/packages/dockerCompose/src/ports.ts b/packages/dockerCompose/src/ports.ts index 553f26720..88e097741 100644 --- a/packages/dockerCompose/src/ports.ts +++ b/packages/dockerCompose/src/ports.ts @@ -12,10 +12,7 @@ export function parsePortMappings(portsArray: string[]): PortMapping[] { const [portMapping, protocolString = ""] = portString.split("/"); // Make sure the protocol is correct - const protocolParsed = - protocolString.toLowerCase() === "udp" - ? PortProtocol.UDP - : PortProtocol.TCP; + const protocolParsed = protocolString.toLowerCase() === "udp" ? PortProtocol.UDP : PortProtocol.TCP; const [hostString, containerString] = portMapping.split(":"); // Convert to appropiate types + Cast to a PortProtocol type @@ -39,8 +36,7 @@ export function parsePortMappings(portsArray: string[]): PortMapping[] { export function stringifyPortMappings(portMappings: PortMapping[]): string[] { // Stringify ports return portMappings.map(({ host, container, protocol }) => { - const parsedProtocol = - (protocol || "").toLowerCase() === "udp" ? "/udp" : ""; + const parsedProtocol = (protocol || "").toLowerCase() === "udp" ? "/udp" : ""; return host ? // HOST:CONTAINER/protocol, if HOST [host, container].join(":") + parsedProtocol @@ -59,27 +55,15 @@ export function stringifyPortMappings(portMappings: PortMapping[]): string[] { * @param portMappings2 PortMapping array with LESS priority * @returns merged PortMapping array */ -export function mergePortMappings( - portMappings1: PortMapping[], - portMappings2: PortMapping[] -): PortMapping[] { +export function mergePortMappings(portMappings1: PortMapping[], portMappings2: PortMapping[]): PortMapping[] { // Give each port mapping a deterministic key so mappings targeting // the same container port number and protocol get overwritten return uniqBy( concat(portMappings1, portMappings2), - ({ container, protocol }: PortMapping) => - `${container}/${protocol || "TCP"}` + ({ container, protocol }: PortMapping) => `${container}/${protocol || "TCP"}` ); } -export function mergePortArrays( - portArray1: string[], - portArray2: string[] -): string[] { - return stringifyPortMappings( - mergePortMappings( - parsePortMappings(portArray1), - parsePortMappings(portArray2) - ) - ); +export function mergePortArrays(portArray1: string[], portArray2: string[]): string[] { + return stringifyPortMappings(mergePortMappings(parsePortMappings(portArray1), parsePortMappings(portArray2))); } diff --git a/packages/dockerCompose/src/setDappnodeComposeDefaults.ts b/packages/dockerCompose/src/setDappnodeComposeDefaults.ts index 59e9ae2e8..8fd5b5dc0 100644 --- a/packages/dockerCompose/src/setDappnodeComposeDefaults.ts +++ b/packages/dockerCompose/src/setDappnodeComposeDefaults.ts @@ -1,10 +1,5 @@ import { mapValues, toPairs, sortBy, fromPairs, pick } from "lodash-es"; -import { - getPrivateNetworkAliases, - getIsCore, - parseEnvironment, - getIsMonoService, -} from "@dappnode/utils"; +import { getPrivateNetworkAliases, getIsCore, parseEnvironment, getIsMonoService } from "@dappnode/utils"; import { params } from "@dappnode/params"; import { cleanCompose } from "./clean.js"; import { parseServiceNetworks } from "./networks.js"; @@ -16,17 +11,14 @@ import { ComposeService, ComposeServiceNetworks, dockerComposeSafeKeys, - Manifest, + Manifest } from "@dappnode/types"; import { lt } from "semver"; /** * Returns the compose file for the given manifest */ -export function setDappnodeComposeDefaults( - composeUnsafe: Compose, - manifest: Manifest -): Compose { +export function setDappnodeComposeDefaults(composeUnsafe: Compose, manifest: Manifest): Compose { const dnpName = manifest.name; const version = manifest.version; const isCore = getIsCore(manifest); @@ -35,47 +27,43 @@ export function setDappnodeComposeDefaults( return cleanCompose({ version: ensureMinimumComposeVersion(composeUnsafe.version), - services: mapValues( - composeUnsafe.services, - (serviceUnsafe, serviceName) => { - return sortServiceKeys({ - // OVERRIDABLE VALUES: values that in case of not been set, it will take the following values - logging: { - driver: "json-file", - options: { - "max-size": "10m", - "max-file": "3", - }, - }, - restart: "unless-stopped", + services: mapValues(composeUnsafe.services, (serviceUnsafe, serviceName) => { + return sortServiceKeys({ + // OVERRIDABLE VALUES: values that in case of not been set, it will take the following values + logging: { + driver: "json-file", + options: { + "max-size": "10m", + "max-file": "3" + } + }, + restart: "unless-stopped", - // SAFE KEYS: values that are whitelisted - ...pick( - serviceUnsafe, - dockerComposeSafeKeys.filter((safeKey) => safeKey !== "build") - ), + // SAFE KEYS: values that are whitelisted + ...pick( + serviceUnsafe, + dockerComposeSafeKeys.filter((safeKey) => safeKey !== "build") + ), - // MANDATORY VALUES: values that will be overwritten with dappnode defaults - container_name: getContainerName({ dnpName, serviceName, isCore }), - image: getImageTag({ serviceName, dnpName, version }), - environment: parseEnvironment(serviceUnsafe.environment || {}), - // Overrides any DNS provided to use the default Docker DNS server - // Since Core v0.2.82, the bind package is not used anymore as DNS server for the containers - dns: undefined, - networks: setServiceNetworksWithAliases(serviceUnsafe.networks, { - serviceName, - dnpName, - // The root pkg alias will be added to the main service or if it is a mono service - isMainOrMonoservice: - isMonoService || manifest.mainService === serviceName, - }), - }); - } - ), + // MANDATORY VALUES: values that will be overwritten with dappnode defaults + container_name: getContainerName({ dnpName, serviceName, isCore }), + image: getImageTag({ serviceName, dnpName, version }), + environment: parseEnvironment(serviceUnsafe.environment || {}), + // Overrides any DNS provided to use the default Docker DNS server + // Since Core v0.2.82, the bind package is not used anymore as DNS server for the containers + dns: undefined, + networks: setServiceNetworksWithAliases(serviceUnsafe.networks, { + serviceName, + dnpName, + // The root pkg alias will be added to the main service or if it is a mono service + isMainOrMonoservice: isMonoService || manifest.mainService === serviceName + }) + }); + }), volumes: composeUnsafe.volumes || {}, - networks: setNetworks(composeUnsafe.networks), + networks: setNetworks(composeUnsafe.networks) }); } @@ -110,25 +98,21 @@ function setServiceNetworksWithAliases( if (!serviceNetworks) return { [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: getPrivateNetworkAliases(service), - }, + aliases: getPrivateNetworkAliases(service) + } }; serviceNetworks = parseServiceNetworks(serviceNetworks); - const dncoreServiceNetwork = - serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] || {}; + const dncoreServiceNetwork = serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] || {}; // do not allow to set hardcoded IPs except for bind - if ( - dncoreServiceNetwork.ipv4_address && - service.dnpName !== params.bindDnpName - ) + if (dncoreServiceNetwork.ipv4_address && service.dnpName !== params.bindDnpName) delete dncoreServiceNetwork.ipv4_address; return { ...serviceNetworks, [params.DOCKER_PRIVATE_NETWORK_NAME]: { ...dncoreServiceNetwork, - aliases: getPrivateNetworkAliases(service), - }, + aliases: getPrivateNetworkAliases(service) + } }; } @@ -136,17 +120,15 @@ function setServiceNetworksWithAliases( * Returns the network provided with the `external: true` added if not provided * If the network dncore_network is not provided, it will be added */ -function setNetworks( - networks: ComposeNetworks | undefined = {} -): ComposeNetworks { +function setNetworks(networks: ComposeNetworks | undefined = {}): ComposeNetworks { const dncoreNetwork = networks[params.DOCKER_PRIVATE_NETWORK_NAME]; // Return network dncore_network with external: true if not provided if (!dncoreNetwork) return { ...networks, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - external: true, - }, + external: true + } }; // Return the network dncore_network with the external: true added @@ -155,8 +137,8 @@ function setNetworks( ...networks, [params.DOCKER_PRIVATE_NETWORK_NAME]: { ...dncoreNetwork, - external: true, - }, + external: true + } }; return networks; diff --git a/packages/dockerCompose/src/specialPermissions.ts b/packages/dockerCompose/src/specialPermissions.ts index d1f688708..cd955e624 100644 --- a/packages/dockerCompose/src/specialPermissions.ts +++ b/packages/dockerCompose/src/specialPermissions.ts @@ -4,10 +4,7 @@ import { Compose, SpecialPermission } from "@dappnode/types"; * Parses relevant settings in the compose that may be dangerous or grant * special permissions to this release's DNP */ -export function parseSpecialPermissions( - compose: Compose, - isCore: boolean -): SpecialPermission[] { +export function parseSpecialPermissions(compose: Compose, isCore: boolean): SpecialPermission[] { const specialPermissions: SpecialPermission[] = []; for (const [serviceName, service] of Object.entries(compose.services)) { @@ -18,7 +15,7 @@ export function parseSpecialPermissions( name: "Privileged access to the system host", details: "Allows to manipulate and read any installed package and install additional packages. Allows to fully interact with the host system", - serviceName, + serviceName }); if (isCore && service.networks && !Array.isArray(service.networks)) { @@ -27,7 +24,7 @@ export function parseSpecialPermissions( specialPermissions.push({ name: "Admin privileges in DAppNode's API", details: "Allows package can execute all admin action", - serviceName, + serviceName }); } @@ -36,7 +33,7 @@ export function parseSpecialPermissions( specialPermissions.push({ name: `Privileged system capability ${cap}`, details: `See docker docs for more information https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities`, - serviceName, + serviceName }); if (network_mode === "host") @@ -44,7 +41,7 @@ export function parseSpecialPermissions( name: "Access to the host network", details: "Allows to connect directly to the host's network. It can bind its open ports directly to the host's IP address", - serviceName, + serviceName }); } diff --git a/packages/dockerCompose/src/userSettings.ts b/packages/dockerCompose/src/userSettings.ts index c8d989195..2b2368f4f 100644 --- a/packages/dockerCompose/src/userSettings.ts +++ b/packages/dockerCompose/src/userSettings.ts @@ -7,16 +7,10 @@ import { parseDevicePathMountpoint, getDevicePath, ComposeFileEditor, - parseServiceNetworks, + parseServiceNetworks } from "./index.js"; import { parseEnvironment } from "@dappnode/utils"; -import { - Compose, - ComposeServiceNetworks, - PortMapping, - UserSettings, - VolumeMapping, -} from "@dappnode/types"; +import { Compose, ComposeServiceNetworks, PortMapping, UserSettings, VolumeMapping } from "@dappnode/types"; import { cleanCompose, isOmitable } from "./clean.js"; import { stringifyVolumeMappings } from "./volumes.js"; import { readContainerLabels, writeDefaultsToLabels } from "./labelsDb.js"; @@ -28,16 +22,13 @@ import { readContainerLabels, writeDefaultsToLabels } from "./labelsDb.js"; * volumes = ["/dev0/user-set-path:/usr/data"] */ const legacyDefaultVolumes: { [dnpName: string]: string[] } = { - "bitcoin.dnp.dappnode.eth": ["bitcoin_data:/root/.bitcoin"], + "bitcoin.dnp.dappnode.eth": ["bitcoin_data:/root/.bitcoin"] }; export const parseUserSettingsFns: { [P in keyof Required<UserSettings>]: (compose: Compose) => UserSettings[P]; } = { - environment: (compose) => - mapValues(compose.services, (service) => - parseEnvironment(service.environment || []) - ), + environment: (compose) => mapValues(compose.services, (service) => parseEnvironment(service.environment || [])), networks: (compose) => { // There can't be service networks without root networks @@ -47,9 +38,7 @@ export const parseUserSettingsFns: { (acc, [serviceName, service]) => { if (Array.isArray(service.networks)) { // Convert array to object - acc[serviceName] = ComposeFileEditor.convertNetworkArrayToObject( - service.networks - ); + acc[serviceName] = ComposeFileEditor.convertNetworkArrayToObject(service.networks); } else { acc[serviceName] = service.networks || {}; } @@ -62,7 +51,7 @@ export const parseUserSettingsFns: { return { serviceNetworks, - rootNetworks, + rootNetworks }; }, @@ -113,7 +102,7 @@ export const parseUserSettingsFns: { allNamedVolumeMountpoint: () => undefined, domainAlias: () => undefined, - fileUploads: () => ({}), + fileUploads: () => ({}) }; /** @@ -123,9 +112,7 @@ export const parseUserSettingsFns: { * user and which are not */ export function parseUserSettings(compose: Compose): UserSettings { - const userSettings = mapValues(parseUserSettingsFns, (parseUserSettingsFn) => - parseUserSettingsFn(compose) - ); + const userSettings = mapValues(parseUserSettingsFns, (parseUserSettingsFn) => parseUserSettingsFn(compose)); // Ignore objects that are empty to make tests and payloads cleaner return omitBy( userSettings, @@ -155,61 +142,44 @@ export function applyUserSettings( const networks = parseServiceNetworks(service.networks || {}); // User set - const userSetEnvironment = - (userSettings.environment || {})[serviceName] || {}; - const userSetPortMappings = - (userSettings.portMappings || {})[serviceName] || {}; - const userSetLegacyBindVolumes = - (userSettings.legacyBindVolumes || {})[serviceName] || {}; - const userSetNetworks = - (userSettings.networks?.serviceNetworks || {})[serviceName] || {}; + const userSetEnvironment = (userSettings.environment || {})[serviceName] || {}; + const userSetPortMappings = (userSettings.portMappings || {})[serviceName] || {}; + const userSetLegacyBindVolumes = (userSettings.legacyBindVolumes || {})[serviceName] || {}; + const userSetNetworks = (userSettings.networks?.serviceNetworks || {})[serviceName] || {}; // New values - const nextEnvironment = mapValues( - environment, - (envValue, envName) => userSetEnvironment[envName] || envValue - ); + const nextEnvironment = mapValues(environment, (envValue, envName) => userSetEnvironment[envName] || envValue); const nextPorts = stringifyPortMappings( portMappings.map((portMapping): PortMapping => { const portId = getPortMappingId(portMapping); const userSetHost = parseInt(userSetPortMappings[portId]); // Use `in` operator to tolerate empty hosts (= ephemeral port) - return portId in userSetPortMappings - ? { ...portMapping, host: userSetHost || undefined } - : portMapping; + return portId in userSetPortMappings ? { ...portMapping, host: userSetHost || undefined } : portMapping; }) ); // docker aliases must be uinique // TODO: use docker compose merge to automatically merge these dappnode docker compose properties // see https://github.com/dappnode/DNP_DAPPMANAGER/issues/1983 - const nextNetworks = mergeWith( - networks, - userSetNetworks, - (value1, value2) => { - return mergeWith(value1, value2, (subvalue1, subvalue2) => { - return union(subvalue1, subvalue2); - }); - } - ); + const nextNetworks = mergeWith(networks, userSetNetworks, (value1, value2) => { + return mergeWith(value1, value2, (subvalue1, subvalue2) => { + return union(subvalue1, subvalue2); + }); + }); // ##### <DEPRECATED> Kept for legacy compatibility const nextServiceVolumes = stringifyVolumeMappings( volumeMappings.map((vol): VolumeMapping => { const hostUserSet = vol.name && userSetLegacyBindVolumes[vol.name]; - return hostUserSet && path.isAbsolute(hostUserSet) - ? { host: hostUserSet, container: vol.container } - : vol; + return hostUserSet && path.isAbsolute(hostUserSet) ? { host: hostUserSet, container: vol.container } : vol; }) ); // ##### </DEPRECATED> const nextLabels = { ...(service.labels || {}), - ...writeDefaultsToLabels( - pick(service, ["environment", "ports", "volumes"]) - ), + ...writeDefaultsToLabels(pick(service, ["environment", "ports", "volumes"])) }; return { @@ -218,23 +188,21 @@ export function applyUserSettings( ports: nextPorts, volumes: nextServiceVolumes, labels: nextLabels, - networks: nextNetworks, + networks: nextNetworks }; }); // Volume section edits // Apply general mountpoint to all volumes + specific mountpoints to named volumes const nextVolumes = mapValues(compose.volumes || {}, (vol, volumeName) => { - const mountpoint = - (userSettings.namedVolumeMountpoints || {})[volumeName] || - userSettings.allNamedVolumeMountpoint; + const mountpoint = (userSettings.namedVolumeMountpoints || {})[volumeName] || userSettings.allNamedVolumeMountpoint; return mountpoint ? { driver_opts: { type: "none", device: getDevicePath({ mountpoint, dnpName, volumeName }), - o: "bind", - }, + o: "bind" + } } : vol; }); @@ -242,14 +210,14 @@ export function applyUserSettings( // TODO: Handle networks in array format? const nextNetworks = { ...compose.networks, - ...userSettings.networks?.rootNetworks, + ...userSettings.networks?.rootNetworks }; return cleanCompose({ ...compose, services: nextServices, volumes: nextVolumes, - networks: nextNetworks, + networks: nextNetworks }); } @@ -268,7 +236,6 @@ function getPortMappingId(portMapping: PortMapping): string { */ function isComposeVolumeUsed(compose: Compose, volName: string): boolean { return Object.values(compose.services).some( - (service) => - service.volumes && service.volumes.some((vol) => vol.startsWith(volName)) + (service) => service.volumes && service.volumes.some((vol) => vol.startsWith(volName)) ); } diff --git a/packages/dockerCompose/src/verify.ts b/packages/dockerCompose/src/verify.ts index 902d5cac9..54dd997ee 100644 --- a/packages/dockerCompose/src/verify.ts +++ b/packages/dockerCompose/src/verify.ts @@ -28,8 +28,7 @@ function verifyServiceVolumes(volumes: string[]): void { for (const vol of volumes) { try { - if (typeof vol !== "string") - throw Error("service.volumes items must be strings, use short syntax"); + if (typeof vol !== "string") throw Error("service.volumes items must be strings, use short syntax"); const [host, container] = vol.split(/:(.*)/); if (!host) throw Error("volume host not defined"); if (!container) throw Error("container path not defined"); @@ -45,13 +44,9 @@ function verifyServicePorts(ports: string[]): void { const portMappings = parsePortMappings(ports); for (const portMapping of portMappings) { if (portMapping.container > maxPortNumber) - throw Error( - `Port mapping container ${portMapping.container} is over the max ${maxPortNumber}` - ); + throw Error(`Port mapping container ${portMapping.container} is over the max ${maxPortNumber}`); if (portMapping.host && portMapping.host > maxPortNumber) - throw Error( - `Port mapping host ${portMapping.host} is over the max ${maxPortNumber}` - ); + throw Error(`Port mapping host ${portMapping.host} is over the max ${maxPortNumber}`); } } @@ -62,7 +57,6 @@ function verifyServicePorts(ports: string[]): void { * ``` */ const assertNoSubstitution = applyRecursivelyToStringValues((value, key) => { - if (value.includes("${")) - throw Error(`variable substitution not allowed: '${key}': '${value}'`); + if (value.includes("${")) throw Error(`variable substitution not allowed: '${key}': '${value}'`); return value; }); diff --git a/packages/dockerCompose/src/volumes.ts b/packages/dockerCompose/src/volumes.ts index a9ce6059f..7ac5bc2fa 100644 --- a/packages/dockerCompose/src/volumes.ts +++ b/packages/dockerCompose/src/volumes.ts @@ -23,23 +23,17 @@ export function normalizeVolumePath(volumePath: string): string { export function parseVolumeMappings(volumesArray: string[]): VolumeMapping[] { return volumesArray .map((volString): VolumeMapping => { - const [host, container] = volString - .split(/:(.*)/) - .map(normalizeVolumePath); + const [host, container] = volString.split(/:(.*)/).map(normalizeVolumePath); const isNamed = !host.startsWith("/") && !host.startsWith("~"); return { host, container, - name: isNamed ? host : undefined, + name: isNamed ? host : undefined }; }) .filter(({ container }) => container); } -export function stringifyVolumeMappings( - volumeMappings: VolumeMapping[] -): string[] { - return volumeMappings.map(({ name, host, container }) => - [name || host, container].join(":") - ); +export function stringifyVolumeMappings(volumeMappings: VolumeMapping[]): string[] { + return volumeMappings.map(({ name, host, container }) => [name || host, container].join(":")); } diff --git a/packages/dockerCompose/test/testUtils.ts b/packages/dockerCompose/test/testUtils.ts index af4c69cd4..e69012646 100644 --- a/packages/dockerCompose/test/testUtils.ts +++ b/packages/dockerCompose/test/testUtils.ts @@ -8,7 +8,7 @@ export const mockCompose: Compose = { services: { [mockDnpName]: { image: `${mockDnpName}:${mockDnpVersion}`, - container_name: `DAppNodePackage-${mockDnpName}`, - }, - }, + container_name: `DAppNodePackage-${mockDnpName}` + } + } }; diff --git a/packages/dockerCompose/test/unit/composeAliases.test.ts b/packages/dockerCompose/test/unit/composeAliases.test.ts index aeb3fd5f1..274e85fe1 100644 --- a/packages/dockerCompose/test/unit/composeAliases.test.ts +++ b/packages/dockerCompose/test/unit/composeAliases.test.ts @@ -1,10 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - ComposeFileEditor, - ComposeServiceEditor, - parseServiceNetworks, -} from "../../src/index.js"; +import { ComposeFileEditor, ComposeServiceEditor, parseServiceNetworks } from "../../src/index.js"; import { params } from "@dappnode/params"; import fs from "fs"; import path from "path"; @@ -55,30 +51,20 @@ networks: // Create necessary dir fs.mkdirSync(dnpRepoExamplePath, { recursive: true }); // Create example compose - fs.writeFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - exampleCompose - ); + fs.writeFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, exampleCompose); }); describe("Add/remove network aliases", () => { it("Should remove alias: example.dappnode", () => { const { compose, composeService, serviceNetwork } = { - ...getComposeEditors(dnpName, serviceName), + ...getComposeEditors(dnpName, serviceName) }; // Edit existing compose - composeService.removeNetworkAliases( - params.DOCKER_PRIVATE_NETWORK_NAME, - ["goerli-geth.dappnode"], - serviceNetwork - ); + composeService.removeNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, ["goerli-geth.dappnode"], serviceNetwork); compose.write(); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); const composeExpected = ` version: '3.5' @@ -117,21 +103,14 @@ networks: it("Should add alias: goerli-geth.dappnode", () => { const { compose, composeService, serviceNetwork } = { - ...getComposeEditors(dnpName, serviceName), + ...getComposeEditors(dnpName, serviceName) }; // Edit existing compose - composeService.addNetworkAliases( - params.DOCKER_PRIVATE_NETWORK_NAME, - ["example.dappnode"], - serviceNetwork - ); + composeService.addNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, ["example.dappnode"], serviceNetwork); compose.write(); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); const composeExpected = ` version: '3.5' @@ -173,7 +152,7 @@ networks: describe("Setglobal envs", () => { it("Should add global env file", () => { const { compose, composeService } = { - ...getComposeEditors(dnpName, serviceName), + ...getComposeEditors(dnpName, serviceName) }; // Edit existing compose @@ -181,10 +160,7 @@ networks: compose.write(); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); const composeExpected = ` version: '3.5' @@ -226,12 +202,12 @@ networks: it("Should add selected global envs", () => { const { compose, composeService } = { - ...getComposeEditors(dnpName, serviceName), + ...getComposeEditors(dnpName, serviceName) }; const GlobalEnvsPrefixed: GlobalEnvsPrefixed = { _DAPPNODE_GLOBAL_ACTIVE: "true", - _DAPPNODE_GLOBAL_NO_NAT_LOOPBACK: "false", + _DAPPNODE_GLOBAL_NO_NAT_LOOPBACK: "false" }; // Edit existing compose @@ -239,8 +215,8 @@ networks: [ { envs: ["ACTIVE", "NO_NAT_LOOPBACK"], - services: ["goerli-geth.dnp.dappnode.eth"], - }, + services: ["goerli-geth.dnp.dappnode.eth"] + } ], GlobalEnvsPrefixed, false @@ -248,10 +224,7 @@ networks: compose.write(); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); const composeExpected = ` version: '3.5' @@ -294,10 +267,7 @@ networks: afterEach(() => { // Overwrite the compose to be used in more tests - fs.writeFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - exampleCompose - ); + fs.writeFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, exampleCompose); }); }); @@ -312,14 +282,11 @@ function getComposeEditors( // Create compose editors const compose = new ComposeFileEditor(dnpName, false); const composeService = compose.services()[serviceName]; - const serviceNetworks = parseServiceNetworks( - composeService.get().networks || {} - ); - const serviceNetwork = - serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] ?? null; + const serviceNetworks = parseServiceNetworks(composeService.get().networks || {}); + const serviceNetwork = serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] ?? null; return { compose, composeService, - serviceNetwork, + serviceNetwork }; } diff --git a/packages/dockerCompose/test/unit/composeSpecs.test.ts b/packages/dockerCompose/test/unit/composeSpecs.test.ts index 66482c12e..0429121a4 100644 --- a/packages/dockerCompose/test/unit/composeSpecs.test.ts +++ b/packages/dockerCompose/test/unit/composeSpecs.test.ts @@ -4,11 +4,7 @@ import fs from "fs"; import path from "path"; import { Manifest, Compose } from "@dappnode/types"; import { yamlParse, yamlDump, isNotFoundError } from "@dappnode/utils"; -import { - setDappnodeComposeDefaults, - validateCompose, - verifyCompose, -} from "../../src/index.js"; +import { setDappnodeComposeDefaults, validateCompose, verifyCompose } from "../../src/index.js"; import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); @@ -18,7 +14,7 @@ const specsDir = path.join(__dirname, "./releaseSpecs"); const paths = { manifest: "dappnode_package.json", compose: "docker-compose.yml", - composeParsed: "docker-compose.parsed.yml", + composeParsed: "docker-compose.parsed.yml" }; describe("Compose specs, against real DNPs", () => { @@ -49,10 +45,7 @@ describe("Compose specs, against real DNPs", () => { const safeCompose = setDappnodeComposeDefaults(unsafeCompose, manifest); if (!composeParsed) { console.log(JSON.stringify(safeCompose, null, 2)); - fs.writeFileSync( - path.join(specsDir, dirName, paths.composeParsed), - yamlDump(safeCompose) - ); + fs.writeFileSync(path.join(specsDir, dirName, paths.composeParsed), yamlDump(safeCompose)); } else { expect(safeCompose).to.deep.equal(composeParsed); } diff --git a/packages/dockerCompose/test/unit/devicePath.test.ts b/packages/dockerCompose/test/unit/devicePath.test.ts index e9f2eda05..9195669a3 100644 --- a/packages/dockerCompose/test/unit/devicePath.test.ts +++ b/packages/dockerCompose/test/unit/devicePath.test.ts @@ -1,17 +1,13 @@ import "mocha"; import { expect } from "chai"; -import { - getDevicePath, - parseDevicePath, - parseDevicePathMountpoint, -} from "../../src/index.js"; +import { getDevicePath, parseDevicePath, parseDevicePathMountpoint } from "../../src/index.js"; const pathParts = { mountpoint: "/dev1/data", dnpName: "bitcoin.dnp.dappnode.eth", volumeName: "data", volumePath: "bitcoin.dnp.dappnode.eth/data", - mountpointPath: "/dev1/data/dappnode-volumes", + mountpointPath: "/dev1/data/dappnode-volumes" }; const devicePath = "/dev1/data/dappnode-volumes/bitcoin.dnp.dappnode.eth/data"; @@ -25,8 +21,6 @@ describe("device path", () => { }); it("Should parse a device path mountpoint", () => { - expect(parseDevicePathMountpoint(devicePath)).to.equal( - pathParts.mountpoint - ); + expect(parseDevicePathMountpoint(devicePath)).to.equal(pathParts.mountpoint); }); }); diff --git a/packages/dockerCompose/test/unit/labelDb.test.ts b/packages/dockerCompose/test/unit/labelDb.test.ts index f1dafb8d4..73945f219 100644 --- a/packages/dockerCompose/test/unit/labelDb.test.ts +++ b/packages/dockerCompose/test/unit/labelDb.test.ts @@ -18,7 +18,7 @@ describe("Parse and validate manifest labels to be used in the compose", () => { dockerTimeout: 10, defaultEnvironment: ["ENV_VAR1=value1", "ENV_VAR2=value2"], defaultPorts: ["8080:8080", "8081:8081"], - defaultVolumes: ["/var/log:/var/log"], + defaultVolumes: ["/var/log:/var/log"] }; const labelsRaw: ContainerLabelsRaw = { "dappnode.dnp.dnpName": "dnp-name", @@ -32,10 +32,9 @@ describe("Parse and validate manifest labels to be used in the compose", () => { "dappnode.dnp.isCore": "true", "dappnode.dnp.isMain": "true", "dappnode.dnp.dockerTimeout": "10", - "dappnode.dnp.default.environment": - '["ENV_VAR1=value1", "ENV_VAR2=value2"]', + "dappnode.dnp.default.environment": '["ENV_VAR1=value1", "ENV_VAR2=value2"]', "dappnode.dnp.default.ports": '["8080:8080", "8081:8081"]', - "dappnode.dnp.default.volumes": '["/var/log:/var/log"]', + "dappnode.dnp.default.volumes": '["/var/log:/var/log"]' }; const labelValues = readContainerLabels(labelsRaw); @@ -53,14 +52,14 @@ describe("Parse and validate manifest labels to be used in the compose", () => { avatar: "avatar-url", origin: "origin-url", chain: { - driver: "ethereum2-beacon-chain-prysm", + driver: "ethereum2-beacon-chain-prysm" }, isCore: true, isMain: true, dockerTimeout: 10, defaultEnvironment: ["ENV_VAR1=value1", "ENV_VAR2=value2"], defaultPorts: ["8080:8080", "8081:8081"], - defaultVolumes: ["/var/log:/var/log"], + defaultVolumes: ["/var/log:/var/log"] }; const labelsRaw: ContainerLabelsRaw = { "dappnode.dnp.dnpName": "dnp-name", @@ -74,10 +73,9 @@ describe("Parse and validate manifest labels to be used in the compose", () => { "dappnode.dnp.isCore": "true", "dappnode.dnp.isMain": "true", "dappnode.dnp.dockerTimeout": "10", - "dappnode.dnp.default.environment": - '["ENV_VAR1=value1", "ENV_VAR2=value2"]', + "dappnode.dnp.default.environment": '["ENV_VAR1=value1", "ENV_VAR2=value2"]', "dappnode.dnp.default.ports": '["8080:8080", "8081:8081"]', - "dappnode.dnp.default.volumes": '["/var/log:/var/log"]', + "dappnode.dnp.default.volumes": '["/var/log:/var/log"]' }; const labelValues = readContainerLabels(labelsRaw); @@ -100,7 +98,7 @@ describe("Parse and validate manifest labels to be used in the compose", () => { dockerTimeout: 10, defaultEnvironment: ["ENV_VAR1=value1", "ENV_VAR2=value2"], defaultPorts: ["8080:8080", "8081:8081"], - defaultVolumes: ["/var/log:/var/log"], + defaultVolumes: ["/var/log:/var/log"] }; const labelsRaw: ContainerLabelsRaw = { "dappnode.dnp.dnpName": "dnp-name", @@ -114,10 +112,9 @@ describe("Parse and validate manifest labels to be used in the compose", () => { "dappnode.dnp.isCore": "true", "dappnode.dnp.isMain": "true", "dappnode.dnp.dockerTimeout": "10", - "dappnode.dnp.default.environment": - '["ENV_VAR1=value1", "ENV_VAR2=value2"]', + "dappnode.dnp.default.environment": '["ENV_VAR1=value1", "ENV_VAR2=value2"]', "dappnode.dnp.default.ports": '["8080:8080", "8081:8081"]', - "dappnode.dnp.default.volumes": '["/var/log:/var/log"]', + "dappnode.dnp.default.volumes": '["/var/log:/var/log"]' }; const labelValues = readContainerLabels(labelsRaw); diff --git a/packages/dockerCompose/test/unit/network.test.ts b/packages/dockerCompose/test/unit/network.test.ts index e61f29eba..bb1bbc47b 100644 --- a/packages/dockerCompose/test/unit/network.test.ts +++ b/packages/dockerCompose/test/unit/network.test.ts @@ -13,13 +13,13 @@ describe("modules / compose / networks", () => { { id: "From array to obj", from: ["dncore_network"], - to: { dncore_network: {} }, + to: { dncore_network: {} } }, { id: "Keep obj", from: { dncore_network: {} }, - to: { dncore_network: {} }, - }, + to: { dncore_network: {} } + } ]; for (const { id, from, to } of testCases) { @@ -41,8 +41,8 @@ describe("modules / compose / networks", () => { const compose = new ComposeEditor({ version: "3.5", services: { - [serviceName]: { container_name, image }, - }, + [serviceName]: { container_name, image } + } }); compose.firstService().addNetwork(networkName, { aliases }); @@ -54,14 +54,14 @@ describe("modules / compose / networks", () => { container_name, image, networks: { - [networkName]: { aliases }, + [networkName]: { aliases } }, - dns: undefined, - }, + dns: undefined + } }, networks: { - [networkName]: { external: true }, - }, + [networkName]: { external: true } + } }); compose.firstService().removeNetwork(networkName); @@ -72,10 +72,10 @@ describe("modules / compose / networks", () => { "sample.dnp.dappnode.eth": { container_name, image, - dns: undefined, - }, + dns: undefined + } }, - networks: {}, + networks: {} }); }); }); diff --git a/packages/dockerCompose/test/unit/ports.test.ts b/packages/dockerCompose/test/unit/ports.test.ts index a64ca4123..ffb375aa3 100644 --- a/packages/dockerCompose/test/unit/ports.test.ts +++ b/packages/dockerCompose/test/unit/ports.test.ts @@ -1,12 +1,7 @@ import "mocha"; import { expect } from "chai"; import { PortProtocol } from "@dappnode/types"; -import { - parsePortMappings, - stringifyPortMappings, - mergePortMappings, - mergePortArrays, -} from "../../src/index.js"; +import { parsePortMappings, stringifyPortMappings, mergePortMappings, mergePortArrays } from "../../src/index.js"; describe("portMappings: parse, stringify and merge", () => { it("should parse and stringify port mappings", () => { @@ -15,18 +10,12 @@ describe("portMappings: parse, stringify and merge", () => { { container: 4001, protocol: PortProtocol.TCP }, { container: 5001, protocol: PortProtocol.UDP }, { host: 30303, container: 30303, protocol: PortProtocol.TCP }, - { host: 30303, container: 30303, protocol: PortProtocol.UDP }, + { host: 30303, container: 30303, protocol: PortProtocol.UDP } ]; - expect(parsePortMappings(portArray)).to.deep.equal( - portMappings, - "Wrong parse" - ); + expect(parsePortMappings(portArray)).to.deep.equal(portMappings, "Wrong parse"); - expect(stringifyPortMappings(portMappings)).to.deep.equal( - portArray, - "Wrong stringify" - ); + expect(stringifyPortMappings(portMappings)).to.deep.equal(portArray, "Wrong stringify"); }); it("should merge port mappings", () => { @@ -34,14 +23,14 @@ describe("portMappings: parse, stringify and merge", () => { { container: 5001, protocol: PortProtocol.UDP }, { host: 30304, container: 30303, protocol: PortProtocol.TCP }, { host: 30304, container: 30303, protocol: PortProtocol.UDP }, - { container: 60606, protocol: PortProtocol.TCP }, + { container: 60606, protocol: PortProtocol.TCP } ]; const portMappings2 = [ { container: 4001, protocol: PortProtocol.TCP }, { host: 30303, container: 30303, protocol: PortProtocol.TCP }, { host: 30303, container: 30303, protocol: PortProtocol.UDP }, - { host: 60606, container: 60606, protocol: PortProtocol.TCP }, + { host: 60606, container: 60606, protocol: PortProtocol.TCP } ]; const mergedPortMappings = mergePortMappings(portMappings1, portMappings2); @@ -51,7 +40,7 @@ describe("portMappings: parse, stringify and merge", () => { { host: 30304, container: 30303, protocol: PortProtocol.TCP }, { host: 30304, container: 30303, protocol: PortProtocol.UDP }, { container: 60606, protocol: PortProtocol.TCP }, - { container: 4001, protocol: PortProtocol.TCP }, + { container: 4001, protocol: PortProtocol.TCP } ]); }); @@ -62,10 +51,6 @@ describe("portMappings: parse, stringify and merge", () => { const mergedPortMappings = mergePortArrays(portArray1, portArray2); - expect(mergedPortMappings).to.deep.equal([ - "30656:30303/udp", - "8080:8080", - "4001:4001", - ]); + expect(mergedPortMappings).to.deep.equal(["30656:30303/udp", "8080:8080", "4001:4001"]); }); }); diff --git a/packages/dockerCompose/test/unit/releaseSpecs/prysm/dappnode_package.json b/packages/dockerCompose/test/unit/releaseSpecs/prysm/dappnode_package.json index 56ed5f265..8ef4e142b 100644 --- a/packages/dockerCompose/test/unit/releaseSpecs/prysm/dappnode_package.json +++ b/packages/dockerCompose/test/unit/releaseSpecs/prysm/dappnode_package.json @@ -10,9 +10,7 @@ "architectures": ["linux/amd64", "linux/arm64"], "mainService": "validator", "author": "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", - "contributors": [ - "dappLion <dapplion@dappnode.io> (https://github.com/dapplion)" - ], + "contributors": ["dappLion <dapplion@dappnode.io> (https://github.com/dapplion)"], "license": "GPL-3.0", "repository": { "type": "git", diff --git a/packages/dockerCompose/test/unit/setDappnodeComposeDefaults.test.ts b/packages/dockerCompose/test/unit/setDappnodeComposeDefaults.test.ts index e5fd15b24..77e970449 100644 --- a/packages/dockerCompose/test/unit/setDappnodeComposeDefaults.test.ts +++ b/packages/dockerCompose/test/unit/setDappnodeComposeDefaults.test.ts @@ -14,42 +14,42 @@ describe("setDappnodeComposeDefaults", () => { context: "./beacon-chain", args: { BEACON_API_PORT: "3500", - UPSTREAM_VERSION: "22.6.1", - }, + UPSTREAM_VERSION: "22.6.1" + } }, environment: { LOG_TYPE: "INFO", BEACON_API_PORT: "3500", HTTP_WEB3PROVIDER: "http://nethermind-xdai.dappnode:8545", CHECKPOINT_SYNC_URL: "", - EXTRA_OPTS: "", + EXTRA_OPTS: "" }, volumes: ["teku-gnosis-data:/opt/teku/data"], ports: ["9000/tcp", "9000/udp"], restart: "unless-stopped", - image: "beacon-chain.teku-gnosis.dnp.dappnode.eth:0.1.0", + image: "beacon-chain.teku-gnosis.dnp.dappnode.eth:0.1.0" }, validator: { build: { context: "./validator", args: { - UPSTREAM_VERSION: "22.6.1", - }, + UPSTREAM_VERSION: "22.6.1" + } }, environment: { LOG_TYPE: "INFO", BEACON_NODE_ADDR: "http://beacon-chain.teku-gnosis.dappnode:3500", GRAFFITI: "validating_from_DAppNode", EXTRA_OPTS: "", - FEE_RECIPIENT_ADDRESS: "", + FEE_RECIPIENT_ADDRESS: "" }, restart: "unless-stopped", - image: "validator.teku-gnosis.dnp.dappnode.eth:0.1.0", - }, + image: "validator.teku-gnosis.dnp.dappnode.eth:0.1.0" + } }, volumes: { - "teku-gnosis-data": {}, - }, + "teku-gnosis-data": {} + } }; const manifest: Manifest = { name: "teku-gnosis.dnp.dappnode.eth", @@ -58,95 +58,91 @@ describe("setDappnodeComposeDefaults", () => { architectures: ["linux/amd64"], upstreamRepo: "ConsenSys/teku", shortDescription: "Teku Gnosis Chain CL Beacon chain + validator", - description: - "Teku Gnosis Chain Consensus Layer (CL) Beacon chain + validator developed by the ConsenSys Team", + description: "Teku Gnosis Chain Consensus Layer (CL) Beacon chain + validator developed by the ConsenSys Team", type: "service", - author: - "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", + author: "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", contributors: [ "mgarciate <mgarciate@gmail.com> (https://github.com/mgarciate)", - "pablomendezroyo <mendez4a@gmail.com> (https://github.com/pablomendezroyo", + "pablomendezroyo <mendez4a@gmail.com> (https://github.com/pablomendezroyo" ], categories: ["Blockchain"], repository: { type: "git", - url: "git+https://github.com/ConsenSys/teku.git", + url: "git+https://github.com/ConsenSys/teku.git" }, bugs: { - url: "https://github.com/ConsenSys/teku/issues", + url: "https://github.com/ConsenSys/teku/issues" }, links: { ui: "http://ui.web3signer-gnosis.dappnode?signer_url=http://web3signer.web3signer-gnosis.dappnode:9000", homepage: "https://docs.teku.consensys.net", readme: "https://github.com/ConsenSys/teku/blob/master/README.md", - docs: "https://docs.teku.consensys.net", + docs: "https://docs.teku.consensys.net" }, license: "Apache-2.0", requirements: { - minimumDappnodeVersion: "0.2.56", + minimumDappnodeVersion: "0.2.56" }, chain: { driver: "ethereum-beacon-chain", serviceName: "beacon-chain", - portNumber: 3500, + portNumber: 3500 }, dependencies: { - "web3signer-gnosis.dnp.dappnode.eth": "latest", + "web3signer-gnosis.dnp.dappnode.eth": "latest" }, warnings: { onRemove: - "Make sure your web3signer does not have this client selected or you will stop validating! (Packages > web3signer > config > client)", - }, + "Make sure your web3signer does not have this client selected or you will stop validating! (Packages > web3signer > config > client)" + } }; const expectedCompose: Compose = { version: "3.5", services: { "beacon-chain": { - container_name: - "DAppNodePackage-beacon-chain.teku-gnosis.dnp.dappnode.eth", + container_name: "DAppNodePackage-beacon-chain.teku-gnosis.dnp.dappnode.eth", environment: { LOG_TYPE: "INFO", BEACON_API_PORT: "3500", HTTP_WEB3PROVIDER: "http://nethermind-xdai.dappnode:8545", CHECKPOINT_SYNC_URL: "", - EXTRA_OPTS: "", + EXTRA_OPTS: "" }, image: "beacon-chain.teku-gnosis.dnp.dappnode.eth:0.1.0", logging: { driver: "json-file", - options: { "max-size": "10m", "max-file": "3" }, + options: { "max-size": "10m", "max-file": "3" } }, networks: { - dncore_network: { aliases: ["beacon-chain.teku-gnosis.dappnode"] }, + dncore_network: { aliases: ["beacon-chain.teku-gnosis.dappnode"] } }, ports: ["9000/tcp", "9000/udp"], restart: "unless-stopped", - volumes: ["teku-gnosis-data:/opt/teku/data"], + volumes: ["teku-gnosis-data:/opt/teku/data"] }, validator: { - container_name: - "DAppNodePackage-validator.teku-gnosis.dnp.dappnode.eth", + container_name: "DAppNodePackage-validator.teku-gnosis.dnp.dappnode.eth", environment: { LOG_TYPE: "INFO", BEACON_NODE_ADDR: "http://beacon-chain.teku-gnosis.dappnode:3500", GRAFFITI: "validating_from_DAppNode", EXTRA_OPTS: "", - FEE_RECIPIENT_ADDRESS: "", + FEE_RECIPIENT_ADDRESS: "" }, image: "validator.teku-gnosis.dnp.dappnode.eth:0.1.0", logging: { driver: "json-file", - options: { "max-size": "10m", "max-file": "3" }, + options: { "max-size": "10m", "max-file": "3" } }, networks: { - dncore_network: { aliases: ["validator.teku-gnosis.dappnode"] }, + dncore_network: { aliases: ["validator.teku-gnosis.dappnode"] } }, - restart: "unless-stopped", - }, + restart: "unless-stopped" + } }, volumes: { "teku-gnosis-data": {} }, - networks: { dncore_network: { external: true } }, + networks: { dncore_network: { external: true } } }; validateDappnodeCompose(compose, manifest); @@ -161,11 +157,11 @@ describe("setDappnodeComposeDefaults", () => { networks: { dncore_network: { name: "dncore_network", - external: true, - }, + external: true + } }, volumes: { - dappmanagerdnpdappnodeeth_data: {}, + dappmanagerdnpdappnodeeth_data: {} }, services: { "dappmanager.dnp.dappnode.eth": { @@ -177,14 +173,14 @@ describe("setDappnodeComposeDefaults", () => { "dappmanagerdnpdappnodeeth_data:/usr/src/app/dnp_repo/", "/usr/src/dappnode/DNCORE/:/usr/src/app/DNCORE/", "/var/run/docker.sock:/var/run/docker.sock", - "/etc/hostname:/etc/dappnodename:ro", + "/etc/hostname:/etc/dappnodename:ro" ], environment: [ "LOG_LEVEL=info", "ETH_MAINNET_RPC_URL_OVERRIDE=", "ETH_MAINNET_RPC_URL_REMOTE=", "IPFS_HOST=", - "DISABLE_UPNP=", + "DISABLE_UPNP=" ], dns: "172.33.1.2", networks: { @@ -194,39 +190,37 @@ describe("setDappnodeComposeDefaults", () => { "dappmanager.dnp.dappnode.eth.dappmanager.dappnode", "dappmanager.dappnode", "my.dappnode", - "dappnode.local", - ], - }, - }, - }, - }, + "dappnode.local" + ] + } + } + } + } }; const manifest: Manifest = { name: "dappmanager.dnp.dappnode.eth", version: "0.2.43", - description: - "Dappnode package responsible for providing the DappNode Package Manager", + description: "Dappnode package responsible for providing the DappNode Package Manager", type: "dncore", architectures: ["linux/amd64", "linux/arm64"], - author: - "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", + author: "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", contributors: [ "Eduardo Antuña <eduadiez@gmail.com> (https://github.com/eduadiez)", - "DAppLion <dapplion@giveth.io> (https://github.com/dapplion)", + "DAppLion <dapplion@giveth.io> (https://github.com/dapplion)" ], keywords: ["DAppNodeCore", "Manager", "Installer"], links: { ui: "http://my.dappnode/", - homepage: "https://github.com/dappnode/DNP_DAPPMANAGER#readme", + homepage: "https://github.com/dappnode/DNP_DAPPMANAGER#readme" }, repository: { type: "git", - url: "https://github.com/dappnode/DNP_DAPPMANAGER", + url: "https://github.com/dappnode/DNP_DAPPMANAGER" }, bugs: { - url: "https://github.com/dappnode/DNP_DAPPMANAGER/issues", + url: "https://github.com/dappnode/DNP_DAPPMANAGER/issues" }, - license: "GPL-3.0", + license: "GPL-3.0" }; const expectedCompose: Compose = { @@ -239,12 +233,12 @@ describe("setDappnodeComposeDefaults", () => { ETH_MAINNET_RPC_URL_OVERRIDE: "", ETH_MAINNET_RPC_URL_REMOTE: "", IPFS_HOST: "", - DISABLE_UPNP: "", + DISABLE_UPNP: "" }, image: "dappmanager.dnp.dappnode.eth:0.2.43", logging: { driver: "json-file", - options: { "max-size": "10m", "max-file": "3" }, + options: { "max-size": "10m", "max-file": "3" } }, networks: { dncore_network: { @@ -252,22 +246,22 @@ describe("setDappnodeComposeDefaults", () => { "dappmanager.dnp.dappnode.eth.dappmanager.dappnode", "dappmanager.dappnode", "my.dappnode", - "dappnode.local", - ], - }, + "dappnode.local" + ] + } }, volumes: [ "/run/dbus/system_bus_socket:/run/dbus/system_bus_socket", "dappmanagerdnpdappnodeeth_data:/usr/src/app/dnp_repo/", "/usr/src/dappnode/DNCORE/:/usr/src/app/DNCORE/", "/var/run/docker.sock:/var/run/docker.sock", - "/etc/hostname:/etc/dappnodename:ro", + "/etc/hostname:/etc/dappnodename:ro" ], - restart: "unless-stopped", - }, + restart: "unless-stopped" + } }, volumes: { dappmanagerdnpdappnodeeth_data: {} }, - networks: { dncore_network: { name: "dncore_network", external: true } }, + networks: { dncore_network: { name: "dncore_network", external: true } } }; validateDappnodeCompose(compose, manifest); diff --git a/packages/dockerCompose/test/unit/specialPermissions.test.ts b/packages/dockerCompose/test/unit/specialPermissions.test.ts index 816a14fe8..468defd10 100644 --- a/packages/dockerCompose/test/unit/specialPermissions.test.ts +++ b/packages/dockerCompose/test/unit/specialPermissions.test.ts @@ -16,12 +16,12 @@ describe("Modules > compose", () => { privileged: true, networks: { network: { - ipv4_address: "172.33.10.4", - }, + ipv4_address: "172.33.10.4" + } }, cap_add: ["NET_ADMIN", "SYS_ADMIN"], - network_mode: "host", - })), + network_mode: "host" + })) }; const specialPermissions = parseSpecialPermissions(compose, isCore); @@ -31,7 +31,7 @@ describe("Modules > compose", () => { "Admin privileges in DAppNode's API", "Privileged system capability NET_ADMIN", "Privileged system capability SYS_ADMIN", - "Access to the host network", + "Access to the host network" ]); }); }); diff --git a/packages/dockerCompose/test/unit/userSettings.test.ts b/packages/dockerCompose/test/unit/userSettings.test.ts index 0e0ded917..7e48e29d5 100644 --- a/packages/dockerCompose/test/unit/userSettings.test.ts +++ b/packages/dockerCompose/test/unit/userSettings.test.ts @@ -12,14 +12,14 @@ const mockDnpName = "mock-dnp.dnp.dappnode.eth"; const mockDnpVersion = "0.0.0"; const mockComposeService: ComposeService = { image: `${mockDnpName}:${mockDnpVersion}`, - container_name: `DAppNodePackage-${mockDnpName}`, + container_name: `DAppNodePackage-${mockDnpName}` }; const mockCompose: Compose = { version: "3.5", services: { - [mockDnpName]: mockComposeService, - }, + [mockDnpName]: mockComposeService + } }; const polkadotServiceName = "polkadot-kusama.public.dappnode.eth"; @@ -34,32 +34,32 @@ const polkadotNewCompose = { NODE_NAME: "DAppNodeNodler", VALIDATOR_ENABLE: "no", TELEMETRY_ENABLE: "no", - EXTRA_OPTS: "--out-peers 10 --in-peers 10", + EXTRA_OPTS: "--out-peers 10 --in-peers 10" }, restart: "unless-stopped", container_name: "DAppNodePackage-polkadot-kusama.public.dappnode.eth", networks: { - dncore_network: {}, - }, - }, + dncore_network: {} + } + } }, volumes: { - polkadot: {}, + polkadot: {} }, networks: { dncore_network: { - external: true, - }, - }, + external: true + } + } }; const polkadotCurrentCompose = { ...polkadotNewCompose, services: { [polkadotServiceName]: { - ...polkadotNewCompose.services[polkadotServiceName], - }, - }, + ...polkadotNewCompose.services[polkadotServiceName] + } + } }; describe("parseUserSettings", () => { @@ -71,20 +71,16 @@ describe("parseUserSettings", () => { ...mockComposeService, environment: { ORIGINAL: "0", - USERSET: "1", + USERSET: "1" }, ports: ["4001:4001", "9090:9090", "32764:6000"], - volumes: [ - "/dev1/custom-path:/usr/data0", - "moredata:/usr/data1", - `${bitcoinVolumeNameNew}:/usr/data2`, - ], + volumes: ["/dev1/custom-path:/usr/data0", "moredata:/usr/data1", `${bitcoinVolumeNameNew}:/usr/data2`], networks: { holesky_network: { - aliases: ["mock-dnp"], + aliases: ["mock-dnp"] } } - }, + } }, volumes: { moredata: {}, @@ -93,13 +89,13 @@ describe("parseUserSettings", () => { driver_opts: { device: `/dev0/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/${bitcoinVolumeNameNew}`, o: "bind", - type: "none", - }, - }, + type: "none" + } + } }, networks: { holesky_network: { - external: true, + external: true } } }; @@ -110,30 +106,30 @@ describe("parseUserSettings", () => { environment: { [mockDnpName]: { ORIGINAL: "0", - USERSET: "1", - }, + USERSET: "1" + } }, portMappings: { [mockDnpName]: { "4001/TCP": "4001", "6000/TCP": "32764", - "9090/TCP": "9090", - }, + "9090/TCP": "9090" + } }, namedVolumeMountpoints: { [bitcoinVolumeNameNew]: "/dev0/data", - moredata: "", + moredata: "" }, networks: { rootNetworks: { holesky_network: { - external: true, + external: true } }, serviceNetworks: { [mockDnpName]: { holesky_network: { - aliases: ["mock-dnp"], + aliases: ["mock-dnp"] } } } @@ -151,25 +147,25 @@ describe("parseUserSettings", () => { services: { [bitcoinName]: { ...mockComposeService, - volumes: ["/dev1/custom-path:/root/.bitcoin", "moredata:/usr/data2"], - }, + volumes: ["/dev1/custom-path:/root/.bitcoin", "moredata:/usr/data2"] + } }, volumes: { [bitcoinVolumeName]: {}, - moredata: {}, - }, + moredata: {} + } }; const userSettings = parseUserSettings(compose); const expectedUserSet: UserSettings = { namedVolumeMountpoints: { - moredata: "", + moredata: "" }, legacyBindVolumes: { [bitcoinName]: { - [bitcoinVolumeName]: "/dev1/custom-path", - }, + [bitcoinVolumeName]: "/dev1/custom-path" + } } }; @@ -185,27 +181,27 @@ describe("parseUserSettings", () => { EXTRA_OPTS: "--out-peers 10 --in-peers 10", NODE_NAME: "DAppNodeNodler", TELEMETRY_ENABLE: "no", - VALIDATOR_ENABLE: "no", - }, + VALIDATOR_ENABLE: "no" + } }, portMappings: { [polkadotServiceName]: { - "30333/TCP": "30333", - }, + "30333/TCP": "30333" + } }, namedVolumeMountpoints: { - polkadot: "", + polkadot: "" }, networks: { rootNetworks: { dncore_network: { - external: true, - }, + external: true + } }, serviceNetworks: { [polkadotServiceName]: { - dncore_network: {}, - }, + dncore_network: {} + } } } }; @@ -220,14 +216,14 @@ describe("parseUserSettings", () => { networks: { network: { driver: "bridge", - ipam: { config: [{ subnet: "172.33.0.0/16" }] }, - }, + ipam: { config: [{ subnet: "172.33.0.0/16" }] } + } }, volumes: { ethchaindnpdappnodeeth_data: {}, ethchaindnpdappnodeeth_geth: {}, ethchaindnpdappnodeeth_identity: {}, - ethchaindnpdappnodeeth_ipc: {}, + ethchaindnpdappnodeeth_ipc: {} }, services: { [serviceName]: { @@ -238,21 +234,21 @@ describe("parseUserSettings", () => { "ethchaindnpdappnodeeth_data:/root/.local/share/io.parity.ethereum", "ethchaindnpdappnodeeth_geth:/root/.ethereum", "ethchaindnpdappnodeeth_identity:/root/identity", - "ethchaindnpdappnodeeth_ipc:/root/.ethereum/ipc", + "ethchaindnpdappnodeeth_ipc:/root/.ethereum/ipc" ], environment: { EXTRA_OPTS: "--warp-barrier 9530000", EXTRA_OPTS_GETH: "", - DEFAULT_CLIENT: "PARITY", + DEFAULT_CLIENT: "PARITY" }, ports: ["35353:30303", "35353:30303/udp", "35354:30304/udp"], networks: { network: { - ipv4_address: "172.33.1.6", - }, - }, - }, - }, + ipv4_address: "172.33.1.6" + } + } + } + } }; const expectedUserSet: UserSettings = { @@ -260,37 +256,37 @@ describe("parseUserSettings", () => { [serviceName]: { EXTRA_OPTS: "--warp-barrier 9530000", EXTRA_OPTS_GETH: "", - DEFAULT_CLIENT: "PARITY", - }, + DEFAULT_CLIENT: "PARITY" + } }, portMappings: { [serviceName]: { "30303/TCP": "35353", "30303/UDP": "35353", - "30304/UDP": "35354", - }, + "30304/UDP": "35354" + } }, namedVolumeMountpoints: { ethchaindnpdappnodeeth_data: "", ethchaindnpdappnodeeth_geth: "", ethchaindnpdappnodeeth_identity: "", - ethchaindnpdappnodeeth_ipc: "", + ethchaindnpdappnodeeth_ipc: "" }, networks: { rootNetworks: { network: { driver: "bridge", - ipam: { config: [{ subnet: "172.33.0.0/16" }] }, - }, + ipam: { config: [{ subnet: "172.33.0.0/16" }] } + } }, serviceNetworks: { [serviceName]: { network: { - ipv4_address: "172.33.1.6", - }, + ipv4_address: "172.33.1.6" + } } } - }, + } }; const userSettings = parseUserSettings(compose); @@ -305,8 +301,7 @@ describe("applyUserSettings", () => { */ const applyUserSettingsTest: typeof applyUserSettings = (...args) => { const nextCompose = applyUserSettings(...args); - for (const serviceName in nextCompose.services) - delete nextCompose.services[serviceName].labels; + for (const serviceName in nextCompose.services) delete nextCompose.services[serviceName].labels; return nextCompose; }; @@ -324,40 +319,40 @@ describe("applyUserSettings", () => { volumes: [ `${bitcoinVolumeNameNew}:/usr/data0`, "/dev1/custom-path:/usr/data1", - `${bitcoinVolumeName}:/usr/data2`, - ], - }, + `${bitcoinVolumeName}:/usr/data2` + ] + } }, volumes: { [bitcoinVolumeNameNew]: {}, - [bitcoinVolumeName]: {}, - }, + [bitcoinVolumeName]: {} + } }; const userSet: UserSettings = { environment: { [mockDnpName]: { - USERSET: "NEW_VALUE", - }, + USERSET: "NEW_VALUE" + } }, portMappings: { [mockDnpName]: { "4001/TCP": "4111", - "9090/UDP": "", - }, + "9090/UDP": "" + } }, namedVolumeMountpoints: { - [bitcoinVolumeNameNew]: "/dev0/data", + [bitcoinVolumeNameNew]: "/dev0/data" }, legacyBindVolumes: { [mockDnpName]: { - [bitcoinVolumeName]: "/dev2/user-set-path", - }, - }, + [bitcoinVolumeName]: "/dev2/user-set-path" + } + } }; const composeReturn = applyUserSettingsTest(compose, userSet, { - dnpName: mockDnpName, + dnpName: mockDnpName }); const expectedCompose: Compose = { ...compose, @@ -369,9 +364,9 @@ describe("applyUserSettings", () => { volumes: [ `${bitcoinVolumeNameNew}:/usr/data0`, "/dev1/custom-path:/usr/data1", - "/dev2/user-set-path:/usr/data2", - ], - }, + "/dev2/user-set-path:/usr/data2" + ] + } }, volumes: { ...compose.volumes, @@ -379,10 +374,10 @@ describe("applyUserSettings", () => { driver_opts: { device: `/dev0/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/${bitcoinVolumeNameNew}`, o: "bind", - type: "none", - }, - }, - }, + type: "none" + } + } + } }; expect(composeReturn).to.deep.equal(expectedCompose); }); @@ -393,22 +388,22 @@ describe("applyUserSettings", () => { services: { [mockDnpName]: { ...mockComposeService, - ports: ["3333/udp", "4444:4444/udp"], - }, - }, + ports: ["3333/udp", "4444:4444/udp"] + } + } }; const userSet: UserSettings = { portMappings: { - [mockDnpName]: { "3333/UDP": "3330", "4444/UDP": "" }, - }, + [mockDnpName]: { "3333/UDP": "3330", "4444/UDP": "" } + } }; const expectedServiceParts = { - ports: ["3330:3333/udp", "4444/udp"], + ports: ["3330:3333/udp", "4444/udp"] }; const composeReturn = applyUserSettingsTest(compose, userSet, { - dnpName: mockDnpName, + dnpName: mockDnpName }); const serviceParts = pick(composeReturn.services[mockDnpName], ["ports"]); @@ -417,11 +412,7 @@ describe("applyUserSettings", () => { it("Should return the same compose if re-applying it's own user settings", () => { const userSettings = parseUserSettings(polkadotCurrentCompose); - const composeReturn = applyUserSettingsTest( - polkadotNewCompose, - userSettings, - { dnpName: mockDnpName } - ); + const composeReturn = applyUserSettingsTest(polkadotNewCompose, userSettings, { dnpName: mockDnpName }); expect(composeReturn).to.deep.equal(polkadotCurrentCompose); }); @@ -433,17 +424,17 @@ describe("applyUserSettings", () => { services: { [mockDnpName]: { ...mockComposeService, - volumes: ["data:/usr/data", "identity:/usr/id"], - }, + volumes: ["data:/usr/data", "identity:/usr/id"] + } }, volumes: { data: {}, - identity: {}, - }, + identity: {} + } }; const userSet: UserSettings = { - allNamedVolumeMountpoint: mountpoint, + allNamedVolumeMountpoint: mountpoint }; const expectedComposeAfterFirstInstall: Compose = { @@ -451,50 +442,44 @@ describe("applyUserSettings", () => { services: { [mockDnpName]: { ...originalCompose.services[mockDnpName], - volumes: ["data:/usr/data", "identity:/usr/id"], - }, + volumes: ["data:/usr/data", "identity:/usr/id"] + } }, volumes: { data: { driver_opts: { - device: - "/dev1/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/data", + device: "/dev1/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/data", o: "bind", - type: "none", - }, + type: "none" + } }, identity: { driver_opts: { - device: - "/dev1/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/identity", + device: "/dev1/data/dappnode-volumes/mock-dnp.dnp.dappnode.eth/identity", o: "bind", - type: "none", - }, - }, - }, + type: "none" + } + } + } }; const expectedUserSettingsOnUpdate: UserSettings = { namedVolumeMountpoints: { data: mountpoint, - identity: mountpoint, - }, + identity: mountpoint + } }; - expect( - applyUserSettingsTest(originalCompose, userSet, { dnpName: mockDnpName }) - ).to.deep.equal( + expect(applyUserSettingsTest(originalCompose, userSet, { dnpName: mockDnpName })).to.deep.equal( expectedComposeAfterFirstInstall, "allNamedVolumeMountpoint setting should be applied in first install" ); - const userSettingsOnUpdate = parseUserSettings( - expectedComposeAfterFirstInstall - ); + const userSettingsOnUpdate = parseUserSettings(expectedComposeAfterFirstInstall); expect(userSettingsOnUpdate).to.deep.equal(expectedUserSettingsOnUpdate); expect( applyUserSettingsTest(originalCompose, userSettingsOnUpdate, { - dnpName: mockDnpName, + dnpName: mockDnpName }) ).to.deep.equal( expectedComposeAfterFirstInstall, @@ -512,12 +497,12 @@ describe("applyUserSettings", () => { [dnpName]: { container_name: dnpName, image: `${dnpName}:0.1.0`, - volumes: [`${customBind}:/root/.bitcoin`], - }, + volumes: [`${customBind}:/root/.bitcoin`] + } }, volumes: { - bitcoin_data: {}, - }, + bitcoin_data: {} + } }; const newCompose: Compose = { @@ -526,12 +511,12 @@ describe("applyUserSettings", () => { [dnpName]: { container_name: dnpName, image: `${dnpName}:0.2.0`, - volumes: ["bitcoin_data:/root/.bitcoin"], - }, + volumes: ["bitcoin_data:/root/.bitcoin"] + } }, volumes: { - bitcoin_data: {}, - }, + bitcoin_data: {} + } }; const expectedComposeAfterUpdate: Compose = { @@ -539,26 +524,24 @@ describe("applyUserSettings", () => { services: { [dnpName]: { ...newCompose.services[dnpName], - volumes: [`${customBind}:/root/.bitcoin`], - }, - }, + volumes: [`${customBind}:/root/.bitcoin`] + } + } }; const expectedUserSettingsOnUpdate: UserSettings = { legacyBindVolumes: { [dnpName]: { - bitcoin_data: customBind, - }, - }, + bitcoin_data: customBind + } + } }; const userSettingsOnUpdate = parseUserSettings(oldLocalCompose); - expect(userSettingsOnUpdate).to.deep.equal( - expectedUserSettingsOnUpdate, - "Wrong userSettingsOnUpdate" + expect(userSettingsOnUpdate).to.deep.equal(expectedUserSettingsOnUpdate, "Wrong userSettingsOnUpdate"); + expect(applyUserSettingsTest(newCompose, userSettingsOnUpdate, { dnpName })).to.deep.equal( + expectedComposeAfterUpdate, + "Wrong composeAfterUpdate" ); - expect( - applyUserSettingsTest(newCompose, userSettingsOnUpdate, { dnpName }) - ).to.deep.equal(expectedComposeAfterUpdate, "Wrong composeAfterUpdate"); }); }); diff --git a/packages/dockerCompose/test/unit/verify.test.ts b/packages/dockerCompose/test/unit/verify.test.ts index 55c6b0e57..2030cc6df 100644 --- a/packages/dockerCompose/test/unit/verify.test.ts +++ b/packages/dockerCompose/test/unit/verify.test.ts @@ -8,16 +8,14 @@ describe("verify compose", () => { return { version: "3.5", services: { - test: { container_name: "name", image: "image", ...service }, - }, + test: { container_name: "name", image: "image", ...service } + } }; } it("Should throw if compose contains variable substitution", () => { const compose = getTestCompose({ environment: { PORT: "${PORT}" } }); - expect(() => verifyCompose(compose)).to.throw( - "variable substitution not allowed" - ); + expect(() => verifyCompose(compose)).to.throw("variable substitution not allowed"); }); it("Should not throw with a regular compose", () => { diff --git a/packages/dockerCompose/test/unit/volumes.test.ts b/packages/dockerCompose/test/unit/volumes.test.ts index 6ca6cc43d..f9362f9b7 100644 --- a/packages/dockerCompose/test/unit/volumes.test.ts +++ b/packages/dockerCompose/test/unit/volumes.test.ts @@ -1,46 +1,36 @@ import "mocha"; import { expect } from "chai"; import { VolumeMapping } from "@dappnode/types"; -import { - parseVolumeMappings, - stringifyVolumeMappings, - normalizeVolumePath, -} from "../../src/index.js"; +import { parseVolumeMappings, stringifyVolumeMappings, normalizeVolumePath } from "../../src/index.js"; describe("volumeMappings: parse, stringify and merge", () => { it("should parse and stringify volume mappings", () => { const volumeArray = [ "/etc/hostname:/etc/vpnname:ro", "/var/run/docker.sock:/var/run/docker.sock", - "vpndnpdappnodeeth_shared:/var/spool/openvpn", + "vpndnpdappnodeeth_shared:/var/spool/openvpn" ]; const volumeMappings: VolumeMapping[] = [ { container: "/etc/vpnname:ro", host: "/etc/hostname", - name: undefined, + name: undefined }, { container: "/var/run/docker.sock", host: "/var/run/docker.sock", - name: undefined, + name: undefined }, { container: "/var/spool/openvpn", host: "vpndnpdappnodeeth_shared", - name: "vpndnpdappnodeeth_shared", - }, + name: "vpndnpdappnodeeth_shared" + } ]; - expect(parseVolumeMappings(volumeArray)).to.deep.equal( - volumeMappings, - "Wrong parse" - ); + expect(parseVolumeMappings(volumeArray)).to.deep.equal(volumeMappings, "Wrong parse"); - expect(stringifyVolumeMappings(volumeMappings)).to.deep.equal( - volumeArray, - "Wrong stringify" - ); + expect(stringifyVolumeMappings(volumeMappings)).to.deep.equal(volumeArray, "Wrong stringify"); }); describe("Path normalization", () => { @@ -49,7 +39,7 @@ describe("volumeMappings: parse, stringify and merge", () => { { path: "/root/.ethereum/", res: "/root/.ethereum" }, { path: "/hello///", res: "/hello" }, { path: "ethchain_geth", res: "ethchain_geth" }, - { path: "data", res: "data" }, + { path: "data", res: "data" } ]; for (const { path, res } of paths) it(`Should normalize ${path}`, () => { diff --git a/packages/dyndns/.eslintignore b/packages/dyndns/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/dyndns/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/dyndns/.eslintrc.cjs b/packages/dyndns/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/dyndns/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/dyndns/package.json b/packages/dyndns/package.json index 75bddf496..8431f5adc 100644 --- a/packages/dyndns/package.json +++ b/packages/dyndns/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "dev": "tsc -w", - "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "lint": "eslint . --ext .ts --fix src" + "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/dyndns/src/generateKeysIfNotExistOrNotValid.ts b/packages/dyndns/src/generateKeysIfNotExistOrNotValid.ts index eac0eb903..740602d32 100644 --- a/packages/dyndns/src/generateKeysIfNotExistOrNotValid.ts +++ b/packages/dyndns/src/generateKeysIfNotExistOrNotValid.ts @@ -62,7 +62,7 @@ export function generateKeysIfNotExistOrNotValid(): void { db.dyndnsIdentity.set({ address, privateKey, - publicKey, + publicKey }); db.domain.set(getDomainFromIdentityAddress(address)); diff --git a/packages/dyndns/src/updateDyndnsIp.ts b/packages/dyndns/src/updateDyndnsIp.ts index eb398eb2d..e9187c916 100644 --- a/packages/dyndns/src/updateDyndnsIp.ts +++ b/packages/dyndns/src/updateDyndnsIp.ts @@ -30,27 +30,18 @@ export async function updateDyndnsIp(): Promise<void> { db.domain.set(dynDnsResponse.domain); } -export async function updateDyndnsIpFromPrivateKey( - privateKey: string -): Promise<DyndnsResponse> { +export async function updateDyndnsIpFromPrivateKey(privateKey: string): Promise<DyndnsResponse> { const timestamp = Math.floor(Date.now() / 1000); // Using ethers as a raw signer (without '\x19Ethereum Signed Message:\n' prefix) to mimic previous EthCrypto signature const wallet = new ethers.Wallet(privateKey); const signingKey = new ethers.SigningKey(privateKey); const signDigest = signingKey.sign.bind(signingKey); - const hash = ethers.solidityPackedKeccak256( - ["string"], - [timestamp.toString()] - ); + const hash = ethers.solidityPackedKeccak256(["string"], [timestamp.toString()]); const signature = ethers.Signature.from(signDigest(hash)); const res = await fetch( - `${dyndnsHost}/?${[ - `address=${wallet.address}`, - `timestamp=${timestamp}`, - `sig=${signature.serialized}`, - ].join("&")}` + `${dyndnsHost}/?${[`address=${wallet.address}`, `timestamp=${timestamp}`, `sig=${signature.serialized}`].join("&")}` ); if (res.status !== 200) { diff --git a/packages/dyndns/test/unit/dyndns.test.ts b/packages/dyndns/test/unit/dyndns.test.ts index 0bec325d3..bf5a972f5 100644 --- a/packages/dyndns/test/unit/dyndns.test.ts +++ b/packages/dyndns/test/unit/dyndns.test.ts @@ -3,7 +3,7 @@ import { expect } from "chai"; import { generateDyndnsIdentity, getDomainFromIdentityAddress, - isPrivateKeyValid, + isPrivateKeyValid } from "../../src/generateKeysIfNotExistOrNotValid.js"; import { ethers } from "ethers"; import { params } from "@dappnode/params"; @@ -34,14 +34,11 @@ describe("Dyndns", () => { // 4e1a38a2394acd41.dyndns.dappnode.io const domain = getDomainFromIdentityAddress(identity.address); // check it ends with .dyndns.dappnode.io - if (!domain.endsWith(params.DYNDNS_DOMAIN)) - throw new Error(`Domain does not end with: ${params.DYNDNS_DOMAIN}`); + if (!domain.endsWith(params.DYNDNS_DOMAIN)) throw new Error(`Domain does not end with: ${params.DYNDNS_DOMAIN}`); // check it does not start with 0x - if (domain.startsWith("0x")) - throw new Error(`Domain starts with 0x: ${domain}`); + if (domain.startsWith("0x")) throw new Error(`Domain starts with 0x: ${domain}`); // it should have 35 characters - if (domain.length !== 35) - throw new Error(`Domain length is not 35: ${domain.length}`); + if (domain.length !== 35) throw new Error(`Domain length is not 35: ${domain.length}`); }); it("Should update a dyndns identity", async () => { diff --git a/packages/ethicalMetrics/.eslintignore b/packages/ethicalMetrics/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/ethicalMetrics/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/ethicalMetrics/.eslintrc.cjs b/packages/ethicalMetrics/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/ethicalMetrics/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/ethicalMetrics/package.json b/packages/ethicalMetrics/package.json index 6610500dc..46915fec5 100644 --- a/packages/ethicalMetrics/package.json +++ b/packages/ethicalMetrics/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "devDependencies": { "@types/mocha": "^10", diff --git a/packages/ethicalMetrics/src/getInstance.ts b/packages/ethicalMetrics/src/getInstance.ts index 247c504c5..c76f81a62 100644 --- a/packages/ethicalMetrics/src/getInstance.ts +++ b/packages/ethicalMetrics/src/getInstance.ts @@ -8,11 +8,12 @@ export async function getInstance(): Promise<string> { await fetch(url.resolve(ethicalMetricsEndpoint, "/instance"), { method: "GET", headers: { - "Content-Type": "application/json", - }, + "Content-Type": "application/json" + } }) ) // TODO: do better type checking + // eslint-disable-next-line @typescript-eslint/no-explicit-any .json()) as any ).instance ); diff --git a/packages/ethicalMetrics/src/getIsRegistered.ts b/packages/ethicalMetrics/src/getIsRegistered.ts index 0b718df10..14090656e 100644 --- a/packages/ethicalMetrics/src/getIsRegistered.ts +++ b/packages/ethicalMetrics/src/getIsRegistered.ts @@ -1,21 +1,17 @@ import { ethicalMetricsEndpoint } from "./params.js"; import url from "url"; -export async function getIsRegistered({ - instance, -}: { - instance: string; -}): Promise<boolean> { +export async function getIsRegistered({ instance }: { instance: string }): Promise<boolean> { return ( ( await fetch(url.resolve(ethicalMetricsEndpoint, "/target-by-instance"), { method: "POST", body: JSON.stringify({ - instance, + instance }), headers: { - "Content-Type": "application/json", - }, + "Content-Type": "application/json" + } }) ).status === 200 ); diff --git a/packages/ethicalMetrics/src/params.ts b/packages/ethicalMetrics/src/params.ts index 0fd1805db..9c1572ba2 100644 --- a/packages/ethicalMetrics/src/params.ts +++ b/packages/ethicalMetrics/src/params.ts @@ -1,5 +1,3 @@ export const ethicalMetricsDnpName = "ethical-metrics.dnp.dappnode.eth"; -export const ethicalMetricsEndpoint = - "http://api-ui.ethical-metrics.dappnode:3000"; -export const ethicalMetricsTorServiceVolume = - "ethical-metricsdnpdappnodeeth_tor-hidden-service"; +export const ethicalMetricsEndpoint = "http://api-ui.ethical-metrics.dappnode:3000"; +export const ethicalMetricsTorServiceVolume = "ethical-metricsdnpdappnodeeth_tor-hidden-service"; diff --git a/packages/ethicalMetrics/src/register.ts b/packages/ethicalMetrics/src/register.ts index 6ba27b809..ea7fe4d7c 100644 --- a/packages/ethicalMetrics/src/register.ts +++ b/packages/ethicalMetrics/src/register.ts @@ -6,7 +6,7 @@ import { ethicalMetricsEndpoint } from "./params.js"; */ export async function register({ mail, - tgChannelId, + tgChannelId }: { mail: string | null; tgChannelId: string | null; @@ -17,16 +17,13 @@ export async function register({ if (mail) body["mail"] = mail; if (tgChannelId) body["tgChannelId"] = tgChannelId; - const response = await fetch( - url.resolve(ethicalMetricsEndpoint, "/targets"), - { - method: "POST", - body: JSON.stringify(body), - headers: { - "Content-Type": "application/json", - }, + const response = await fetch(url.resolve(ethicalMetricsEndpoint, "/targets"), { + method: "POST", + body: JSON.stringify(body), + headers: { + "Content-Type": "application/json" } - ); + }); if (response.status === 200) return; diff --git a/packages/ethicalMetrics/src/unregister.ts b/packages/ethicalMetrics/src/unregister.ts index 2bc798db2..203dc6adb 100644 --- a/packages/ethicalMetrics/src/unregister.ts +++ b/packages/ethicalMetrics/src/unregister.ts @@ -5,15 +5,12 @@ import url from "url"; * Unregister the instance in the Ethical Metrics server */ export async function unregister(): Promise<void> { - const response = await fetch( - url.resolve(ethicalMetricsEndpoint, "/targets"), - { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, + const response = await fetch(url.resolve(ethicalMetricsEndpoint, "/targets"), { + method: "DELETE", + headers: { + "Content-Type": "application/json" } - ); + }); if (response.status === 200) return; diff --git a/packages/eventBus/.eslintignore b/packages/eventBus/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/eventBus/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/eventBus/.eslintrc.cjs b/packages/eventBus/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/eventBus/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/eventBus/package.json b/packages/eventBus/package.json index 86ccb1caa..0fa5ed55d 100644 --- a/packages/eventBus/package.json +++ b/packages/eventBus/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/types": "workspace:^0.1.0", diff --git a/packages/eventBus/src/eventBus.ts b/packages/eventBus/src/eventBus.ts index 1fbe6eec8..fe66c34ab 100644 --- a/packages/eventBus/src/eventBus.ts +++ b/packages/eventBus/src/eventBus.ts @@ -6,7 +6,7 @@ import { ProgressLog, UserActionLog, PackageNotification, - DirectoryItem, + DirectoryItem } from "@dappnode/types"; interface EventTypes { @@ -54,18 +54,14 @@ const eventBusData: { [P in keyof EventTypes]: Record<string, never> } = { runEthClientInstaller: {}, runEthicalMetricsInstaller: {}, runNatRenewal: {}, - runStakerCacheUpdate: {}, + runStakerCacheUpdate: {} }; const eventEmitter = new EventEmitter(); type GetEventBus<T> = { [P in keyof T]: { - on: ( - listener: T[P] extends void - ? () => void | Promise<void> - : (arg: T[P]) => void | Promise<void> - ) => void; + on: (listener: T[P] extends void ? () => void | Promise<void> : (arg: T[P]) => void | Promise<void>) => void; emit: T[P] extends void ? () => void : (arg: T[P]) => void; }; }; @@ -87,6 +83,7 @@ export const eventBus: EventBus = mapValues(eventBusData, (_, eventName) => ({ */ try { await listener(...args); + // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { // Do not use logger module to avoud cirucular dependencies /** logs.error( @@ -99,5 +96,5 @@ export const eventBus: EventBus = mapValues(eventBusData, (_, eventName) => ({ emit: (...args: EventArg[]): void => { eventEmitter.emit(eventName, ...args); - }, + } })); diff --git a/packages/hostScriptsServices/.eslintignore b/packages/hostScriptsServices/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/hostScriptsServices/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/hostScriptsServices/.eslintrc.cjs b/packages/hostScriptsServices/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/hostScriptsServices/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/hostScriptsServices/package.json b/packages/hostScriptsServices/package.json index 75a42346f..151102e65 100644 --- a/packages/hostScriptsServices/package.json +++ b/packages/hostScriptsServices/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/logger": "workspace:^0.1.0", diff --git a/packages/hostScriptsServices/src/copyOnHost.ts b/packages/hostScriptsServices/src/copyOnHost.ts index 847bd9df6..31fcb2b08 100644 --- a/packages/hostScriptsServices/src/copyOnHost.ts +++ b/packages/hostScriptsServices/src/copyOnHost.ts @@ -12,7 +12,7 @@ import { logs } from "@dappnode/logger"; */ export async function copyOnHost({ hostDir, - hostDirSource, + hostDirSource }: { hostDir: string; hostDirSource: string; diff --git a/packages/hostScriptsServices/src/hostScripts/copyHostScripts.ts b/packages/hostScriptsServices/src/hostScripts/copyHostScripts.ts index af6c501f5..36dabd66a 100644 --- a/packages/hostScriptsServices/src/hostScripts/copyHostScripts.ts +++ b/packages/hostScriptsServices/src/hostScripts/copyHostScripts.ts @@ -14,6 +14,6 @@ const hostScriptsDirSource = params.HOST_SCRIPTS_SOURCE_DIR; export async function copyHostScripts(): Promise<void> { await copyOnHost({ hostDir: hostScriptsDir, - hostDirSource: hostScriptsDirSource, + hostDirSource: hostScriptsDirSource }); } diff --git a/packages/hostScriptsServices/src/hostScripts/runScripts.ts b/packages/hostScriptsServices/src/hostScripts/runScripts.ts index d668dfa60..65fdf92f7 100644 --- a/packages/hostScriptsServices/src/hostScripts/runScripts.ts +++ b/packages/hostScriptsServices/src/hostScripts/runScripts.ts @@ -23,13 +23,9 @@ type ScriptName = * Run a script for the hostScripts folder * @param scriptName "detect_fs.sh" */ -export async function runScript( - scriptName: ScriptName, - args = "" -): Promise<string> { +export async function runScript(scriptName: ScriptName, args = ""): Promise<string> { const scriptPath = path.resolve(hostScriptsDir, scriptName); - if (!fs.existsSync(scriptPath)) - throw Error(`Host script ${scriptName} not found`); + if (!fs.existsSync(scriptPath)) throw Error(`Host script ${scriptName} not found`); const scriptPathFromHost = path.resolve(hostScriptsDirFromHost, scriptName); return await shellHost(`/bin/bash ${scriptPathFromHost} ${args}`); diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/avahiDaemon.ts b/packages/hostScriptsServices/src/hostScripts/scripts/avahiDaemon.ts index 9ce6f94a1..30c82a1b0 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/avahiDaemon.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/avahiDaemon.ts @@ -35,7 +35,7 @@ export const getAvahiDaemonStatus = memoize( return { isAvahiRunning: status.isAvahiRunning === "true", isAvahiEnabled: status.isAvahiEnabled === "true", - avahiResolves: status.avahiResolves === "true", + avahiResolves: status.avahiResolves === "true" }; }, // Prevent running this script more than once diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/dockerUpgradeCheck.ts b/packages/hostScriptsServices/src/hostScripts/scripts/dockerUpgradeCheck.ts index 99017875c..325ad1b99 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/dockerUpgradeCheck.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/dockerUpgradeCheck.ts @@ -8,9 +8,7 @@ export async function dockerUpgradeCheck(): Promise<DockerUpgradeRequirements> { return { dockerHostVersion: requirementsParsed.dockerHostVersion, dockerLatestVersion: requirementsParsed.dockerLatestVersion || undefined, // check if dockerLatestVersion is empty string and set it to undefined if so - isDockerInstalledThroughApt: - requirementsParsed.isDockerInstalledThroughApt === "true", // check if isDockerInstalledThroughApt is a string and set it to boolean if so - isDockerInUnattendedUpgrades: - requirementsParsed.isDockerInUnattendedUpgrades === "true", // check if isDockerInUnattendedUpgrades is a string and set it to boolean if so + isDockerInstalledThroughApt: requirementsParsed.isDockerInstalledThroughApt === "true", // check if isDockerInstalledThroughApt is a string and set it to boolean if so + isDockerInUnattendedUpgrades: requirementsParsed.isDockerInUnattendedUpgrades === "true" // check if isDockerInUnattendedUpgrades is a string and set it to boolean if so }; } diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/hostInfo.ts b/packages/hostScriptsServices/src/hostScripts/scripts/hostInfo.ts index a785354af..89d5e66c6 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/hostInfo.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/hostInfo.ts @@ -28,7 +28,7 @@ export const getHostInfoMemoized = memoize( os: info.os.toLowerCase().trim(), versionCodename: info.versionCodename.toLowerCase().trim(), architecture: info.architecture.toLowerCase().trim(), - kernel: info.kernel.toLowerCase().trim(), + kernel: info.kernel.toLowerCase().trim() }; }, diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/lvm.ts b/packages/hostScriptsServices/src/hostScripts/scripts/lvm.ts index 34d9406dc..7d5d1d9a8 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/lvm.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/lvm.ts @@ -6,7 +6,7 @@ import { HostVolumeGroup, HostVolumeGroupReport, HostLogicalVolume, - HostLogicalVolumeReport, + HostLogicalVolumeReport } from "@dappnode/types"; /** @@ -27,8 +27,7 @@ export const getHostHardDisks = memoize( export const getHostVolumeGroups = memoize( async function (): Promise<HostVolumeGroup[]> { const volumeGroupsInfo = await runScript("lvm.sh", "-- --get-vg"); - const volumeGroupReport: HostVolumeGroupReport = - JSON.parse(volumeGroupsInfo); + const volumeGroupReport: HostVolumeGroupReport = JSON.parse(volumeGroupsInfo); const volumeGroups = volumeGroupReport.report[0].vg; return volumeGroups; }, @@ -42,8 +41,7 @@ export const getHostVolumeGroups = memoize( export const getHostLogicalVolumes = memoize( async function (): Promise<HostLogicalVolume[]> { const logicalVolumeInfo = await runScript("lvm.sh", "-- --get-lv"); - const logicalVolumeReport: HostLogicalVolumeReport = - JSON.parse(logicalVolumeInfo); + const logicalVolumeReport: HostLogicalVolumeReport = JSON.parse(logicalVolumeInfo); const logicalVolumes = logicalVolumeReport.report[0].lv; return logicalVolumes; }, @@ -54,15 +52,8 @@ export const getHostLogicalVolumes = memoize( * Extends host disk space */ export const extendHostDiskSpace = memoize( - async function ( - disk: string, - volumeGroup: string, - logicalVolume: string - ): Promise<string> { - return await runScript( - "lvm.sh", - `-- --extend ${disk} ${volumeGroup} ${logicalVolume}` - ); + async function (disk: string, volumeGroup: string, logicalVolume: string): Promise<string> { + return await runScript("lvm.sh", `-- --extend ${disk} ${volumeGroup} ${logicalVolume}`); }, { promise: true, maxAge: 2000 } ); diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/migrateVolume.ts b/packages/hostScriptsServices/src/hostScripts/scripts/migrateVolume.ts index 8f784929c..5b1a0a050 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/migrateVolume.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/migrateVolume.ts @@ -5,10 +5,7 @@ import { runScript } from "../runScripts.js"; * @param fromVolumeName "dncore_ethchaindnpdappnodeeth_geth" * @param toVolumeName "gethdnpdappnodeeth_geth" */ -export async function migrateVolume( - fromVolumeName: string, - toVolumeName: string -): Promise<void> { +export async function migrateVolume(fromVolumeName: string, toVolumeName: string): Promise<void> { for (const [id, name] of Object.entries({ fromVolumeName, toVolumeName })) { // Make sure a wrong path is not created, and prevent "../../" paths if (!name) throw new Error(`${id} must not be empty`); diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/mountpoints.ts b/packages/hostScriptsServices/src/hostScripts/scripts/mountpoints.ts index e46e0e48a..875e3dafd 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/mountpoints.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/mountpoints.ts @@ -37,9 +37,7 @@ export const detectMountpoints = memoize( }[] = JSON.parse(rawMountpointsJson); if (!Array.isArray(mountpointsDaraRaw)) - throw Error( - `detect_fs script must return an array but returned: ${rawMountpointsJson}` - ); + throw Error(`detect_fs script must return an array but returned: ${rawMountpointsJson}`); const mountpoints = mountpointsDaraRaw.map( (dataRaw): MountpointData => ({ @@ -49,7 +47,7 @@ export const detectMountpoints = memoize( total: parseInt(dataRaw.total), free: parseInt(dataRaw.free), vendor: dataRaw.vendor, - model: dataRaw.model, + model: dataRaw.model }) ); diff --git a/packages/hostScriptsServices/src/hostScripts/scripts/rebootRequired.ts b/packages/hostScriptsServices/src/hostScripts/scripts/rebootRequired.ts index 4e0faa268..c137cf217 100644 --- a/packages/hostScriptsServices/src/hostScripts/scripts/rebootRequired.ts +++ b/packages/hostScriptsServices/src/hostScripts/scripts/rebootRequired.ts @@ -12,11 +12,11 @@ export const getRebootRequiredMemoized = memoize( const infoParsed = JSON.parse(response); return { rebootRequired: infoParsed.rebootRequired, - pkgs: infoParsed.pkgs, + pkgs: infoParsed.pkgs }; }, { promise: true, - maxAge: 60 * 1000 * 5, // 5 minutes + maxAge: 60 * 1000 * 5 // 5 minutes } ); diff --git a/packages/hostScriptsServices/src/hostServices/copyHostServices.ts b/packages/hostScriptsServices/src/hostServices/copyHostServices.ts index af2fcc57b..2a80801ff 100644 --- a/packages/hostScriptsServices/src/hostServices/copyHostServices.ts +++ b/packages/hostScriptsServices/src/hostServices/copyHostServices.ts @@ -14,6 +14,6 @@ const hostServicesDirSource = params.HOST_SERVICES_SOURCE_DIR; export async function copyHostServices(): Promise<void> { await copyOnHost({ hostDir: hostServicesDir, - hostDirSource: hostServicesDirSource, + hostDirSource: hostServicesDirSource }); } diff --git a/packages/hostScriptsServices/src/hostServices/runService.ts b/packages/hostScriptsServices/src/hostServices/runService.ts index 73b268b20..c2876e1bf 100644 --- a/packages/hostScriptsServices/src/hostServices/runService.ts +++ b/packages/hostScriptsServices/src/hostServices/runService.ts @@ -19,19 +19,11 @@ export type ServiceName = * @param serviceName "update-docker-engine.service" * sytemd service info: https://www.freedesktop.org/software/systemd/man/systemd.service.html */ -export async function runService( - serviceName: ServiceName, - reload: boolean, - args = "" -): Promise<string> { - const servicePath = path.resolve( - params.HOST_SERVICES_SOURCE_DIR, - serviceName - ); +export async function runService(serviceName: ServiceName, reload: boolean, args = ""): Promise<string> { + const servicePath = path.resolve(params.HOST_SERVICES_SOURCE_DIR, serviceName); try { // Check if service exists - if (!fs.existsSync(servicePath)) - throw Error(`Host service ${serviceName} not found`); + if (!fs.existsSync(servicePath)) throw Error(`Host service ${serviceName} not found`); // Copy service into shared volume await copyHostService(serviceName); diff --git a/packages/hostScriptsServices/src/hostServices/services/updateUpgradeHost.ts b/packages/hostScriptsServices/src/hostServices/services/updateUpgradeHost.ts index 8eaa947f6..45aa4d4fe 100644 --- a/packages/hostScriptsServices/src/hostServices/services/updateUpgradeHost.ts +++ b/packages/hostScriptsServices/src/hostServices/services/updateUpgradeHost.ts @@ -11,7 +11,7 @@ import { runService } from "../runService.js"; * - When running this host service containers will restart and connection with the dappnode will be lost for a while */ export const updateUpgradeHost = memoize( - async function(): Promise<string> { + async function (): Promise<string> { return await runService("update-upgrade-host.service", false); }, // Prevent running this service more than once diff --git a/packages/hostScriptsServices/src/hostTimers/copyHostTimers.ts b/packages/hostScriptsServices/src/hostTimers/copyHostTimers.ts index 561b72b36..58471a201 100644 --- a/packages/hostScriptsServices/src/hostTimers/copyHostTimers.ts +++ b/packages/hostScriptsServices/src/hostTimers/copyHostTimers.ts @@ -14,6 +14,6 @@ const hostTimersDirSource = params.HOST_TIMERS_SOURCE_DIR; export async function copyHostTimers(): Promise<void> { await copyOnHost({ hostDir: hostTimersDir, - hostDirSource: hostTimersDirSource, + hostDirSource: hostTimersDirSource }); } diff --git a/packages/hostScriptsServices/src/hostTimers/runTimer.ts b/packages/hostScriptsServices/src/hostTimers/runTimer.ts index 781397587..cc45f2fe7 100644 --- a/packages/hostScriptsServices/src/hostTimers/runTimer.ts +++ b/packages/hostScriptsServices/src/hostTimers/runTimer.ts @@ -26,8 +26,7 @@ export async function runTimer(timer: Timer): Promise<string> { const timerPath = path.resolve(params.HOST_TIMERS_SOURCE_DIR, timer.name); try { // Check if timer exists - if (!fs.existsSync(timerPath)) - throw Error(`Host timer ${timer.name} not found`); + if (!fs.existsSync(timerPath)) throw Error(`Host timer ${timer.name} not found`); // Copy timer and service into shared volume await copyHostService(timer.dependantService); diff --git a/packages/hostScriptsServices/src/hostTimers/timers/checkDockerNetwork.ts b/packages/hostScriptsServices/src/hostTimers/timers/checkDockerNetwork.ts index 74f726ecd..d67bb8f53 100644 --- a/packages/hostScriptsServices/src/hostTimers/timers/checkDockerNetwork.ts +++ b/packages/hostScriptsServices/src/hostTimers/timers/checkDockerNetwork.ts @@ -7,7 +7,7 @@ import { runTimer } from "../runTimer.js"; export async function checkDockerNetwork(): Promise<void> { const response = await runTimer({ name: "check-docker-network.timer", - dependantService: "check-docker-network.service", + dependantService: "check-docker-network.service" }); logs.info(`Successfully started checker docker network service ${response}`); } diff --git a/packages/hostScriptsServices/src/hostTimers/timers/recreateDappnode.ts b/packages/hostScriptsServices/src/hostTimers/timers/recreateDappnode.ts index c8bb873a8..ed80fe8a0 100644 --- a/packages/hostScriptsServices/src/hostTimers/timers/recreateDappnode.ts +++ b/packages/hostScriptsServices/src/hostTimers/timers/recreateDappnode.ts @@ -7,9 +7,7 @@ import { runTimer } from "../runTimer.js"; export async function recreateDappnode(): Promise<void> { const response = await runTimer({ name: "recreate-dappnode.timer", - dependantService: "recreate-dappnode.service", + dependantService: "recreate-dappnode.service" }); - logs.info( - `Successfully started recreate dappnode to latest service ${response}` - ); + logs.info(`Successfully started recreate dappnode to latest service ${response}`); } diff --git a/packages/hostScriptsServices/test/unit/hostScripts.test.int.ts b/packages/hostScriptsServices/test/unit/hostScripts.test.int.ts index 27201342f..9cbc41ccc 100644 --- a/packages/hostScriptsServices/test/unit/hostScripts.test.int.ts +++ b/packages/hostScriptsServices/test/unit/hostScripts.test.int.ts @@ -6,9 +6,7 @@ const hostScriptsPath = process.cwd() + "/hostScripts"; describe.skip("Host scripts", () => { it("Should fetch host info", async () => { - const hostInfo = await shell( - `sudo bash ${hostScriptsPath}/collect_host_info.sh` - ); + const hostInfo = await shell(`sudo bash ${hostScriptsPath}/collect_host_info.sh`); expect(hostInfo).to.be.ok; }); @@ -21,7 +19,7 @@ describe.skip("Host scripts", () => { expect(hostUpdate).to.be.ok; }); */ - after("Clean logs", async function() { + after("Clean logs", async function () { await shell(`sudo rm -rf /usr/src/dappnode/logs`); }); }); diff --git a/packages/httpsPortal/.eslintignore b/packages/httpsPortal/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/httpsPortal/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/httpsPortal/.eslintrc.cjs b/packages/httpsPortal/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/httpsPortal/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/httpsPortal/package.json b/packages/httpsPortal/package.json index 755168751..fdf624fe2 100644 --- a/packages/httpsPortal/package.json +++ b/packages/httpsPortal/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/dockerapi": "workspace:^0.1.0", diff --git a/packages/httpsPortal/src/apiClient.ts b/packages/httpsPortal/src/apiClient.ts index ec2e04419..6add8aeca 100644 --- a/packages/httpsPortal/src/apiClient.ts +++ b/packages/httpsPortal/src/apiClient.ts @@ -33,9 +33,9 @@ export const httpsPortalResponseSchema = { required: ["from", "to"], properties: { from: { type: "string" }, - to: { type: "string" }, - }, - }, + to: { type: "string" } + } + } }; export class HttpsPortalApiClient { @@ -65,7 +65,7 @@ export class HttpsPortalApiClient { const search = querystring.encode({ from: fromSubdomain, to: toHost, - auth: auth && (await this.getHtpasswdEntry(auth)), + auth: auth && (await this.getHtpasswdEntry(auth)) }); await this.get(urlJoin(this.baseUrl, `/add?${search}`)); } @@ -80,7 +80,7 @@ export class HttpsPortalApiClient { async remove({ fromSubdomain, toHost }: HttpPortalEntry): Promise<void> { const search = querystring.encode({ from: fromSubdomain, - to: toHost, + to: toHost }); await this.get(urlJoin(this.baseUrl, `/remove?${search}`)); } @@ -92,9 +92,9 @@ export class HttpsPortalApiClient { * [{"from":"validator-prysm-pyrmont.1ba499fcc3aff025.dyndns.dappnode.io","to":"validator-prysm-pyrmont"}] */ async list(): Promise<HttpPortalEntry[]> { - const entries = await this.get< - { from: string; to: string; auth?: string }[] - >(urlJoin(this.baseUrl, `/?format=json`)); + const entries = await this.get<{ from: string; to: string; auth?: string }[]>( + urlJoin(this.baseUrl, `/?format=json`) + ); if (!ajv.validate(httpsPortalResponseSchema, entries)) { throw Error(`Invalid response: ${JSON.stringify(ajv.errors, null, 2)}`); @@ -106,9 +106,9 @@ export class HttpsPortalApiClient { auth: entry.auth ? { username: entry.auth.split(":")[0], - password: entry.auth.split(":")[1], + password: entry.auth.split(":")[1] } - : undefined, + : undefined })); } @@ -140,13 +140,7 @@ export class HttpsPortalApiClient { * @param {string} params.password - The password. * @returns {Promise<string>}`exampleUser:{SSHA}5ZCbZYs5Pn5T6Z9wXV5YWZRp+mgc0e3cLQFklHQbU3W5bg==`. */ - private async getHtpasswdEntry({ - username, - password, - }: { - username: string; - password: string; - }): Promise<string> { + private async getHtpasswdEntry({ username, password }: { username: string; password: string }): Promise<string> { const saltLength = 16; // Length of the salt in bytes // Generate a random salt diff --git a/packages/httpsPortal/src/exposable/index.ts b/packages/httpsPortal/src/exposable/index.ts index ca3324d36..763a57d32 100644 --- a/packages/httpsPortal/src/exposable/index.ts +++ b/packages/httpsPortal/src/exposable/index.ts @@ -9,19 +9,15 @@ import { parseExposableServiceManifest } from "./parseExposable.js"; * Cache results for 1 hour, 50 max by dnpName + version. Prevent reading from disk too often */ const getExposableServicesByDnpMemo = memoizee( - function getExposableServicesByDnp( - dnp: InstalledPackageData - ): ExposableServiceInfo[] | null { + function getExposableServicesByDnp(dnp: InstalledPackageData): ExposableServiceInfo[] | null { // Read disk const manifest = readManifestIfExists(dnp); - return manifest?.exposable - ? parseExposableServiceManifest(dnp, manifest.exposable) - : null; + return manifest?.exposable ? parseExposableServiceManifest(dnp, manifest.exposable) : null; }, { max: 50, maxAge: 60 * 60 * 1000, - normalizer: ([dnp]) => dnp.dnpName + dnp.version, + normalizer: ([dnp]) => dnp.dnpName + dnp.version } ); @@ -31,10 +27,7 @@ export async function getExposableServices(): Promise<ExposableServiceInfo[]> { const exposable: ExposableServiceInfo[] = []; for (const dnp of dnps) { - const exposableByDnpArr = - getExposableServicesByDnpMemo(dnp) || - exposablePredefined[dnp.dnpName] || - []; + const exposableByDnpArr = getExposableServicesByDnpMemo(dnp) || exposablePredefined[dnp.dnpName] || []; for (const item of exposableByDnpArr) exposable.push(item); } diff --git a/packages/httpsPortal/src/exposable/parseExposable.ts b/packages/httpsPortal/src/exposable/parseExposable.ts index 493935208..087ee11aa 100644 --- a/packages/httpsPortal/src/exposable/parseExposable.ts +++ b/packages/httpsPortal/src/exposable/parseExposable.ts @@ -1,8 +1,4 @@ -import { - ExposableServiceInfo, - ExposableServiceManifestInfo, - InstalledPackageData, -} from "@dappnode/types"; +import { ExposableServiceInfo, ExposableServiceManifestInfo, InstalledPackageData } from "@dappnode/types"; import { getPublicSubdomain, stripBadDomainChars } from "../domains.js"; /** @@ -26,7 +22,7 @@ export function parseExposableServiceManifest( const rootSubdomain = stripBadDomainChars(dnp.dnpName.split(".")[0]); const defaultFromSubdomain = getPublicSubdomain({ dnpName: dnp.dnpName, - serviceName, + serviceName }); if (info.fromSubdomain && !rootSubdomain.includes(info.fromSubdomain)) { @@ -40,7 +36,7 @@ export function parseExposableServiceManifest( fromSubdomain: info.fromSubdomain || defaultFromSubdomain, dnpName: dnp.dnpName, serviceName, - port: info.port, + port: info.port }); } } diff --git a/packages/httpsPortal/src/exposable/predefined.ts b/packages/httpsPortal/src/exposable/predefined.ts index 0dcbf40be..edc9ff1f0 100644 --- a/packages/httpsPortal/src/exposable/predefined.ts +++ b/packages/httpsPortal/src/exposable/predefined.ts @@ -10,7 +10,7 @@ export const exposablePredefined: { serviceName: "geth.dnp.dappnode.eth", port: 8545, name: "Geth JSON RPC", - description: "JSON RPC endpoint for Geth Ethereum mainnet", + description: "JSON RPC endpoint for Geth Ethereum mainnet" }, { fromSubdomain: "geth-ws", @@ -18,8 +18,8 @@ export const exposablePredefined: { serviceName: "geth.dnp.dappnode.eth", port: 8546, name: "Geth JSON RPC (WS)", - description: "WebSockets endpoint for Geth Ethereum mainnet", - }, + description: "WebSockets endpoint for Geth Ethereum mainnet" + } ], "goerli-geth.dnp.dappnode.eth": [ { @@ -28,7 +28,7 @@ export const exposablePredefined: { serviceName: "goerli-geth.dnp.dappnode.eth", port: 8545, name: "Goerli Geth JSON RPC", - description: "JSON RPC endpoint for Goerli Ethereum network", + description: "JSON RPC endpoint for Goerli Ethereum network" }, { fromSubdomain: "goerli-geth-ws", @@ -36,8 +36,8 @@ export const exposablePredefined: { serviceName: "goerli-geth.dnp.dappnode.eth", port: 8546, name: "Goerli Geth JSON RPC (WS)", - description: "WebSockets endpoint for Goerli Ethereum network", - }, + description: "WebSockets endpoint for Goerli Ethereum network" + } ], "kovan.dnp.dappnode.eth": [ { @@ -46,7 +46,7 @@ export const exposablePredefined: { serviceName: "kovan.dnp.dappnode.eth", port: 8545, name: "Kovan JSON RPC", - description: "JSON RPC endpoint for Kovan Ethereum network", + description: "JSON RPC endpoint for Kovan Ethereum network" }, { fromSubdomain: "kovan-ws", @@ -54,8 +54,8 @@ export const exposablePredefined: { serviceName: "kovan.dnp.dappnode.eth", port: 8546, name: "Kovan JSON RPC (WS)", - description: "WebSockets endpoint for Kovan Ethereum network", - }, + description: "WebSockets endpoint for Kovan Ethereum network" + } ], "nethermind.public.dappnode.eth": [ { @@ -64,7 +64,7 @@ export const exposablePredefined: { serviceName: "nethermind.public.dappnode.eth", port: 8545, name: "Nethermind JSON RPC", - description: "JSON RPC endpoint for Nethermind Ethereum mainnet", + description: "JSON RPC endpoint for Nethermind Ethereum mainnet" }, { fromSubdomain: "nethermind-ws", @@ -72,8 +72,8 @@ export const exposablePredefined: { serviceName: "nethermind.public.dappnode.eth", port: 8546, name: "Nethermind JSON RPC (WS)", - description: "WebSockets endpoint for Nethermind Ethereum mainnet", - }, + description: "WebSockets endpoint for Nethermind Ethereum mainnet" + } ], "rinkeby.dnp.dappnode.eth": [ { @@ -82,7 +82,7 @@ export const exposablePredefined: { serviceName: "rinkeby.dnp.dappnode.eth", port: 8545, name: "Rinkeby JSON RPC", - description: "JSON RPC endpoint for Rinkeby Ethereum network", + description: "JSON RPC endpoint for Rinkeby Ethereum network" }, { fromSubdomain: "rinkeby-ws", @@ -90,8 +90,8 @@ export const exposablePredefined: { serviceName: "rinkeby.dnp.dappnode.eth", port: 8546, name: "Rinkeby JSON RPC (WS)", - description: "WebSockets endpoint for Rinkeby Ethereum network", - }, + description: "WebSockets endpoint for Rinkeby Ethereum network" + } ], "ropsten.dnp.dappnode.eth": [ { @@ -100,7 +100,7 @@ export const exposablePredefined: { serviceName: "ropsten.dnp.dappnode.eth", port: 8545, name: "Ropsten JSON RPC", - description: "JSON RPC endpoint for Ropsten Ethereum network", + description: "JSON RPC endpoint for Ropsten Ethereum network" }, { fromSubdomain: "ropsten-ws", @@ -108,8 +108,8 @@ export const exposablePredefined: { serviceName: "ropsten.dnp.dappnode.eth", port: 8546, name: "Ropsten JSON RPC (WS)", - description: "WebSockets endpoint for Ropsten Ethereum network", - }, + description: "WebSockets endpoint for Ropsten Ethereum network" + } ], "avalanche.public.dappnode.eth": [ { @@ -118,8 +118,8 @@ export const exposablePredefined: { serviceName: "wallet", port: 80, name: "Avalanche wallet", - description: "Avalanche wallet UI", - }, + description: "Avalanche wallet UI" + } ], "bee.dnp.dappnode.eth": [ { @@ -128,8 +128,8 @@ export const exposablePredefined: { serviceName: "bee.dnp.dappnode.eth", port: 1633, name: "Bee JSON RPC", - description: "JSON RPC endpoint for Bee", - }, + description: "JSON RPC endpoint for Bee" + } ], "bitcoin.dnp.dappnode.eth": [ { @@ -138,8 +138,8 @@ export const exposablePredefined: { serviceName: "bitcoin.dnp.dappnode.eth", port: 8332, name: "Bitcoin JSON RPC", - description: "JSON RPC endpoint for Bitcoin", - }, + description: "JSON RPC endpoint for Bitcoin" + } ], "monero.dnp.dappnode.eth": [ { @@ -148,8 +148,8 @@ export const exposablePredefined: { serviceName: "monero.dnp.dappnode.eth", port: 18081, name: "Monero JSON RPC", - description: "JSON RPC endpoint for Monero", - }, + description: "JSON RPC endpoint for Monero" + } ], "zcash.public.dappnode.eth": [ { @@ -158,8 +158,8 @@ export const exposablePredefined: { serviceName: "zcash.public.dappnode.eth", port: 8232, name: "Zcash JSON RPC", - description: "JSON RPC endpoint for Zcash", - }, + description: "JSON RPC endpoint for Zcash" + } ], "owncloud.dnp.dappnode.eth": [ { @@ -168,8 +168,8 @@ export const exposablePredefined: { serviceName: "owncloud", port: 80, name: "Owncloud UI", - description: "Owncloud UI", - }, + description: "Owncloud UI" + } ], "trustlines.dnp.dappnode.eth": [ { @@ -178,7 +178,7 @@ export const exposablePredefined: { serviceName: "node", port: 8545, name: "Truslines JSON RPC", - description: "JSON RPC endpoint for Truslines network", + description: "JSON RPC endpoint for Truslines network" }, { fromSubdomain: "trustlines-ws", @@ -186,8 +186,8 @@ export const exposablePredefined: { serviceName: "node", port: 8546, name: "Truslines JSON RPC (WS)", - description: "WebSockets endpoint for Truslines network", - }, + description: "WebSockets endpoint for Truslines network" + } ], "turbo-geth.dnp.dappnode.eth": [ { @@ -196,7 +196,7 @@ export const exposablePredefined: { serviceName: "rpcdaemon", port: 8545, name: "Turbo-Geth JSON RPC", - description: "JSON RPC endpoint for Turbo-Geth Ethereum mainnet", + description: "JSON RPC endpoint for Turbo-Geth Ethereum mainnet" }, { fromSubdomain: "turbo-geth-ws", @@ -204,7 +204,7 @@ export const exposablePredefined: { serviceName: "rpcdaemon", port: 8546, name: "Turbo-Geth JSON RPC (WS)", - description: "WebSockets endpoint for Turbo-Geth Ethereum mainnet", - }, - ], + description: "WebSockets endpoint for Turbo-Geth Ethereum mainnet" + } + ] }; diff --git a/packages/httpsPortal/src/httpsPortal.ts b/packages/httpsPortal/src/httpsPortal.ts index 6e09777f4..952e436e6 100644 --- a/packages/httpsPortal/src/httpsPortal.ts +++ b/packages/httpsPortal/src/httpsPortal.ts @@ -3,17 +3,12 @@ import { dockerListNetworks, dockerNetworkConnect, dockerNetworkDisconnect, - listPackageNoThrow, + listPackageNoThrow } from "@dappnode/dockerapi"; import { listPackageContainers } from "@dappnode/dockerapi"; import { params } from "@dappnode/params"; import { getExternalNetworkAlias } from "./domains.js"; -import { - PackageContainer, - HttpsPortalMapping, - InstallPackageData, - InstalledPackageData, -} from "@dappnode/types"; +import { PackageContainer, HttpsPortalMapping, InstallPackageData, InstalledPackageData } from "@dappnode/types"; import { HttpsPortalApiClient } from "./apiClient.js"; import { ComposeEditor, ComposeFileEditor } from "@dappnode/dockercompose"; import { prettyDnpName } from "@dappnode/utils"; @@ -48,22 +43,17 @@ export class HttpsPortal { } // Ensure the HTTPs portal container is connected to `externalNetworkName` - const httpsPortalContainer = containers.find( - (c) => c.dnpName === params.HTTPS_PORTAL_DNPNAME - ); + const httpsPortalContainer = containers.find((c) => c.dnpName === params.HTTPS_PORTAL_DNPNAME); if (!httpsPortalContainer) throw Error(`HTTPs portal container not found`); if (!this.isConnected(httpsPortalContainer)) { - await dockerNetworkConnect( - externalNetworkName, - httpsPortalContainer.containerName - ); + await dockerNetworkConnect(externalNetworkName, httpsPortalContainer.containerName); } // Container joins external network with a designated alias (immediate) // Check first is it's already connected, or dockerNetworkConnect throws if (!this.isConnected(container)) { await dockerNetworkConnect(externalNetworkName, container.containerName, { - Aliases: aliases, + Aliases: aliases }); } @@ -71,24 +61,19 @@ export class HttpsPortal { await this.httpsPortalApiClient.add({ fromSubdomain: mapping.fromSubdomain, toHost: `${externalNetworkAlias}:${mapping.port}`, - auth: mapping.auth, + auth: mapping.auth }); // Edit compose to persist the setting this.addNetworkAliasCompose(container, externalNetworkName, aliases); // Check whether DNP_HTTPS compose has external network persisted - const httpsComposePath = ComposeEditor.getComposePath( - params.HTTPS_PORTAL_DNPNAME, - true - ); + const httpsComposePath = ComposeEditor.getComposePath(params.HTTPS_PORTAL_DNPNAME, true); const editor = new ComposeEditor(ComposeEditor.readFrom(httpsComposePath)); if (editor.getComposeNetwork(externalNetworkName) === null) { const httpsExternalAlias = getExternalNetworkAlias(httpsPortalContainer); - this.addNetworkAliasCompose(httpsPortalContainer, externalNetworkName, [ - httpsExternalAlias, - ]); + this.addNetworkAliasCompose(httpsPortalContainer, externalNetworkName, [httpsExternalAlias]); } } @@ -105,34 +90,27 @@ export class HttpsPortal { // Call Http Portal API to remove the mapping await this.httpsPortalApiClient.remove({ fromSubdomain: mapping.fromSubdomain, - toHost: externalNetworkAlias, + toHost: externalNetworkAlias }); // If container still has mappings, don't disconnect from network const mappings = await this.getMappings(containers); const containerHasMappings = mappings.some( - (mapping) => - mapping.dnpName === container.dnpName && - mapping.serviceName === container.serviceName + (mapping) => mapping.dnpName === container.dnpName && mapping.serviceName === container.serviceName ); if (containerHasMappings) return; // Container leaves external network // Check first is it's connected, or dockerNetworkDisconnect throws if (this.isConnected(container)) { - await dockerNetworkDisconnect( - externalNetworkName, - container.containerName - ); + await dockerNetworkDisconnect(externalNetworkName, container.containerName); } // Edit compose to persist the setting this.removeNetworkAliasCompose(container, externalNetworkName); } - async getMappings( - containers?: PackageContainer[] - ): Promise<HttpsPortalMapping[]> { + async getMappings(containers?: PackageContainer[]): Promise<HttpsPortalMapping[]> { if (!(await this.isRunningHttps())) return []; if (!containers) containers = await listPackageContainers(); @@ -154,7 +132,7 @@ export class HttpsPortal { dnpName: container.dnpName, serviceName: container.serviceName, port: parseInt(port) || 80, - auth, + auth }); } } @@ -181,10 +159,7 @@ export class HttpsPortal { * - is HTTPS package * - any package with https portal mappings */ - async connectToPublicNetwork( - pkg: InstallPackageData, - externalNetworkName: string - ): Promise<void> { + async connectToPublicNetwork(pkg: InstallPackageData, externalNetworkName: string): Promise<void> { // if there is no https, checks aren't needed if (!(await this.isRunningHttps())) return; @@ -196,28 +171,21 @@ export class HttpsPortal { const containers = ( await listPackageNoThrow({ - dnpName: pkg.dnpName, + dnpName: pkg.dnpName }) )?.containers || []; if (containers.length === 0) return; for (const container of containers) { - if ( - pkg.dnpName === params.HTTPS_PORTAL_DNPNAME || - (await this.hasMapping(pkg.dnpName, container.serviceName)) - ) { + if (pkg.dnpName === params.HTTPS_PORTAL_DNPNAME || (await this.hasMapping(pkg.dnpName, container.serviceName))) { const alias = getExternalNetworkAlias({ serviceName: container.serviceName, - dnpName: pkg.dnpName, + dnpName: pkg.dnpName }); if (!container.networks.find((n) => n.name === externalNetworkName)) { - await dockerNetworkConnect( - externalNetworkName, - container.containerName, - { Aliases: [alias] } - ); + await dockerNetworkConnect(externalNetworkName, container.containerName, { Aliases: [alias] }); } } } @@ -226,10 +194,7 @@ export class HttpsPortal { /** * Expose default HTTPS ports on installation defined in the manifest - exposable */ - async exposeByDefaultHttpsPorts( - pkg: InstallPackageData, - log: Log - ): Promise<void> { + async exposeByDefaultHttpsPorts(pkg: InstallPackageData, log: Log): Promise<void> { const exposables = pkg.manifest.exposable; // Return if no exposable or not exposeByDefault @@ -237,9 +202,7 @@ export class HttpsPortal { // Requires that https package exists and it is running if (!(await this.isRunningHttps())) - throw Error( - `HTTPS package not running but required to expose HTTPS ports by default.` - ); + throw Error(`HTTPS package not running but required to expose HTTPS ports by default.`); const currentMappings = await this.getMappings(); const portMappinRollback: HttpsPortalMapping[] = []; @@ -249,54 +212,29 @@ export class HttpsPortal { const portalMapping: HttpsPortalMapping = { fromSubdomain: exposable.fromSubdomain || prettyDnpName(pkg.dnpName), // get dnpName by default dnpName: pkg.dnpName, - serviceName: - exposable.serviceName || Object.keys(pkg.compose.services)[0], // get first service name by default (docs: https://docs.dappnode.io/es/developers/manifest-reference/#servicename) - port: exposable.port, + serviceName: exposable.serviceName || Object.keys(pkg.compose.services)[0], // get first service name by default (docs: https://docs.dappnode.io/es/developers/manifest-reference/#servicename) + port: exposable.port }; - if ( - currentMappings.length > 0 && - currentMappings.includes(portalMapping) - ) - continue; + if (currentMappings.length > 0 && currentMappings.includes(portalMapping)) continue; try { // Expose default HTTPS ports - log( - pkg.dnpName, - `Exposing ${prettyDnpName(pkg.dnpName)}:${ - exposable.port - } to the external internet` - ); + log(pkg.dnpName, `Exposing ${prettyDnpName(pkg.dnpName)}:${exposable.port} to the external internet`); await this.addMapping(portalMapping); portMappinRollback.push(portalMapping); - log( - pkg.dnpName, - `Exposed ${prettyDnpName(pkg.dnpName)}:${ - exposable.port - } to the external internet` - ); + log(pkg.dnpName, `Exposed ${prettyDnpName(pkg.dnpName)}:${exposable.port} to the external internet`); } catch (e) { if (e.message.includes("External endpoint already exists")) { // Bypass error if already exposed: 400 Bad Request {"error":"External endpoint already exists"} - log( - pkg.dnpName, - `External endpoint already exists for ${prettyDnpName( - pkg.dnpName - )}:${exposable.port}` - ); + log(pkg.dnpName, `External endpoint already exists for ${prettyDnpName(pkg.dnpName)}:${exposable.port}`); } else { // Remove all mappings and throw error to trigger package install rollback e.message = `${e.message} Error exposing default HTTPS ports, removing mappings`; for (const mappingRollback of portMappinRollback) { await this.removeMapping(mappingRollback).catch((e) => { - log( - pkg.dnpName, - `Error removing mapping ${JSON.stringify(mappingRollback)}, ${ - e.message - }` - ); + log(pkg.dnpName, `Error removing mapping ${JSON.stringify(mappingRollback)}, ${e.message}`); }); } throw e; @@ -313,9 +251,7 @@ export class HttpsPortal { if (mapping.dnpName === pkg.dnpName) await this.removeMapping(mapping) // Bypass error to continue deleting mappings - .catch((e) => - logs.error(`Error removing https mapping of ${pkg.dnpName}`, e) - ); + .catch((e) => logs.error(`Error removing https mapping of ${pkg.dnpName}`, e)); } } @@ -325,14 +261,8 @@ export class HttpsPortal { ): Promise<PackageContainer> { if (!containers) containers = await listPackageContainers(); - const container = containers.find( - (c) => - c.dnpName === mapping.dnpName && c.serviceName === mapping.serviceName - ); - if (!container) - throw Error( - `No container found for ${mapping.dnpName} ${mapping.serviceName}` - ); + const container = containers.find((c) => c.dnpName === mapping.dnpName && c.serviceName === mapping.serviceName); + if (!container) throw Error(`No container found for ${mapping.dnpName} ${mapping.serviceName}`); return container; } @@ -346,7 +276,7 @@ export class HttpsPortal { */ private async isRunningHttps(): Promise<boolean> { const httpsPackage = await listPackageNoThrow({ - dnpName: params.HTTPS_PORTAL_DNPNAME, + dnpName: params.HTTPS_PORTAL_DNPNAME }); if (!httpsPackage) return false; @@ -355,21 +285,14 @@ export class HttpsPortal { return httpsPackage.containers.every((container) => container.running); } - private removeNetworkAliasCompose( - container: PackageContainer, - networkName: string - ): void { + private removeNetworkAliasCompose(container: PackageContainer, networkName: string): void { const compose = new ComposeFileEditor(container.dnpName, container.isCore); const composeService = compose.services()[container.serviceName]; composeService.removeNetwork(networkName); compose.write(); } - private addNetworkAliasCompose( - container: PackageContainer, - networkName: string, - aliases: string[] - ): void { + private addNetworkAliasCompose(container: PackageContainer, networkName: string, aliases: string[]): void { const compose = new ComposeFileEditor(container.dnpName, container.isCore); const composeService = compose.services()[container.serviceName]; composeService.addNetwork(networkName, { aliases }); diff --git a/packages/httpsPortal/src/index.ts b/packages/httpsPortal/src/index.ts index a55c7e714..5047b5a28 100644 --- a/packages/httpsPortal/src/index.ts +++ b/packages/httpsPortal/src/index.ts @@ -1,9 +1,7 @@ import { params } from "@dappnode/params"; import { HttpsPortal, HttpsPortalApiClient } from "./httpsPortal.js"; -const httpsPortalApiClient = new HttpsPortalApiClient( - params.HTTPS_PORTAL_API_URL -); +const httpsPortalApiClient = new HttpsPortalApiClient(params.HTTPS_PORTAL_API_URL); export const httpsPortal = new HttpsPortal(httpsPortalApiClient); export { getExposableServices } from "./exposable/index.js"; diff --git a/packages/httpsPortal/test/testUtils.ts b/packages/httpsPortal/test/testUtils.ts index 0be57abe0..5099a859e 100644 --- a/packages/httpsPortal/test/testUtils.ts +++ b/packages/httpsPortal/test/testUtils.ts @@ -25,7 +25,7 @@ export const mockContainer: PackageContainer = { defaultVolumes: [], dependencies: {}, origin: "", - avatarUrl: "", + avatarUrl: "" }; export const mockDnp: InstalledPackageData = { @@ -37,5 +37,5 @@ export const mockDnp: InstalledPackageData = { dependencies: {}, origin: "", avatarUrl: "", - containers: [mockContainer], + containers: [mockContainer] }; diff --git a/packages/httpsPortal/test/unit/exposable.test.ts b/packages/httpsPortal/test/unit/exposable.test.ts index b63d002d0..1b1383f0a 100644 --- a/packages/httpsPortal/test/unit/exposable.test.ts +++ b/packages/httpsPortal/test/unit/exposable.test.ts @@ -1,10 +1,6 @@ import { expect } from "chai"; import { parseExposableServiceManifest } from "../../src/exposable/parseExposable.js"; -import { - ExposableServiceInfo, - ExposableServiceManifestInfo, - InstalledPackageData, -} from "@dappnode/types"; +import { ExposableServiceInfo, ExposableServiceManifestInfo, InstalledPackageData } from "@dappnode/types"; import { mockDnp, mockContainer } from "../testUtils.js"; describe("modules / https-portal / exposable", () => { @@ -12,7 +8,7 @@ describe("modules / https-portal / exposable", () => { const manifestExposable: ExposableServiceManifestInfo[] = [ { name: "name1", port: 1111 }, { broken: true } as unknown as ExposableServiceManifestInfo, - { name: "name3", description: "desc3", serviceName: "serv3", port: 3333 }, + { name: "name3", description: "desc3", serviceName: "serv3", port: 3333 } ]; const dnpName = "mock-dnp.dnp.dappnode.eth"; @@ -20,7 +16,7 @@ describe("modules / https-portal / exposable", () => { const dnp: InstalledPackageData = { ...mockDnp, dnpName, - containers: [{ ...mockContainer, serviceName }], + containers: [{ ...mockContainer, serviceName }] }; const expectedExposable: ExposableServiceInfo[] = [ @@ -30,7 +26,7 @@ describe("modules / https-portal / exposable", () => { description: "", dnpName: "mock-dnp.dnp.dappnode.eth", serviceName: "mock-dnp.dnp.dappnode.eth", - port: 1111, + port: 1111 }, { fromSubdomain: "serv-mock-dnp", @@ -38,8 +34,8 @@ describe("modules / https-portal / exposable", () => { description: "desc3", dnpName: "mock-dnp.dnp.dappnode.eth", serviceName: "serv3", - port: 3333, - }, + port: 3333 + } ]; const exposable = parseExposableServiceManifest(dnp, manifestExposable); diff --git a/packages/installer/.eslintignore b/packages/installer/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/installer/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/installer/.eslintrc.cjs b/packages/installer/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/installer/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/installer/package.json b/packages/installer/package.json index 1d446a03c..9a39f2076 100644 --- a/packages/installer/package.json +++ b/packages/installer/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/installer/src/calls/packageGet.ts b/packages/installer/src/calls/packageGet.ts index 742b94fca..76540d7b3 100644 --- a/packages/installer/src/calls/packageGet.ts +++ b/packages/installer/src/calls/packageGet.ts @@ -11,11 +11,7 @@ import { params } from "@dappnode/params"; /** * Get package detail information */ -export async function packageGet({ - dnpName, -}: { - dnpName: string; -}): Promise<InstalledPackageDetailData> { +export async function packageGet({ dnpName }: { dnpName: string }): Promise<InstalledPackageDetailData> { if (!dnpName) throw Error("kwarg id must be defined"); const dnpList = sortPackages(await listPackages()); @@ -30,10 +26,7 @@ export async function packageGet({ ...dnp, updateAvailable: - latestKnownVersion && - shouldUpdate(dnp.version, latestKnownVersion.newVersion) - ? latestKnownVersion - : null, + latestKnownVersion && shouldUpdate(dnp.version, latestKnownVersion.newVersion) ? latestKnownVersion : null, areThereVolumesToRemove: dnp.containers.some((container) => container.volumes.length > 0) && @@ -43,14 +36,11 @@ export async function packageGet({ return !owner || owner === dnp.dnpName; }) ), - dependantsOf: dnpList - .filter((d) => d.dependencies[dnpName]) - .map((d) => d.dnpName), + dependantsOf: dnpList.filter((d) => d.dependencies[dnpName]).map((d) => d.dnpName), - notRemovable: - dnp.isCore && params.corePackagesNotRemovable.includes(dnp.dnpName), + notRemovable: dnp.isCore && params.corePackagesNotRemovable.includes(dnp.dnpName), - packageSentData: db.packageSentData.get(dnp.dnpName) ?? {}, + packageSentData: db.packageSentData.get(dnp.dnpName) ?? {} }; // Add non-blocking data @@ -58,18 +48,12 @@ export async function packageGet({ const manifest = readManifestIfExists(dnp); if (manifest) { // Append manifest for general info - dnpData.manifest = omit(manifest, [ - "setupWizard", - "gettingStarted", - "backup", - ]); + dnpData.manifest = omit(manifest, ["setupWizard", "gettingStarted", "backup"]); // Getting started if (manifest.gettingStarted) { dnpData.gettingStarted = manifest.gettingStarted; - dnpData.gettingStartedShow = Boolean( - db.packageGettingStartedShow.get(dnp.dnpName) - ); + dnpData.gettingStartedShow = Boolean(db.packageGettingStartedShow.get(dnp.dnpName)); } // Backup @@ -81,9 +65,7 @@ export async function packageGet({ if (manifest.setupWizard) { dnpData.setupWizard = { ...manifest.setupWizard, - fields: manifest.setupWizard.fields.filter( - (field) => field.target && field.target.type === "environment" - ), + fields: manifest.setupWizard.fields.filter((field) => field.target && field.target.type === "environment") }; } } else { @@ -98,12 +80,9 @@ export async function packageGet({ // Why not fetch the ENVs from a container inspect > config ?? // ENVs that are not declared in the compose will show up (i.e. PATH) // So it's easier and cleaner to just parse the docker-compose.yml - const userSettings = ComposeFileEditor.getUserSettingsIfExist( - dnp.dnpName, - dnp.isCore - ); + const userSettings = ComposeFileEditor.getUserSettingsIfExist(dnp.dnpName, dnp.isCore); dnpData.userSettings = { - environment: userSettings.environment, + environment: userSettings.environment }; } catch (e) { logs.warn(`Error getting user settings for ${dnp.dnpName}`, e); diff --git a/packages/installer/src/calls/packageGetData.ts b/packages/installer/src/calls/packageGetData.ts index 771b5a65d..23557840a 100644 --- a/packages/installer/src/calls/packageGetData.ts +++ b/packages/installer/src/calls/packageGetData.ts @@ -8,10 +8,7 @@ import { DappnodeInstaller } from "../dappnodeInstaller.js"; // TODO: find a proper place for these functions. The functions inside this file // are not used as the other files within this same folder -export async function packageGetData( - dappnodeInstaller: DappnodeInstaller, - dnpName: string -): Promise<PackageItemData> { +export async function packageGetData(dappnodeInstaller: DappnodeInstaller, dnpName: string): Promise<PackageItemData> { const cachedDnp = db.pkgItemMetadata.get(dnpName); if (cachedDnp) { // Update cache in the background @@ -25,9 +22,7 @@ export async function packageGetData( } } -export function packagePickItemData( - pkgRelease: PackageRelease -): PackageItemData { +export function packagePickItemData(pkgRelease: PackageRelease): PackageItemData { return { manifest: packagePickManifestData(pkgRelease.manifest), ...pick(pkgRelease, [ @@ -38,19 +33,11 @@ export function packagePickItemData( "avatarFile", "warnings", "origin", - "signedSafe", - ] as const), + "signedSafe" + ] as const) }; } function packagePickManifestData(manifest: Manifest): Manifest { - return pick(manifest, [ - "name", - "version", - "shortDescription", - "avatar", - "links", - "chain", - "warnings", - ] as const); + return pick(manifest, ["name", "version", "shortDescription", "avatar", "links", "chain", "warnings"] as const); } diff --git a/packages/installer/src/calls/packageInstall.ts b/packages/installer/src/calls/packageInstall.ts index b22487030..bd99fe9f7 100644 --- a/packages/installer/src/calls/packageInstall.ts +++ b/packages/installer/src/calls/packageInstall.ts @@ -10,7 +10,7 @@ import { rollbackPackages, writeAndValidateFiles, postInstallClean, - afterInstall, + afterInstall } from "../installer/index.js"; import { logs, getLogUi, logUiClear } from "@dappnode/logger"; import { Routes } from "@dappnode/types"; @@ -31,40 +31,27 @@ import { DappnodeInstaller } from "../dappnodeInstaller.js"; */ export async function packageInstall( dappnodeInstaller: DappnodeInstaller, - { - name: reqName, - version: reqVersion, - userSettings = {}, - options = {}, - }: Parameters<Routes["packageInstall"]>[0] + { name: reqName, version: reqVersion, userSettings = {}, options = {} }: Parameters<Routes["packageInstall"]>[0] ): Promise<void> { // 1. Parse the id into a request const req: PackageRequest = { name: sanitizeRequestName(reqName), - ver: sanitizeRequestVersion(reqVersion), + ver: sanitizeRequestVersion(reqVersion) }; const id = req.name; const log = getLogUi(id); try { log(id, "Resolving dependencies..."); - const { state, currentVersions, releases } = - await dappnodeInstaller.getReleasesResolved(req, options); + const { state, currentVersions, releases } = await dappnodeInstaller.getReleasesResolved(req, options); logs.info("Resolved request", req, state); // Throw any errors found in the release for (const release of releases) { - if ( - release.warnings.coreFromForeignRegistry && - !options.BYPASS_CORE_RESTRICTION - ) - throw Error( - `Core package ${release.dnpName} is from a foreign registry` - ); + if (release.warnings.coreFromForeignRegistry && !options.BYPASS_CORE_RESTRICTION) + throw Error(`Core package ${release.dnpName} is from a foreign registry`); if (!release.signedSafe && !options.BYPASS_SIGNED_RESTRICTION) { - throw Error( - `Package ${release.dnpName} is from untrusted origin and is not signed` - ); + throw Error(`Package ${release.dnpName} is from untrusted origin and is not signed`); } } @@ -73,15 +60,14 @@ export async function packageInstall( releases, userSettings, currentVersions, - reqName, + reqName }); logs.debug("Packages data", packagesData); logs.debug("User settings", userSettings); // Make sure that no package is already being installed const dnpNames = packagesData.map(({ dnpName }) => dnpName); - for (const dnpName of dnpNames) - if (packageIsInstalling(dnpName)) throw Error(`${dnpName} is installing`); + for (const dnpName of dnpNames) if (packageIsInstalling(dnpName)) throw Error(`${dnpName} is installing`); try { flagPackagesAreInstalling(dnpNames); diff --git a/packages/installer/src/calls/packageRemove.ts b/packages/installer/src/calls/packageRemove.ts index 0d12e2072..0e4425bc3 100644 --- a/packages/installer/src/calls/packageRemove.ts +++ b/packages/installer/src/calls/packageRemove.ts @@ -8,7 +8,7 @@ import { dockerContainerRemove, dockerContainerStop, dockerComposeDown, - listPackage, + listPackage } from "@dappnode/dockerapi"; import { httpsPortal } from "@dappnode/httpsportal"; import { ethicalMetricsDnpName, unregister } from "@dappnode/ethicalmetrics"; @@ -21,7 +21,7 @@ import { ethicalMetricsDnpName, unregister } from "@dappnode/ethicalmetrics"; */ export async function packageRemove({ dnpName, - deleteVolumes = false, + deleteVolumes = false }: { dnpName: string; deleteVolumes?: boolean; @@ -44,10 +44,7 @@ export async function packageRemove({ httpsPortal.removeMappings(dnp); } catch (e) { // Bypass error to continue deleting the package - logs.error( - `Error trying to remove https mappings from ${dnp.dnpName}. Continue with package remove`, - e - ); + logs.error(`Error trying to remove https mappings from ${dnp.dnpName}. Continue with package remove`, e); } // If Ethical Metrics is being removed, unregister the instance first @@ -75,7 +72,7 @@ export async function packageRemove({ await dockerComposeDown(composePath, { volumes: deleteVolumes, // Ignore timeout is user doesn't want to keep any data - timeout: deleteVolumes ? undefined : timeout, + timeout: deleteVolumes ? undefined : timeout }); hasRemoved = true; // To mimic an early return } catch (e) { @@ -89,11 +86,7 @@ export async function packageRemove({ containerNames.map(async (containerName) => { // Continue removing package even if container is already stopped await dockerContainerStop(containerName, { timeout }).catch((e) => { - if ( - e.reason.includes("container already stopped") && - e.statusCode === 304 - ) - return; + if (e.reason.includes("container already stopped") && e.statusCode === 304) return; else throw e; }); await dockerContainerRemove(containerName, { volumes: deleteVolumes }); diff --git a/packages/installer/src/calls/packageSetEnvironment.ts b/packages/installer/src/calls/packageSetEnvironment.ts index eb3e2616d..5f94f1c6d 100644 --- a/packages/installer/src/calls/packageSetEnvironment.ts +++ b/packages/installer/src/calls/packageSetEnvironment.ts @@ -1,10 +1,6 @@ import { eventBus } from "@dappnode/eventbus"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - getContainersStatus, - dockerComposeUpPackage, - listPackage, -} from "@dappnode/dockerapi"; +import { getContainersStatus, dockerComposeUpPackage, listPackage } from "@dappnode/dockerapi"; import { packageInstalledHasPid, getDockerComposePath } from "@dappnode/utils"; import { PackageEnvs } from "@dappnode/types"; import { params } from "@dappnode/params"; @@ -15,7 +11,7 @@ import { restartDappmanagerPatch } from "../installer/index.js"; */ export async function packageSetEnvironment({ dnpName, - environmentByService, + environmentByService }: { dnpName: string; environmentByService: { [serviceName: string]: PackageEnvs }; @@ -27,9 +23,7 @@ export async function packageSetEnvironment({ const compose = new ComposeFileEditor(dnp.dnpName, dnp.isCore); const services = compose.services(); - for (const [serviceName, environment] of Object.entries( - environmentByService - )) { + for (const [serviceName, environment] of Object.entries(environmentByService)) { const service = services[serviceName]; if (!service) throw Error(`No service ${serviceName} in dnp ${dnpName}`); service.mergeEnvs(environment); @@ -44,12 +38,12 @@ export async function packageSetEnvironment({ if (dnpName === params.dappmanagerDnpName) { // Note: About restartPatch, combining rm && up doesn't prevent the installer from crashing await restartDappmanagerPatch({ - composePath: getDockerComposePath(params.dappmanagerDnpName, true), + composePath: getDockerComposePath(params.dappmanagerDnpName, true) }); return; } else { await dockerComposeUpPackage({ dnpName }, false, containersStatus, { - forceRecreate: packageInstalledHasPid(compose.compose), + forceRecreate: packageInstalledHasPid(compose.compose) }); } diff --git a/packages/installer/src/calls/packagesGet.ts b/packages/installer/src/calls/packagesGet.ts index c21af6898..245be2410 100644 --- a/packages/installer/src/calls/packagesGet.ts +++ b/packages/installer/src/calls/packagesGet.ts @@ -1,11 +1,7 @@ import * as db from "@dappnode/db"; import { shouldUpdate } from "@dappnode/utils"; import { listPackages } from "@dappnode/dockerapi"; -import { - InstalledPackageData, - InstalledPackageDataApiReturn, - UpdateAvailable, -} from "@dappnode/types"; +import { InstalledPackageData, InstalledPackageDataApiReturn, UpdateAvailable } from "@dappnode/types"; /** * Returns the list of current containers associated to packages @@ -17,15 +13,11 @@ export async function packagesGet(): Promise<InstalledPackageDataApiReturn[]> { const latestKnownVersions = db.packageLatestKnownVersion.getAll(); return dnps.map((dnp) => { - const latestKnownVersion: UpdateAvailable | undefined = - latestKnownVersions[dnp.dnpName]; + const latestKnownVersion: UpdateAvailable | undefined = latestKnownVersions[dnp.dnpName]; return { ...dnp, updateAvailable: - latestKnownVersion && - shouldUpdate(dnp.version, latestKnownVersion.newVersion) - ? latestKnownVersion - : null, + latestKnownVersion && shouldUpdate(dnp.version, latestKnownVersion.newVersion) ? latestKnownVersion : null }; }); } @@ -34,9 +26,7 @@ export async function packagesGet(): Promise<InstalledPackageDataApiReturn[]> { * Sort packages by dnpName * Sort their containers by isMain first, then by serviceName */ -export function sortPackages( - dnps: InstalledPackageData[] -): InstalledPackageData[] { +export function sortPackages(dnps: InstalledPackageData[]): InstalledPackageData[] { for (const dnp of dnps) { dnp.containers = dnp.containers.sort((a, b) => { if (a.isMain && !b.isMain) return -1; diff --git a/packages/installer/src/dappGet/aggregate/aggregateDependencies.ts b/packages/installer/src/dappGet/aggregate/aggregateDependencies.ts index dfb498143..49e7f5231 100644 --- a/packages/installer/src/dappGet/aggregate/aggregateDependencies.ts +++ b/packages/installer/src/dappGet/aggregate/aggregateDependencies.ts @@ -28,7 +28,7 @@ export default async function aggregateDependencies({ versionRange, dnps, recursiveCount, - dappGetFetcher, + dappGetFetcher }: { dappnodeInstaller: DappnodeInstaller; name: string; @@ -42,14 +42,11 @@ export default async function aggregateDependencies({ else if (recursiveCount++ > 1000) return; // Check injected dependency - if (!dappGetFetcher) - throw Error('injected dependency "fetch" is not defined'); + if (!dappGetFetcher) throw Error('injected dependency "fetch" is not defined'); // 1. Fetch versions of "name" that match this request // versions = [ "0.1.0", "/ipfs/QmFe3..."] - const versions = await dappGetFetcher - .versions(dappnodeInstaller, name, versionRange) - .then(sanitizeVersions); + const versions = await dappGetFetcher.versions(dappnodeInstaller, name, versionRange).then(sanitizeVersions); await Promise.all( versions.map(async (version) => { @@ -77,7 +74,7 @@ export default async function aggregateDependencies({ versionRange: dependencies[dependencyName], dnps, recursiveCount, - dappGetFetcher, + dappGetFetcher }); }) ); diff --git a/packages/installer/src/dappGet/aggregate/getRelevantInstalledDnps.ts b/packages/installer/src/dappGet/aggregate/getRelevantInstalledDnps.ts index 516f6ad97..a258ee1db 100644 --- a/packages/installer/src/dappGet/aggregate/getRelevantInstalledDnps.ts +++ b/packages/installer/src/dappGet/aggregate/getRelevantInstalledDnps.ts @@ -21,7 +21,7 @@ import { InstalledPackageData } from "@dappnode/types"; export default function getRelevantInstalledDnps({ requestedDnps, - installedDnps, + installedDnps }: { requestedDnps: string[]; installedDnps: InstalledPackageData[]; @@ -40,9 +40,7 @@ export default function getRelevantInstalledDnps({ if (dnp) addDependants(dnp); } // Return only packages that are not already included in the requestedDnps array - return Object.values(state).filter( - (dnp) => !requestedDnps.includes(dnp.dnpName) - ); + return Object.values(state).filter((dnp) => !requestedDnps.includes(dnp.dnpName)); function addDependants(dnp: InstalledPackageData): void { // Prevent possible recursive loops @@ -62,10 +60,7 @@ export default function getRelevantInstalledDnps({ function isInState(dnp: InstalledPackageData): boolean { return Boolean(state[dnp.dnpName]); } - function dependsOn( - dependantPkg: InstalledPackageData, - dnp: InstalledPackageData - ): boolean { + function dependsOn(dependantPkg: InstalledPackageData, dnp: InstalledPackageData): boolean { return Boolean(dependantPkg.dependencies[dnp.dnpName]); } } diff --git a/packages/installer/src/dappGet/aggregate/index.ts b/packages/installer/src/dappGet/aggregate/index.ts index 0e113524a..386ee1fa6 100644 --- a/packages/installer/src/dappGet/aggregate/index.ts +++ b/packages/installer/src/dappGet/aggregate/index.ts @@ -8,11 +8,7 @@ import { DappGetDnps } from "../types.js"; import { logs } from "@dappnode/logger"; import { DappGetFetcher } from "../fetch/DappGetFetcher.js"; import { setVersion } from "../utils/dnpUtils.js"; -import { - ErrorDappGetDowngrade, - ErrorDappGetNotSatisfyRange, - ErrorDappGetNoVersions, -} from "../errors.js"; +import { ErrorDappGetDowngrade, ErrorDappGetNotSatisfyRange, ErrorDappGetNoVersions } from "../errors.js"; import { InstalledPackageData, PackageRequest } from "@dappnode/types"; import { DappnodeInstaller } from "../../dappnodeInstaller.js"; @@ -64,7 +60,7 @@ export default async function aggregate({ dappnodeInstaller, req, dnpList, - dappGetFetcher, + dappGetFetcher }: { dappnodeInstaller: DappnodeInstaller; req: PackageRequest; @@ -82,7 +78,7 @@ export default async function aggregate({ name: req.name, versionRange: req.ver, dnps, - dappGetFetcher, // #### Injected dependency + dappGetFetcher // #### Injected dependency }); const relevantInstalledDnps = getRelevantInstalledDnps({ @@ -90,9 +86,7 @@ export default async function aggregate({ requestedDnps: Object.keys(dnps), // Ignore invalid versions as: dnp.dnp.dappnode.eth:dev, :c5ashf61 // Ignore 'core.dnp.dappnode.eth': it's dependencies are not real and its compatibility doesn't need to be guaranteed - installedDnps: dnpList.filter( - (dnp) => valid(dnp.version) && dnp.dnpName !== params.coreDnpName - ), + installedDnps: dnpList.filter((dnp) => valid(dnp.version) && dnp.dnpName !== params.coreDnpName) }); // Add relevant installed dnps and their dependencies to the dnps object await Promise.all( @@ -110,7 +104,7 @@ export default async function aggregate({ name: dnpName, versionRange: `>=${version}`, dnps, - dappGetFetcher, // #### Injected dependency + dappGetFetcher // #### Injected dependency }); } } catch (e) { @@ -132,8 +126,7 @@ export default async function aggregate({ delete dnps[dnpName].versions[version]; } } - if (!Object.keys(dnps[dnpName].versions).length) - throw new ErrorDappGetNotSatisfyRange(req); + if (!Object.keys(dnps[dnpName].versions).length) throw new ErrorDappGetNotSatisfyRange(req); } // > Label isInstalled + Enfore conditions: // - installed DNPs cannot be downgraded (don't apply this condition to the request) @@ -150,8 +143,7 @@ export default async function aggregate({ ) delete dnps[dnpName].versions[version]; } - if (!Object.keys(dnps[dnpName].versions).length) - throw new ErrorDappGetDowngrade({ dnpName, dnpVersion }); + if (!Object.keys(dnps[dnpName].versions).length) throw new ErrorDappGetDowngrade({ dnpName, dnpVersion }); } else { // Validate aggregated dnps // - dnps must contain at least one version of the requested package diff --git a/packages/installer/src/dappGet/basic.ts b/packages/installer/src/dappGet/basic.ts index f1e70c28d..ccd72123e 100644 --- a/packages/installer/src/dappGet/basic.ts +++ b/packages/installer/src/dappGet/basic.ts @@ -19,17 +19,13 @@ export default async function dappGetBasic( req: PackageRequest ): Promise<DappGetResult> { const dappGetFetcher = new DappGetFetcher(); - const dependencies = await dappGetFetcher.dependencies( - dappnodeInstaller, - req.name, - req.ver - ); + const dependencies = await dappGetFetcher.dependencies(dappnodeInstaller, req.name, req.ver); // Append dependencies in the list of DNPs to install // Add current request to pacakages to install const state = { ...dependencies, - [req.name]: req.ver, + [req.name]: req.ver }; const alreadyUpdated: DappGetState = {}; const currentVersions: DappGetState = {}; @@ -59,6 +55,6 @@ export default async function dappGetBasic( message: "dappGet basic resolved first level dependencies", state, alreadyUpdated: {}, - currentVersions, + currentVersions }; } diff --git a/packages/installer/src/dappGet/dappGet.ts b/packages/installer/src/dappGet/dappGet.ts index 9583a92b2..7e71f6a81 100644 --- a/packages/installer/src/dappGet/dappGet.ts +++ b/packages/installer/src/dappGet/dappGet.ts @@ -65,8 +65,7 @@ export async function dappGet( * It will not use the fetch or resolver module and only * fetch the first level dependencies of the request */ - if (options && options.BYPASS_RESOLVER) - return await dappGetBasic(dappnodeInstaller, req); + if (options && options.BYPASS_RESOLVER) return await dappGetBasic(dappnodeInstaller, req); const dnpList = await listPackages(); @@ -78,7 +77,7 @@ export async function dappGet( dappnodeInstaller, req, dnpList, - dappGetFetcher: dappGetFetcher || new DappGetFetcher(), + dappGetFetcher: dappGetFetcher || new DappGetFetcher() }); } catch (e) { logs.debug("dappGet/aggregate error", e); @@ -121,6 +120,6 @@ export async function dappGet( message, state, alreadyUpdated, - currentVersions, + currentVersions }; } diff --git a/packages/installer/src/dappGet/errors.ts b/packages/installer/src/dappGet/errors.ts index 28a559fa3..4d0af89e7 100644 --- a/packages/installer/src/dappGet/errors.ts +++ b/packages/installer/src/dappGet/errors.ts @@ -6,9 +6,7 @@ export class ErrorDappGetNotSatisfyRange extends DappGetError { req: PackageRequest; constructor(req: PackageRequest) { - super( - `Aggregated versions of request ${req.name}@${req.ver} did not satisfy its range` - ); + super(`Aggregated versions of request ${req.name}@${req.ver} did not satisfy its range`); this.req = req; } } @@ -17,13 +15,7 @@ export class ErrorDappGetDowngrade extends DappGetError { dnpName: string; dnpVersion: string; - constructor({ - dnpName, - dnpVersion, - }: { - dnpName: string; - dnpVersion: string; - }) { + constructor({ dnpName, dnpVersion }: { dnpName: string; dnpVersion: string }) { super( `Aggregated versions of installed package ${dnpName} cause a downgrade from ${dnpVersion}. Having a future development version could be the cause of this error.` ); @@ -37,9 +29,7 @@ export class ErrorDappGetNoVersions extends DappGetError { req: PackageRequest; constructor({ dnpName, req }: { dnpName: string; req: PackageRequest }) { - super( - `No version aggregated for ${dnpName}, request ${req.name} @ ${req.ver}` - ); + super(`No version aggregated for ${dnpName}, request ${req.name} @ ${req.ver}`); this.dnpName = dnpName; this.req = req; } diff --git a/packages/installer/src/dappGet/fetch/DappGetFetcher.ts b/packages/installer/src/dappGet/fetch/DappGetFetcher.ts index bf9166ff9..08699e5b5 100644 --- a/packages/installer/src/dappGet/fetch/DappGetFetcher.ts +++ b/packages/installer/src/dappGet/fetch/DappGetFetcher.ts @@ -10,23 +10,16 @@ export class DappGetFetcher { * @returns dependencies: * { dnp-name-1: "semverRange", dnp-name-2: "/ipfs/Qmf53..."} */ - async dependencies( - dappnodeInstaller: DappnodeInstaller, - name: string, - version: string - ): Promise<Dependencies> { + async dependencies(dappnodeInstaller: DappnodeInstaller, name: string, version: string): Promise<Dependencies> { const manifest = await dappnodeInstaller.getManifestFromDir(name, version); const dependencies = manifest.dependencies || {}; const optionalDependencies = manifest.optionalDependencies; if (optionalDependencies) { // Iterate over optional dependencies and inject them if installed - for (const [ - optionalDependencyName, - optionalDependencyVersion, - ] of Object.entries(optionalDependencies)) { + for (const [optionalDependencyName, optionalDependencyVersion] of Object.entries(optionalDependencies)) { const optionalDependency = await listPackageNoThrow({ - dnpName: optionalDependencyName, + dnpName: optionalDependencyName }); if (!optionalDependency) continue; dependencies[optionalDependencyName] = optionalDependencyVersion; @@ -49,30 +42,23 @@ export class DappGetFetcher { * } * @returns set of versions */ - async versions( - dappnodeInstaller: DappnodeInstaller, - name: string, - versionRange: string - ): Promise<string[]> { + async versions(dappnodeInstaller: DappnodeInstaller, name: string, versionRange: string): Promise<string[]> { if (validRange(versionRange)) { if (versionRange === "*") { // ##### TODO: Case 0. Force "*" to strictly fetch the last version only // If "*" is interpreted as any version, many old manifests are not well // hosted and delay the resolution too much because all old versions have // to timeout in order to proceed - const { version: latestVersion } = - await dappnodeInstaller.getVersionAndIpfsHash({ - dnpNameOrHash: name, - }); + const { version: latestVersion } = await dappnodeInstaller.getVersionAndIpfsHash({ + dnpNameOrHash: name + }); return [latestVersion]; } else if (valid(versionRange)) { // Case 1. Valid semver version (not range): Return that version return [versionRange]; } else { // Case 1. Valid semver range: Fetch the valid versions from APM - const requestedVersions = await dappnodeInstaller.fetchApmVersionsState( - name - ); + const requestedVersions = await dappnodeInstaller.fetchApmVersionsState(name); return Object.values(requestedVersions) .map(({ version }) => version) .filter((version) => satisfies(version, versionRange)); diff --git a/packages/installer/src/dappGet/resolve/generateErrorMessage.ts b/packages/installer/src/dappGet/resolve/generateErrorMessage.ts index fd8957b7f..a560deb0e 100644 --- a/packages/installer/src/dappGet/resolve/generateErrorMessage.ts +++ b/packages/installer/src/dappGet/resolve/generateErrorMessage.ts @@ -1,3 +1,4 @@ +import { logs } from "@dappnode/logger"; import { DappGetErrors } from "../types.js"; /** @@ -37,15 +38,12 @@ export default function generateErrorMessage({ if (!blameDepReq[dep]) blameDepReq[dep] = {}; blameDepReq[dep][req] = true; } - const highestDep = Object.keys(blameDep).reduce((a, b) => - blameDep[a] > blameDep[b] ? a : b - ); + const highestDep = Object.keys(blameDep).reduce((a, b) => (blameDep[a] > blameDep[b] ? a : b)); const blamePackages = Object.keys(blameDepReq[highestDep]).join(", "); - errorMsgs.push( - `Packages ${blamePackages} request incompatible versions of ${highestDep}.` - ); + errorMsgs.push(`Packages ${blamePackages} request incompatible versions of ${highestDep}.`); } catch (e) { // Ignore possible errors from the message processing + logs.error("Error generating blame message", e); } // Report how many cases have been checked errorMsgs.push(`Checked ${caseId}/${totalCases} possible states.`); diff --git a/packages/installer/src/dappGet/resolve/index.ts b/packages/installer/src/dappGet/resolve/index.ts index ef667f3c3..3776d643b 100644 --- a/packages/installer/src/dappGet/resolve/index.ts +++ b/packages/installer/src/dappGet/resolve/index.ts @@ -1,9 +1,5 @@ import verifyState from "./verifyState.js"; -import { - getPermutationsTable, - getTotalPermutations, - getPermutation -} from "./permutations.js"; +import { getPermutationsTable, getTotalPermutations, getPermutation } from "./permutations.js"; import { pickBy, mapValues } from "lodash-es"; import generateErrorMessage from "./generateErrorMessage.js"; import { DappGetDnps, DappGetErrors } from "../types.js"; diff --git a/packages/installer/src/dappGet/resolve/permutations.ts b/packages/installer/src/dappGet/resolve/permutations.ts index e767ae298..7011015a8 100644 --- a/packages/installer/src/dappGet/resolve/permutations.ts +++ b/packages/installer/src/dappGet/resolve/permutations.ts @@ -1,10 +1,6 @@ import prioritizeVersions from "./prioritizeVersions.js"; import prioritizeDnps from "./prioritizeDnps.js"; -import { - DappGetDnps, - PermutationsTableInterface, - PermutationInterface -} from "../types.js"; +import { DappGetDnps, PermutationsTableInterface, PermutationInterface } from "../types.js"; /** * Computes key parameters to construct all version permutations @@ -32,9 +28,7 @@ import { * { name: 'D', versions: [ '1.1.0', '1.0.0' ], n: 2, m: 6 } * ] */ -export function getPermutationsTable( - dnps: DappGetDnps -): PermutationsTableInterface { +export function getPermutationsTable(dnps: DappGetDnps): PermutationsTableInterface { let m = 1; // This sort is extremely important. It prioritizes the first successful version // The sort orders the priority criterias as follows @@ -54,7 +48,7 @@ export function getPermutationsTable( // // It is more important for A to have a specific version than B, // then order 2 should be followed - return prioritizeDnps(dnps).map(dnp => { + return prioritizeDnps(dnps).map((dnp) => { const versions = prioritizeVersions(dnp); const n = versions.length; const _m = m; @@ -73,13 +67,8 @@ export function getPermutationsTable( * ] * @returns total number of possible permutations */ -export function getTotalPermutations( - permutationsTable: PermutationsTableInterface -): number { - return Object.values(permutationsTable).reduce( - (num, dnp) => num * dnp.versions.length, - 1 - ); +export function getTotalPermutations(permutationsTable: PermutationsTableInterface): number { + return Object.values(permutationsTable).reduce((num, dnp) => num * dnp.versions.length, 1); } /** @@ -98,10 +87,7 @@ export function getTotalPermutations( * @returns A state with a specific set of versions * { A: '2.2.0', C: '2.0.0', D: '1.1.0' } */ -export function getPermutation( - permutationsTable: PermutationsTableInterface, - i: number -): PermutationInterface { +export function getPermutation(permutationsTable: PermutationsTableInterface, i: number): PermutationInterface { const permutation: PermutationInterface = {}; for (const dnp of permutationsTable) { permutation[dnp.name] = dnp.versions[Math.floor(i / dnp.m) % dnp.n]; diff --git a/packages/installer/src/dappGet/resolve/prioritizeDnps.ts b/packages/installer/src/dappGet/resolve/prioritizeDnps.ts index 94e21bdee..ebbbef8e9 100644 --- a/packages/installer/src/dappGet/resolve/prioritizeDnps.ts +++ b/packages/installer/src/dappGet/resolve/prioritizeDnps.ts @@ -45,13 +45,11 @@ interface PrioritizeDnpReturn extends DappGetDnp { * {name: 'A', isRequest: true, versions: []}, * ] */ -export default function prioritizeDnps( - dnps: DappGetDnps -): PrioritizeDnpReturn[] { +export default function prioritizeDnps(dnps: DappGetDnps): PrioritizeDnpReturn[] { // Convert the dnps object into an array of objects appending the name return ( Object.keys(dnps) - .map(name => ({ ...dnps[name], name })) + .map((name) => ({ ...dnps[name], name })) // Sort the package ordening .sort((dnpA, dnpB) => { if (dnpA.isRequest) return 1; diff --git a/packages/installer/src/dappGet/resolve/verifyState.ts b/packages/installer/src/dappGet/resolve/verifyState.ts index e6db15d9f..618c651c2 100644 --- a/packages/installer/src/dappGet/resolve/verifyState.ts +++ b/packages/installer/src/dappGet/resolve/verifyState.ts @@ -32,7 +32,7 @@ export default function verifyState( range: string; }; } { - for (const stateDnp of Object.keys(state).filter(pkg => state[pkg])) { + for (const stateDnp of Object.keys(state).filter((pkg) => state[pkg])) { const stateVer = state[stateDnp] || ""; if (!dnps[stateDnp]) { throw Error(`DNP ${stateDnp} not in dnps`); diff --git a/packages/installer/src/dappGet/utils/dnpUtils.ts b/packages/installer/src/dappGet/utils/dnpUtils.ts index 0bca985b8..e3d458a52 100644 --- a/packages/installer/src/dappGet/utils/dnpUtils.ts +++ b/packages/installer/src/dappGet/utils/dnpUtils.ts @@ -12,28 +12,15 @@ function getVersion( return ((dnps[name] || {}).versions || {})[version]; } -export function hasVersion( - dnps: DappGetDnps, - name: string, - version: string -): boolean { +export function hasVersion(dnps: DappGetDnps, name: string, version: string): boolean { return Boolean(getVersion(dnps, name, version)); } -export function getDependencies( - dnps: DappGetDnps, - name: string, - version: string -): Dependencies { +export function getDependencies(dnps: DappGetDnps, name: string, version: string): Dependencies { return getVersion(dnps, name, version); } -export function setVersion( - dnps: DappGetDnps, - name: string, - version: string, - dependencies: Dependencies -): void { +export function setVersion(dnps: DappGetDnps, name: string, version: string, dependencies: Dependencies): void { if (!dnps[name]) dnps[name] = { versions: {} }; dnps[name].versions[version] = sanitizeDependencies(dependencies); } diff --git a/packages/installer/src/dappGet/utils/safeSemver.ts b/packages/installer/src/dappGet/utils/safeSemver.ts index 249e2bd90..31ddc019c 100644 --- a/packages/installer/src/dappGet/utils/safeSemver.ts +++ b/packages/installer/src/dappGet/utils/safeSemver.ts @@ -13,9 +13,7 @@ import { isIpfsHash } from "../../utils.js"; * @param sortFunction can be semver.rcompare for example * @returns wrapped sort function */ -function safeSort( - sortFunction: (a: string, b: string) => number -): (a: string, b: string) => number { +function safeSort(sortFunction: (a: string, b: string) => number): (a: string, b: string) => number { return (v1: string, v2: string): number => { // 1. Put IPFS versions the first if (isIpfsHash(v1)) return -1; @@ -40,5 +38,5 @@ export const safeSemver = { if (!valid(ver)) return false; if (!validRange(range)) return false; return satisfies(ver, range); - }, + } }; diff --git a/packages/installer/src/dappGet/utils/sanitizeDependencies.ts b/packages/installer/src/dappGet/utils/sanitizeDependencies.ts index 2cffb5800..c57c5bc27 100644 --- a/packages/installer/src/dappGet/utils/sanitizeDependencies.ts +++ b/packages/installer/src/dappGet/utils/sanitizeDependencies.ts @@ -10,14 +10,8 @@ export function sanitizeDependencies(dependencies: Dependencies): Dependencies { throw Error("SANITIZE-ERROR: Dependencies is not defined"); } if (typeof dependencies !== "object") { - throw Error( - `SANITIZE-ERROR: Dependencies is not an object, dependencies: ${JSON.stringify( - dependencies - )}` - ); + throw Error(`SANITIZE-ERROR: Dependencies is not an object, dependencies: ${JSON.stringify(dependencies)}`); } - return mapValues(dependencies, (version) => - version === "latest" ? "*" : version - ); + return mapValues(dependencies, (version) => (version === "latest" ? "*" : version)); } diff --git a/packages/installer/src/dappGet/utils/sanitizeVersions.ts b/packages/installer/src/dappGet/utils/sanitizeVersions.ts index 8c89cbba5..20e2e165a 100644 --- a/packages/installer/src/dappGet/utils/sanitizeVersions.ts +++ b/packages/installer/src/dappGet/utils/sanitizeVersions.ts @@ -7,11 +7,7 @@ export function sanitizeVersions(versions: string[]): string[] { throw Error("SANITIZE-ERROR: Versions is not defined"); } if (!Array.isArray(versions)) { - throw Error( - `SANITIZE-ERROR: Versions is not an array. versions: ${JSON.stringify( - versions - )}` - ); + throw Error(`SANITIZE-ERROR: Versions is not an array. versions: ${JSON.stringify(versions)}`); } return versions; } diff --git a/packages/installer/src/dappnodeInstaller.ts b/packages/installer/src/dappnodeInstaller.ts index 5c6b3e8e0..40aa987a3 100644 --- a/packages/installer/src/dappnodeInstaller.ts +++ b/packages/installer/src/dappnodeInstaller.ts @@ -11,18 +11,11 @@ import { PackageRequest, SetupWizard, GrafanaDashboard, - PrometheusTarget, + PrometheusTarget } from "@dappnode/types"; import { DappGetState, DappgetOptions, dappGet } from "./dappGet/index.js"; -import { - validateDappnodeCompose, - validateManifestSchema, -} from "@dappnode/schemas"; -import { - ComposeEditor, - setDappnodeComposeDefaults, - writeMetadataToLabels, -} from "@dappnode/dockercompose"; +import { validateDappnodeCompose, validateManifestSchema } from "@dappnode/schemas"; +import { ComposeEditor, setDappnodeComposeDefaults, writeMetadataToLabels } from "@dappnode/dockercompose"; import { computeGlobalEnvsFromDb } from "@dappnode/db"; import { getIsCore } from "@dappnode/utils"; import { sanitizeDependencies } from "./dappGet/utils/sanitizeDependencies.js"; @@ -67,7 +60,7 @@ export class DappnodeInstaller extends DappnodeRepository { dnpNameOrHash: name, trustedKeys: db.releaseKeysTrusted.get(), os: process.arch, - version, + version }); // validate manifest and compose files @@ -79,7 +72,7 @@ export class DappnodeInstaller extends DappnodeRepository { disclaimer: pkgRelease.disclaimer, gettingStarted: pkgRelease.gettingStarted, grafanaDashboards: pkgRelease.grafanaDashboards, - prometheusTargets: pkgRelease.prometheusTargets, + prometheusTargets: pkgRelease.prometheusTargets }); // set compose to custom dappnode compose in release @@ -96,16 +89,10 @@ export class DappnodeInstaller extends DappnodeRepository { /** * Get multiple release assets for multiple requests */ - async getReleases(packages: { - [name: string]: string; - }): Promise<PackageRelease[]> { + async getReleases(packages: { [name: string]: string }): Promise<PackageRelease[]> { await this.updateProviders(); - const pkgReleases = await this.getPkgsReleases( - packages, - db.releaseKeysTrusted.get(), - process.arch - ); + const pkgReleases = await this.getPkgsReleases(packages, db.releaseKeysTrusted.get(), process.arch); // validate manifest and compose files pkgReleases.forEach((pkgRelease) => { @@ -120,7 +107,7 @@ export class DappnodeInstaller extends DappnodeRepository { disclaimer: pkgRelease.disclaimer, gettingStarted: pkgRelease.gettingStarted, grafanaDashboards: pkgRelease.grafanaDashboards, - prometheusTargets: pkgRelease.prometheusTargets, + prometheusTargets: pkgRelease.prometheusTargets }); }); @@ -154,7 +141,7 @@ export class DappnodeInstaller extends DappnodeRepository { const releases = await this.getReleases(result.state); return { ...result, - releases, + releases }; } @@ -164,7 +151,7 @@ export class DappnodeInstaller extends DappnodeRepository { disclaimer, gettingStarted, prometheusTargets, - grafanaDashboards, + grafanaDashboards }: { manifest: Manifest; SetupWizard?: SetupWizard; @@ -177,8 +164,7 @@ export class DappnodeInstaller extends DappnodeRepository { if (disclaimer) manifest.disclaimer = { message: disclaimer }; if (gettingStarted) manifest.gettingStarted = gettingStarted; if (prometheusTargets) manifest.prometheusTargets = prometheusTargets; - if (grafanaDashboards && grafanaDashboards.length > 0) - manifest.grafanaDashboards = grafanaDashboards; + if (grafanaDashboards && grafanaDashboards.length > 0) manifest.grafanaDashboards = grafanaDashboards; return manifest; } @@ -200,20 +186,14 @@ export class DappnodeInstaller extends DappnodeRepository { avatarFile: DistributedFile | undefined, origin?: string ): Compose { - const customCompose = new ComposeEditor( - setDappnodeComposeDefaults(compose, manifest) - ); + const customCompose = new ComposeEditor(setDappnodeComposeDefaults(compose, manifest)); const services = Object.values(customCompose.services()); const globalEnvsFromDbPrefixed = computeGlobalEnvsFromDb(true); const isCore = getIsCore(manifest); const metadata = this.parseMetadataFromManifest(manifest); for (const service of services) { - service.setGlobalEnvs( - manifest.globalEnvs, - globalEnvsFromDbPrefixed, - isCore - ); + service.setGlobalEnvs(manifest.globalEnvs, globalEnvsFromDbPrefixed, isCore); service.mergeLabels( writeMetadataToLabels({ @@ -232,7 +212,7 @@ export class DappnodeInstaller extends DappnodeRepository { services.length === 1 ? true : undefined, - dockerTimeout: parseTimeoutSeconds(metadata.dockerTimeout), + dockerTimeout: parseTimeoutSeconds(metadata.dockerTimeout) }) ); } @@ -247,8 +227,7 @@ export class DappnodeInstaller extends DappnodeRepository { private fileToMultiaddress(distributedFile?: DistributedFile): string { if (!distributedFile || !distributedFile.hash) return ""; - if (distributedFile.source === "ipfs") - return `/ipfs/${this.normalizeHash(distributedFile.hash)}`; + if (distributedFile.source === "ipfs") return `/ipfs/${this.normalizeHash(distributedFile.hash)}`; else return ""; } @@ -286,16 +265,10 @@ export class DappnodeInstaller extends DappnodeRepository { return { // TODO: research if this omit can be removed since none packages should have been publish with this // format from long time ago - ...omit(manifest as ManifestWithImage, [ - "avatar", - "image", - "setupSchema", - "setupTarget", - "setupUiJson", - ]), + ...omit(manifest as ManifestWithImage, ["avatar", "image", "setupSchema", "setupTarget", "setupUiJson"]), ...(setupWizard ? { setupWizard } : {}), // ##### Is this necessary? Correct manifest: type missing - type: manifest.type || "service", + type: manifest.type || "service" }; } } diff --git a/packages/installer/src/ethClient/apiUrl.ts b/packages/installer/src/ethClient/apiUrl.ts index 8fc25881c..2034abff5 100644 --- a/packages/installer/src/ethClient/apiUrl.ts +++ b/packages/installer/src/ethClient/apiUrl.ts @@ -15,7 +15,7 @@ export function getEthExecClientApiUrl(dnpName: string, port = 8545): string { const containerDomain = buildNetworkAlias({ dnpName, serviceName: "", - isMainOrMonoservice: true, + isMainOrMonoservice: true }); return `http://${containerDomain}:${port}`; @@ -30,17 +30,12 @@ export async function getEthConsClientApiUrl(dnpName: string): Promise<string> { let port = 3500; let domain = ""; const dnp = await listPackageNoThrow({ dnpName }); - if ( - dnp && - typeof dnp.chain === "object" && - dnp.chain.portNumber && - dnp.chain.serviceName - ) { + if (dnp && typeof dnp.chain === "object" && dnp.chain.portNumber && dnp.chain.serviceName) { port = dnp.chain.portNumber; domain = buildNetworkAlias({ dnpName: dnpName, serviceName: dnp.chain.serviceName, - isMainOrMonoservice: false, + isMainOrMonoservice: false }); } else { // Lighthouse, Teku and Prysm use 3500 @@ -51,7 +46,7 @@ export async function getEthConsClientApiUrl(dnpName: string): Promise<string> { domain = buildNetworkAlias({ dnpName: dnpName, serviceName: getBeaconServiceName(dnpName), - isMainOrMonoservice: false, + isMainOrMonoservice: false }); } return `http://${domain}:${port}`; diff --git a/packages/installer/src/ethClient/clientStatus.ts b/packages/installer/src/ethClient/clientStatus.ts index 94fbe47b6..2cfe1fd33 100644 --- a/packages/installer/src/ethClient/clientStatus.ts +++ b/packages/installer/src/ethClient/clientStatus.ts @@ -60,32 +60,26 @@ export async function getMultiClientStatus( if (await isSyncing(execUrl)) { return { ok: false, code: "IS_SYNCING" }; } else { - const _isApmStateCorrect = await isApmStateCorrect(execUrl).catch( - (eFromTestCall) => { - // APM state call failed, syncing call succeeded and is not working - // = Likely an error related to fetching state content - return { - ok: false, - code: "STATE_CALL_ERROR", - error: serializeError(eFromTestCall), - }; - } - ); + const _isApmStateCorrect = await isApmStateCorrect(execUrl).catch((eFromTestCall) => { + // APM state call failed, syncing call succeeded and is not working + // = Likely an error related to fetching state content + return { + ok: false, + code: "STATE_CALL_ERROR", + error: serializeError(eFromTestCall) + }; + }); if (_isApmStateCorrect) { // State contract is okay!! // Check is synced with consensus and remote execution if ( (await isSyncedWithConsensus(execUrl, consUrl).catch((e) => { - throw Error( - `Error while checking if synced with consensus: ${e.message}` - ); + throw Error(`Error while checking if synced with consensus: ${e.message}`); })) && (await isSyncedWithRemoteExecution(execUrl).catch((e) => { // Do not throw if checking remote execution fails // Otherwise the fallback will be triggered and the remote node may not be available - logs.error( - `Error while checking if synced with remote execution: ${e.message}` - ); + logs.error(`Error while checking if synced with remote execution: ${e.message}`); })) ) return { ok: true, url: execUrl, dnpName: execClientDnpName }; @@ -94,7 +88,7 @@ export async function getMultiClientStatus( // State is not correct, node is not synced but eth_syncing did not picked it up return { ok: false, - code: "STATE_NOT_SYNCED", + code: "STATE_NOT_SYNCED" }; } } @@ -110,47 +104,46 @@ export async function getMultiClientStatus( return { ok: false, code: "NOT_AVAILABLE", - error: serializeError(clientError), + error: serializeError(clientError) }; } else { return { ok: false, - code: "NOT_RUNNING", + code: "NOT_RUNNING" }; } } else { // DNP is not installed, figure out why - const installStatus = - db.ethExecClientInstallStatus.get(execClientDnpName); + const installStatus = db.ethExecClientInstallStatus.get(execClientDnpName); if (installStatus) { switch (installStatus.status) { case "TO_INSTALL": case "INSTALLING": return { ok: false, - code: "INSTALLING", + code: "INSTALLING" }; case "INSTALLING_ERROR": return { ok: false, code: "INSTALLING_ERROR", - error: installStatus.error, + error: installStatus.error }; case "INSTALLED": return { ok: false, - code: "UNINSTALLED", + code: "UNINSTALLED" }; case "UNINSTALLED": return { ok: false, - code: "NOT_INSTALLED", + code: "NOT_INSTALLED" }; } } else { return { ok: false, - code: "NOT_INSTALLED", + code: "NOT_INSTALLED" }; } } @@ -159,7 +152,7 @@ export async function getMultiClientStatus( return { ok: false, code: "UNKNOWN_ERROR", - error: eGeneric, + error: eGeneric }; } } @@ -173,13 +166,9 @@ export async function getMultiClientStatus( async function isSyncedWithRemoteExecution(localUrl: string): Promise<boolean> { if (db.ethClientFallback.get() === "off") return true; // Check is synced with remote execution - const latestLocalBlock = await (await getEthersProvider(localUrl)) - .send("eth_blockNumber", []) - .then(parseEthersBlock); + const latestLocalBlock = await (await getEthersProvider(localUrl)).send("eth_blockNumber", []).then(parseEthersBlock); - const latestRemoteBlock = await ( - await getEthersProvider(params.ETH_MAINNET_RPC_URL_REMOTE) - ) + const latestRemoteBlock = await (await getEthersProvider(params.ETH_MAINNET_RPC_URL_REMOTE)) .send("eth_blockNumber", []) .then(parseEthersBlock); @@ -194,9 +183,7 @@ async function isSyncedWithRemoteExecution(localUrl: string): Promise<boolean> { */ async function isSyncing(url: string): Promise<boolean> { const provider = await getEthersProvider(url); - const syncing = await provider - .send("eth_syncing", []) - .then(parseEthersSyncing); + const syncing = await provider.send("eth_syncing", []).then(parseEthersSyncing); if (!syncing) return false; @@ -220,7 +207,7 @@ async function isApmStateCorrect(url: string): Promise<boolean> { // Returns (uint16[3] semanticVersion, address contractAddress, bytes contentURI) const testTxData = { to: "0x0c564ca7b948008fb324268d8baedaeb1bd47bce", - data: "0x737e7d4f0000000000000000000000000000000000000000000000000000000000000023", + data: "0x737e7d4f0000000000000000000000000000000000000000000000000000000000000023" }; const result = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000342f697066732f516d63516958454c42745363646278464357454a517a69664d54736b4e5870574a7a7a5556776d754e336d4d4361000000000000000000000000"; @@ -238,22 +225,15 @@ async function isApmStateCorrect(url: string): Promise<boolean> { * @param consUrl * @returns true if synced, false if not synced */ -async function isSyncedWithConsensus( - execUrl: string, - consUrl: string -): Promise<boolean> { +async function isSyncedWithConsensus(execUrl: string, consUrl: string): Promise<boolean> { const provider = await getEthersProvider(execUrl); const execBlockNumber = await provider.getBlockNumber(); - const execBlockHeadersResponse = await fetch( - consUrl + "/eth/v2/beacon/blocks/head" - ); + const execBlockHeadersResponse = await fetch(consUrl + "/eth/v2/beacon/blocks/head"); // TODO: do better type checking const consBlockHeadersResponseParsed = // eslint-disable-next-line @typescript-eslint/no-explicit-any (await execBlockHeadersResponse.json()) as any; - const consBlockNumber = - consBlockHeadersResponseParsed.data.message.body.execution_payload - .block_number; + const consBlockNumber = consBlockHeadersResponseParsed.data.message.body.execution_payload.block_number; if (execBlockNumber - consBlockNumber < ETHEREUM_BLOCKS_PER_DAY) { return true; diff --git a/packages/installer/src/ethClient/ethereumClient.ts b/packages/installer/src/ethClient/ethereumClient.ts index bdb6579ad..c003d419c 100644 --- a/packages/installer/src/ethClient/ethereumClient.ts +++ b/packages/installer/src/ethClient/ethereumClient.ts @@ -1,31 +1,24 @@ import { isEqual, uniq } from "lodash-es"; -import { - Eth2ClientTarget, - EthClientRemote, - InstalledPackageDetailData, -} from "@dappnode/types"; +import { Eth2ClientTarget, EthClientRemote, InstalledPackageDetailData } from "@dappnode/types"; import * as db from "@dappnode/db"; import { eventBus } from "@dappnode/eventbus"; import { logs } from "@dappnode/logger"; import { getConsensusUserSettings } from "@dappnode/utils"; import { packageInstall, packageGet, packageRemove } from "../calls/index.js"; -import { - ComposeFileEditor, - parseServiceNetworks, -} from "@dappnode/dockercompose"; +import { ComposeFileEditor, parseServiceNetworks } from "@dappnode/dockercompose"; import { params } from "@dappnode/params"; import { dockerComposeUpPackage, dockerNetworkReconnect, listPackageNoThrow, - getNetworkContainerConfig, + getNetworkContainerConfig } from "@dappnode/dockerapi"; import { Network } from "@dappnode/types"; import { DappnodeInstaller } from "../dappnodeInstaller.js"; export enum ComposeAliasEditorAction { ADD, - REMOVE, + REMOVE } export class EthereumClient { @@ -45,12 +38,11 @@ export class EthereumClient { return { target: "remote", ethRemoteRpc: db.ethRemoteRpc.get() }; case EthClientRemote.off: - if (!executionClient || !consensusClient) - return { target: "remote", ethRemoteRpc: db.ethRemoteRpc.get() }; + if (!executionClient || !consensusClient) return { target: "remote", ethRemoteRpc: db.ethRemoteRpc.get() }; return { target: { execClient: executionClient, consClient: consensusClient }, - ethRemoteRpc: db.ethRemoteRpc.get(), + ethRemoteRpc: db.ethRemoteRpc.get() }; } } @@ -70,7 +62,7 @@ export class EthereumClient { deletePrevExecClientVolumes, deletePrevConsClient, deletePrevConsClientVolumes, - ethRemoteRpc, + ethRemoteRpc }: { dappnodeInstaller: DappnodeInstaller; nextTarget: Eth2ClientTarget; @@ -81,48 +73,35 @@ export class EthereumClient { deletePrevConsClientVolumes: boolean; ethRemoteRpc?: string; }): Promise<void> { - const { target: currentTarget, ethRemoteRpc: currentEthRemoteRpc } = - this.computeEthereumTarget(); + const { target: currentTarget, ethRemoteRpc: currentEthRemoteRpc } = this.computeEthereumTarget(); // Return if the target is the same - if ( - isEqual(nextTarget, currentTarget) && - ethRemoteRpc === currentEthRemoteRpc - ) - return; + if (isEqual(nextTarget, currentTarget) && ethRemoteRpc === currentEthRemoteRpc) return; // Remove clients if currentTarge is !== remote if (currentTarget !== "remote") { // Remove Execution client if (deletePrevExecClient) await packageRemove({ dnpName: currentTarget.execClient, - deleteVolumes: deletePrevExecClientVolumes, + deleteVolumes: deletePrevExecClientVolumes }).catch((e) => logs.error(`Error removing prev exec client: ${e}`)); // Remove Consensus client if (deletePrevConsClient) await packageRemove({ dnpName: currentTarget.consClient, - deleteVolumes: deletePrevConsClientVolumes, + deleteVolumes: deletePrevConsClientVolumes }).catch((e) => logs.error(`Error removing prev cons client: ${e}`)); } if (nextTarget === "remote") { - if (!ethRemoteRpc) - throw Error( - `Argument ethRemoteRpc must be defined if target is remote` - ); + if (!ethRemoteRpc) throw Error(`Argument ethRemoteRpc must be defined if target is remote`); db.ethClientRemote.set(EthClientRemote.on); db.ethRemoteRpc.set(ethRemoteRpc); // Remove alias fullnode.dappnode from the eth client if not removed by the user if (!deletePrevExecClient && currentTarget !== "remote") await this.updateFullnodeAlias({ network: Network.Mainnet, - prevExecClientDnpName: currentTarget.execClient, - }).catch((e) => - logs.error( - "Error removing fullnode.dappnode alias from previous ETH exec client", - e - ) - ); + prevExecClientDnpName: currentTarget.execClient + }).catch((e) => logs.error("Error removing fullnode.dappnode alias from previous ETH exec client", e)); } else { const { execClient, consClient } = nextTarget; db.ethClientRemote.set(EthClientRemote.off); @@ -131,17 +110,15 @@ export class EthereumClient { if (sync) await this.changeEthClientSync({ dappnodeInstaller, - prevExecClient: - currentTarget !== "remote" ? currentTarget.execClient : undefined, + prevExecClient: currentTarget !== "remote" ? currentTarget.execClient : undefined, execClient, - consClient, + consClient }); else await this.changeEthClientNotAsync({ - prevExecClient: - currentTarget !== "remote" ? currentTarget.execClient : undefined, + prevExecClient: currentTarget !== "remote" ? currentTarget.execClient : undefined, execClient, - consClient, + consClient }); } } @@ -157,16 +134,13 @@ export class EthereumClient { async updateFullnodeAlias({ prevExecClientDnpName, newExecClientDnpName, - network = Network.Mainnet, + network = Network.Mainnet }: { prevExecClientDnpName?: string; newExecClientDnpName?: string | null; network?: Network; }): Promise<void> { - const fullnodeAlias = - network === "mainnet" - ? params.FULLNODE_ALIAS - : `${network}.${params.FULLNODE_ALIAS}`; + const fullnodeAlias = network === "mainnet" ? params.FULLNODE_ALIAS : `${network}.${params.FULLNODE_ALIAS}`; logs.info( `Updating fullnode alias (${fullnodeAlias}) for network ${network} from ${prevExecClientDnpName} to ${newExecClientDnpName}` @@ -180,7 +154,7 @@ export class EthereumClient { ); await this.removeAliasFromPreviousExecClient({ execClientDnpName: prevExecClientDnpName, - fullnodeAlias, + fullnodeAlias }); } @@ -191,14 +165,14 @@ export class EthereumClient { ); this.addAliasToNewExecClient({ execClientDnpName: newExecClientDnpName, - fullnodeAlias, + fullnodeAlias }); } } private async removeAliasFromPreviousExecClient({ execClientDnpName, - fullnodeAlias, + fullnodeAlias }: { execClientDnpName: string; fullnodeAlias: string; @@ -206,27 +180,24 @@ export class EthereumClient { const execClientPkg = await packageGet({ dnpName: execClientDnpName }); const serviceName = this.getServiceNameFromPackage(execClientPkg); - const containerName = this.getContainerNameFromService( - execClientPkg, - serviceName - ); + const containerName = this.getContainerNameFromService(execClientPkg, serviceName); await this.removeContainerAliasFromDockerNetwork({ containerName, - aliasToRemove: fullnodeAlias, + aliasToRemove: fullnodeAlias }); this.editFullnodeAliasInCompose({ action: ComposeAliasEditorAction.REMOVE, execClientDnpName, execClientServiceName: serviceName, - alias: fullnodeAlias, + alias: fullnodeAlias }); } private async addAliasToNewExecClient({ execClientDnpName, - fullnodeAlias, + fullnodeAlias }: { execClientDnpName: string; fullnodeAlias: string; @@ -234,21 +205,18 @@ export class EthereumClient { const execClientPkg = await packageGet({ dnpName: execClientDnpName }); const serviceName = this.getServiceNameFromPackage(execClientPkg); - const containerName = this.getContainerNameFromService( - execClientPkg, - serviceName - ); + const containerName = this.getContainerNameFromService(execClientPkg, serviceName); this.addContainerAliasToDockerNetwork({ containerName, - aliasToAdd: fullnodeAlias, + aliasToAdd: fullnodeAlias }); this.editFullnodeAliasInCompose({ action: ComposeAliasEditorAction.ADD, execClientDnpName, execClientServiceName: serviceName, - alias: fullnodeAlias, + alias: fullnodeAlias }); } @@ -256,66 +224,47 @@ export class EthereumClient { return pkg.manifest?.mainService || pkg.containers[0].serviceName; } - private getContainerNameFromService( - pkg: InstalledPackageDetailData, - serviceName: string - ): string { + private getContainerNameFromService(pkg: InstalledPackageDetailData, serviceName: string): string { return ( - pkg.containers.find((container) => container.serviceName === serviceName) - ?.containerName || pkg.containers[0].containerName + pkg.containers.find((container) => container.serviceName === serviceName)?.containerName || + pkg.containers[0].containerName ); } private async removeContainerAliasFromDockerNetwork({ containerName, - aliasToRemove, + aliasToRemove }: { containerName: string; aliasToRemove: string; }): Promise<void> { - const currentEndpointConfig = await getNetworkContainerConfig( - containerName, - params.DOCKER_PRIVATE_NETWORK_NAME - ); + const currentEndpointConfig = await getNetworkContainerConfig(containerName, params.DOCKER_PRIVATE_NETWORK_NAME); - const updatedAliases = (currentEndpointConfig?.Aliases || []).filter( - (alias: string) => alias !== aliasToRemove - ); + const updatedAliases = (currentEndpointConfig?.Aliases || []).filter((alias: string) => alias !== aliasToRemove); const endpointConfig = { ...currentEndpointConfig, - Aliases: updatedAliases, + Aliases: updatedAliases }; - await dockerNetworkReconnect( - params.DOCKER_PRIVATE_NETWORK_NAME, - containerName, - endpointConfig - ); + await dockerNetworkReconnect(params.DOCKER_PRIVATE_NETWORK_NAME, containerName, endpointConfig); } private async addContainerAliasToDockerNetwork({ containerName, - aliasToAdd, + aliasToAdd }: { containerName: string; aliasToAdd: string; }): Promise<void> { - const currentEndpointConfig = await getNetworkContainerConfig( - containerName, - params.DOCKER_PRIVATE_NETWORK_NAME - ); + const currentEndpointConfig = await getNetworkContainerConfig(containerName, params.DOCKER_PRIVATE_NETWORK_NAME); const endpointConfig = { ...currentEndpointConfig, - Aliases: uniq([...(currentEndpointConfig?.Aliases || []), aliasToAdd]), + Aliases: uniq([...(currentEndpointConfig?.Aliases || []), aliasToAdd]) }; - await dockerNetworkReconnect( - params.DOCKER_PRIVATE_NETWORK_NAME, - containerName, - endpointConfig - ); + await dockerNetworkReconnect(params.DOCKER_PRIVATE_NETWORK_NAME, containerName, endpointConfig); } /** @@ -325,7 +274,7 @@ export class EthereumClient { dappnodeInstaller, prevExecClient, execClient, - consClient, + consClient }: { dappnodeInstaller: DappnodeInstaller; prevExecClient?: string; @@ -335,7 +284,7 @@ export class EthereumClient { try { // Install execution client and set default fullnode alias const execClientPackage = await listPackageNoThrow({ - dnpName: execClient, + dnpName: execClient }); if (!execClientPackage) { @@ -345,7 +294,7 @@ export class EthereumClient { await this.updateFullnodeAlias({ network: Network.Mainnet, newExecClientDnpName: execClient, - prevExecClientDnpName: prevExecClient, + prevExecClientDnpName: prevExecClient }) ); } else { @@ -357,24 +306,24 @@ export class EthereumClient { await this.updateFullnodeAlias({ network: Network.Mainnet, newExecClientDnpName: execClient, - prevExecClientDnpName: prevExecClient, + prevExecClientDnpName: prevExecClient }) ); } // Install consensus client const consClientPkg = await listPackageNoThrow({ - dnpName: execClient, + dnpName: execClient }); if (!consClientPkg) { // Get default cons client user settings and install cons client const userSettings = getConsensusUserSettings({ dnpName: consClient, - network: Network.Mainnet, + network: Network.Mainnet }); await packageInstall(dappnodeInstaller, { name: consClient, - userSettings, + userSettings }); } else { // Start pkg if not running @@ -392,20 +341,20 @@ export class EthereumClient { private async changeEthClientNotAsync({ prevExecClient, execClient, - consClient, + consClient }: { prevExecClient?: string; execClient: string; consClient: string; }): Promise<void> { db.ethExecClientInstallStatus.set(execClient, { - status: "TO_INSTALL", + status: "TO_INSTALL" }); db.ethConsClientInstallStatus.set(consClient, { - status: "TO_INSTALL", + status: "TO_INSTALL" }); eventBus.runEthClientInstaller.emit({ - prevExecClientDnpName: prevExecClient, + prevExecClientDnpName: prevExecClient }); } @@ -416,7 +365,7 @@ export class EthereumClient { action, execClientDnpName, execClientServiceName, - alias = params.FULLNODE_ALIAS, + alias = params.FULLNODE_ALIAS }: { action: ComposeAliasEditorAction; execClientDnpName: string; @@ -425,24 +374,13 @@ export class EthereumClient { }): void { const compose = new ComposeFileEditor(execClientDnpName, false); const composeService = compose.services()[execClientServiceName]; - const serviceNetworks = parseServiceNetworks( - composeService.get().networks || {} - ); - const serviceNetwork = - serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] || null; + const serviceNetworks = parseServiceNetworks(composeService.get().networks || {}); + const serviceNetwork = serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME] || null; if (action === ComposeAliasEditorAction.REMOVE) { - composeService.removeNetworkAliases( - params.DOCKER_PRIVATE_NETWORK_NAME, - [alias], - serviceNetwork - ); + composeService.removeNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, [alias], serviceNetwork); } else { - composeService.addNetworkAliases( - params.DOCKER_PRIVATE_NETWORK_NAME, - [alias], - serviceNetwork - ); + composeService.addNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, [alias], serviceNetwork); } compose.write(); diff --git a/packages/installer/src/ethClient/ethersProvider.ts b/packages/installer/src/ethClient/ethersProvider.ts index 350806228..74a364ad9 100644 --- a/packages/installer/src/ethClient/ethersProvider.ts +++ b/packages/installer/src/ethClient/ethersProvider.ts @@ -12,20 +12,14 @@ import { FetchRequest } from "ethers"; * If the package target is not active it returns the remote URL * @returns initialized ethers instance */ -export async function getEthersProvider( - url?: string, - network?: string -): Promise<ethers.JsonRpcProvider> { +export async function getEthersProvider(url?: string, network?: string): Promise<ethers.JsonRpcProvider> { const rpcUrl = url ?? (await getEthUrl()); const rpcNetwork = network ?? "mainnet"; const fetchRequest = new FetchRequest(rpcUrl); const versionData = db.versionData.get(); - fetchRequest.setHeader( - "x-dappmanager-version", - `${versionData.version}-${db.versionData.get().commit?.slice(0, 8)}` - ); + fetchRequest.setHeader("x-dappmanager-version", `${versionData.version}-${db.versionData.get().commit?.slice(0, 8)}`); return new ethers.JsonRpcProvider(fetchRequest, rpcNetwork, { - staticNetwork: true, + staticNetwork: true }); } @@ -35,8 +29,7 @@ export async function getEthersProvider( * @returns ethProvier http://geth.dappnode:8545 */ export async function getEthUrl(): Promise<string> { - if (params.ETH_MAINNET_RPC_URL_OVERRIDE) - return params.ETH_MAINNET_RPC_URL_OVERRIDE; + if (params.ETH_MAINNET_RPC_URL_OVERRIDE) return params.ETH_MAINNET_RPC_URL_OVERRIDE; const { target, ethRemoteRpc } = ethereumClient.computeEthereumTarget(); @@ -50,10 +43,7 @@ export async function getEthUrl(): Promise<string> { if (!target.execClient) throw Error("No execution client selected yet"); if (!target.consClient) throw Error("No consensus client selected yet"); - const status = await getMultiClientStatus( - target.execClient, - target.consClient - ); + const status = await getMultiClientStatus(target.execClient, target.consClient); db.ethExecClientStatus.set(target.execClient, status); emitSyncedNotification(target, status); diff --git a/packages/installer/src/ethClient/localFallbackVersions.ts b/packages/installer/src/ethClient/localFallbackVersions.ts index f001833a2..0010cde91 100644 --- a/packages/installer/src/ethClient/localFallbackVersions.ts +++ b/packages/installer/src/ethClient/localFallbackVersions.ts @@ -15,9 +15,7 @@ interface ContentHashes { * Local fallback versions, to be able to install and eth client without connecting to remote * @param dnpName "geth.dnp.dappnode.eth" */ -export function getLocalFallbackContentHash( - dnpName: string -): string | undefined { +export function getLocalFallbackContentHash(dnpName: string): string | undefined { const contentHashes = loadContentHashes(params.FALLBACK_VERSIONS_PATH); return (contentHashes || {})[dnpName]; } diff --git a/packages/installer/src/ethClient/syncedNotification.ts b/packages/installer/src/ethClient/syncedNotification.ts index 498999de4..e720b5d2d 100644 --- a/packages/installer/src/ethClient/syncedNotification.ts +++ b/packages/installer/src/ethClient/syncedNotification.ts @@ -5,10 +5,7 @@ import { Eth2ClientTarget, EthClientStatus } from "@dappnode/types"; /** * Send a notification when going from syncing to synced only once per target */ -export function emitSyncedNotification( - target: Eth2ClientTarget, - status: EthClientStatus -): void { +export function emitSyncedNotification(target: Eth2ClientTarget, status: EthClientStatus): void { if (target === "remote" || !target.execClient) return; const syncedStatus = db.ethClientSyncedNotificationStatus.get(); @@ -20,7 +17,7 @@ export function emitSyncedNotification( // None -> AwaitingSynced db.ethClientSyncedNotificationStatus.set({ execClientTarget: target.execClient, - status: "AwaitingSynced", + status: "AwaitingSynced" }); } else if ( status.ok && @@ -31,13 +28,13 @@ export function emitSyncedNotification( // AwaitingSynced -> Synced db.ethClientSyncedNotificationStatus.set({ execClientTarget: target.execClient, - status: "Synced", + status: "Synced" }); eventBus.notification.emit({ id: `eth-client-synced-${target}`, type: "success", title: "Ethereum node synced", - body: `Your DAppNode's Ethereum node ${target} is synced.`, + body: `Your DAppNode's Ethereum node ${target} is synced.` }); } } diff --git a/packages/installer/src/ethClient/types.ts b/packages/installer/src/ethClient/types.ts index 53b242215..f80dede79 100644 --- a/packages/installer/src/ethClient/types.ts +++ b/packages/installer/src/ethClient/types.ts @@ -6,5 +6,5 @@ import { ErrorSerialized } from "@dappnode/types"; */ export const serializeError = (e: Error): ErrorSerialized => ({ message: e.message, - stack: e.stack, + stack: e.stack }); diff --git a/packages/installer/src/installer/createVolumeDevicePaths.ts b/packages/installer/src/installer/createVolumeDevicePaths.ts index 02b160ee6..a0079da1b 100644 --- a/packages/installer/src/installer/createVolumeDevicePaths.ts +++ b/packages/installer/src/installer/createVolumeDevicePaths.ts @@ -9,9 +9,7 @@ import { shellHost } from "@dappnode/utils"; * If the full path declared in the compose in not already created * docker will throw an error */ -export default async function createVolumeDevicePaths( - composeArray: { compose: Compose }[] -): Promise<void> { +export default async function createVolumeDevicePaths(composeArray: { compose: Compose }[]): Promise<void> { const volumePaths = getVolumeDevicePaths(composeArray); if (!volumePaths.length) return; @@ -36,9 +34,7 @@ export default async function createVolumeDevicePaths( * Gets an array of devicePaths used in a Compose * [NOTE]: This pure function is abstracted for testability */ -export function getVolumeDevicePaths( - composeArray: { compose: Compose }[] -): string[] { +export function getVolumeDevicePaths(composeArray: { compose: Compose }[]): string[] { const volumePaths: string[] = []; for (const { compose } of composeArray) for (const volObj of Object.values(compose.volumes || [])) diff --git a/packages/installer/src/installer/downloadImages.ts b/packages/installer/src/installer/downloadImages.ts index 33a040be7..712fb54ed 100644 --- a/packages/installer/src/installer/downloadImages.ts +++ b/packages/installer/src/installer/downloadImages.ts @@ -1,10 +1,6 @@ import fs from "fs"; import { isAbsolute } from "path"; -import { - InstallPackageData, - DistributedFile, - getImageTag, -} from "@dappnode/types"; +import { InstallPackageData, DistributedFile, getImageTag } from "@dappnode/types"; import { Log, logs } from "@dappnode/logger"; import { shell, validatePath } from "@dappnode/utils"; import { getDockerImageManifest } from "@dappnode/dockerapi"; @@ -88,8 +84,7 @@ export async function getImage( progress: (n: number) => void ): Promise<void> { // Validate parameters - if (!path || path.startsWith("/ipfs/") || !isAbsolute("/")) - throw Error(`Invalid path: "${path}"`); + if (!path || path.startsWith("/ipfs/") || !isAbsolute("/")) throw Error(`Invalid path: "${path}"`); validatePath(path); // Check if cache exist and validate it @@ -98,6 +93,7 @@ export async function getImage( return; // Image OK } catch (e) { // Continue, bad image + logs.error(`Image at ${path} is invalid: ${e}`); } const { hash, size } = imageFile; @@ -112,9 +108,7 @@ export async function getImage( // Validate downloaded image await validateTarImage(path).catch((e) => { - throw Error( - `Downloaded image from ${imageFile.hash} to ${path} failed validation: ${e.message}` - ); + throw Error(`Downloaded image from ${imageFile.hash} to ${path} failed validation: ${e.message}`); }); } @@ -126,7 +120,7 @@ export async function getImage( async function verifyDockerImage({ imagePath, dnpName, - version, + version }: { imagePath: string; dnpName: string; @@ -135,13 +129,12 @@ async function verifyDockerImage({ const expectedTagSuffix = getImageTag({ dnpName, serviceName: dnpName, - version, + version }); const images = await getDockerImageManifest(imagePath); for (const image of images) { for (const repoTag of image.RepoTags) { - if (!repoTag.endsWith(expectedTagSuffix)) - throw Error(`Invalid image tag '${repoTag}' for ${dnpName} ${version}`); + if (!repoTag.endsWith(expectedTagSuffix)) throw Error(`Invalid image tag '${repoTag}' for ${dnpName} ${version}`); } } } @@ -180,10 +173,10 @@ async function verifyXz(xzFilePath: string): Promise<{ return shell(`xz -t ${xzFilePath}`) .then(() => ({ success: true, - message: "", + message: "" })) .catch((e: Error) => ({ success: false, - message: e.message, + message: e.message })); } diff --git a/packages/installer/src/installer/getInstallerPackageData.ts b/packages/installer/src/installer/getInstallerPackageData.ts index 99b73dada..5f08dddcc 100644 --- a/packages/installer/src/installer/getInstallerPackageData.ts +++ b/packages/installer/src/installer/getInstallerPackageData.ts @@ -8,14 +8,9 @@ import { UserSettings, PackageRelease, InstallPackageData, - ContainersStatus, + ContainersStatus } from "@dappnode/types"; -import { - getBackupPath, - getDockerComposePath, - getImagePath, - getManifestPath, -} from "@dappnode/utils"; +import { getBackupPath, getDockerComposePath, getImagePath, getManifestPath } from "@dappnode/utils"; interface GetInstallerPackageDataArg { releases: PackageRelease[]; @@ -28,7 +23,7 @@ export async function getInstallerPackagesData({ releases, userSettings, currentVersions, - reqName, + reqName }: GetInstallerPackageDataArg): Promise<InstallPackageData[]> { // Gather packageData first to prevent calling multiple times // listPackage inside of getContainersStatus @@ -43,7 +38,7 @@ export async function getInstallerPackagesData({ currentVersions[release.dnpName], await getContainersStatus({ dnpName: release.dnpName, - dnp: dnps.find((pkg) => pkg.dnpName === release.dnpName), + dnp: dnps.find((pkg) => pkg.dnpName === release.dnpName) }) ) ) @@ -101,6 +96,6 @@ function getInstallerPackageData( // User settings to be applied by the installer fileUploads: userSettings?.fileUploads, dockerTimeout, - containersStatus, + containersStatus }; } diff --git a/packages/installer/src/installer/loadImages.ts b/packages/installer/src/installer/loadImages.ts index 491b60a46..895c9f782 100644 --- a/packages/installer/src/installer/loadImages.ts +++ b/packages/installer/src/installer/loadImages.ts @@ -8,16 +8,11 @@ import { loadImage, getDockerImageManifest } from "@dappnode/dockerapi"; * If a dependency fails, some future version of another DNP could be loaded * creating wierd bugs with unstable versions */ -export async function loadImages( - packagesData: InstallPackageData[], - log: Log -): Promise<void> { +export async function loadImages(packagesData: InstallPackageData[], log: Log): Promise<void> { await Promise.all( packagesData.map(async function ({ dnpName, imagePath }) { log(dnpName, "Loading image..."); - await loadImageWithProgress(imagePath, (message) => - log(dnpName, message) - ); + await loadImageWithProgress(imagePath, (message) => log(dnpName, message)); log(dnpName, "Package Loaded"); }) ); @@ -27,14 +22,10 @@ export async function loadImages( * Logs image load progress without knowing the total uncompress image size * Assumes all image layers have the same size */ -async function loadImageWithProgress( - imagePath: string, - log: (message: string) => void -): Promise<void> { +async function loadImageWithProgress(imagePath: string, log: (message: string) => void): Promise<void> { const imageManifests = await getDockerImageManifest(imagePath); let totalLayers = 0; - for (const manifest of imageManifests) - totalLayers += (manifest.Layers || []).length; + for (const manifest of imageManifests) totalLayers += (manifest.Layers || []).length; const seenLayers = new Set<string>(); let lastPercent = -1; @@ -45,14 +36,9 @@ async function loadImageWithProgress( seenLayers.add(layerId); - if ( - Number.isInteger(current) && - Number.isInteger(total) && - totalLayers > 0 - ) { + if (Number.isInteger(current) && Number.isInteger(total) && totalLayers > 0) { const layerProgress = current / total; - const totalProgress = - (seenLayers.size - 1) / totalLayers + layerProgress / totalLayers; + const totalProgress = (seenLayers.size - 1) / totalLayers + layerProgress / totalLayers; const roundedPercent = Math.min(100, Math.round(100 * totalProgress)); if (lastPercent !== roundedPercent) { log(`Loading image ${roundedPercent}%`); diff --git a/packages/installer/src/installer/orderInstallPackages.ts b/packages/installer/src/installer/orderInstallPackages.ts index d499d8971..6261fe6df 100644 --- a/packages/installer/src/installer/orderInstallPackages.ts +++ b/packages/installer/src/installer/orderInstallPackages.ts @@ -13,10 +13,7 @@ const dappmanager = params.dappmanagerDnpName; * volumes, so the packages have to be ordered * @param packagesData */ -export function orderInstallPackages( - packagesData: InstallPackageData[], - requestName: string -): InstallPackageData[] { +export function orderInstallPackages(packagesData: InstallPackageData[], requestName: string): InstallPackageData[] { // Generic order, by name and the dappmanager the last const basicOrder = packagesData .sort((a, b) => a.dnpName.localeCompare(b.dnpName)) @@ -32,9 +29,7 @@ export function orderInstallPackages( const requestPkg = packagesData.find((pkg) => pkg.dnpName === requestName); if (requestPkg && requestPkg.manifest.runOrder?.length) { const runOrder = requestPkg.manifest.runOrder; - return basicOrder.sort( - (a, b) => runOrder.indexOf(a.dnpName) - runOrder.indexOf(b.dnpName) - ); + return basicOrder.sort((a, b) => runOrder.indexOf(a.dnpName) - runOrder.indexOf(b.dnpName)); } // Order by volume dependencies diff --git a/packages/installer/src/installer/postInstallClean.ts b/packages/installer/src/installer/postInstallClean.ts index cc2a4a103..f2d69212e 100644 --- a/packages/installer/src/installer/postInstallClean.ts +++ b/packages/installer/src/installer/postInstallClean.ts @@ -13,17 +13,8 @@ import { dockerCleanOldImages } from "@dappnode/dockerapi"; * @param packagesData * @param log */ -export async function postInstallClean( - packagesData: InstallPackageDataPaths[], - log: Log -): Promise<void> { - for (const { - dnpName, - semVersion, - imagePath, - manifestBackupPath, - composeBackupPath, - } of packagesData) { +export async function postInstallClean(packagesData: InstallPackageDataPaths[], log: Log): Promise<void> { + for (const { dnpName, semVersion, imagePath, manifestBackupPath, composeBackupPath } of packagesData) { db.addPackageInstalledMetadata(dnpName); // [Clean] old files and images @@ -62,6 +53,5 @@ function unlinkIfExists(path: string): void { * @param ext ".tar.xz" */ function unlinkFilesWithExt(dir: string, ext: string): void { - for (const file of fs.readdirSync(dir)) - if (file.endsWith(ext)) unlinkIfExists(path.join(dir, file)); + for (const file of fs.readdirSync(dir)) if (file.endsWith(ext)) unlinkIfExists(path.join(dir, file)); } diff --git a/packages/installer/src/installer/restartPatch.ts b/packages/installer/src/installer/restartPatch.ts index e675e9dc9..3ef042848 100644 --- a/packages/installer/src/installer/restartPatch.ts +++ b/packages/installer/src/installer/restartPatch.ts @@ -1,20 +1,12 @@ import fs from "fs"; import path from "path"; -import { - getBackupPath, - getDockerComposePath, - validatePath, -} from "@dappnode/utils"; +import { getBackupPath, getDockerComposePath, validatePath } from "@dappnode/utils"; import * as db from "@dappnode/db"; import { shell, pause } from "@dappnode/utils"; import { params } from "@dappnode/params"; import { logs } from "@dappnode/logger"; import Dockerode from "dockerode"; -import { - dockerContainerInspect, - logContainer, - dockerContainerRemove, -} from "@dappnode/dockerapi"; +import { dockerContainerInspect, logContainer, dockerContainerRemove } from "@dappnode/dockerapi"; import { getLogUi } from "@dappnode/logger"; import { rollbackPackages } from "./rollbackPackages.js"; import { postInstallClean } from "./postInstallClean.js"; @@ -44,7 +36,7 @@ export async function restartDappmanagerPatch({ composeBackupPath, restartCommand, restartLaunchCommand, - packagesData, + packagesData }: { composePath: string; composeBackupPath?: string; @@ -120,9 +112,9 @@ exit $UPEXIT volumes: params.restartDnpVolumes, // The entrypoint property in the docker compose overwrites // both the CMD [ ] and ENTRYPOINT [ ] directive in the Dockerfile - entrypoint: restartCommand || `/bin/sh ${restartScriptPath}`, - }, - }, + entrypoint: restartCommand || `/bin/sh ${restartScriptPath}` + } + } }); validatePath(composeRestartPath); @@ -138,10 +130,7 @@ exit $UPEXIT // // [NOTE2]: Allow to customize the restart launch command with a parameter that comes from // the new DAPPMANAGER / CORE manifest, as an extra safety measure - await shell( - restartLaunchCommand || - `docker compose -f ${composeRestartPath} up --force-recreate <&-` - ); + await shell(restartLaunchCommand || `docker compose -f ${composeRestartPath} up --force-recreate <&-`); if (packagesData) db.coreUpdatePackagesData.set(null); } catch (e) { @@ -197,9 +186,7 @@ export async function postRestartPatch(): Promise<void> { * Non-essential, so wrap in try catch to not prevent a rollback * @param restart */ -async function logRestartPatchStatus( - restart: Dockerode.ContainerInspectInfo -): Promise<void> { +async function logRestartPatchStatus(restart: Dockerode.ContainerInspectInfo): Promise<void> { try { if (!restart) { logs.info(`No restart patch found, assuming a manual restart`); @@ -231,10 +218,7 @@ async function waitForRestartPatchToFinish(): Promise<Dockerode.ContainerInspect try { let restart = await dockerContainerInspect(restartContainerName); const start = Date.now(); - while ( - Date.now() - start < timeoutWaitForRestart && - restart.State.Running - ) { + while (Date.now() - start < timeoutWaitForRestart && restart.State.Running) { restart = await dockerContainerInspect(restartContainerName); await pause(1000); } @@ -251,9 +235,7 @@ async function waitForRestartPatchToFinish(): Promise<Dockerode.ContainerInspect * so this function ensures compatibility cross-version * - packageData from < v0.2.35, won't have property .dnpName */ -function parsePackageDataRaw( - packageData: InstallPackageDataPaths -): InstallPackageDataPaths { +function parsePackageDataRaw(packageData: InstallPackageDataPaths): InstallPackageDataPaths { if (packageData.dnpName) { // New OK data return packageData; @@ -268,7 +250,7 @@ function parsePackageDataRaw( return { ...packageData, dnpName: pre0235Data.name, - semVersion: pre0235Data.version, + semVersion: pre0235Data.version }; } diff --git a/packages/installer/src/installer/rollbackPackages.ts b/packages/installer/src/installer/rollbackPackages.ts index a7c89af59..598b6367f 100644 --- a/packages/installer/src/installer/rollbackPackages.ts +++ b/packages/installer/src/installer/rollbackPackages.ts @@ -13,24 +13,20 @@ import { restartDappmanagerPatch } from "./restartPatch.js"; * @param packagesData * @param log */ -export async function rollbackPackages( - packagesData: InstallPackageDataPaths[], - log: Log -): Promise<void> { +export async function rollbackPackages(packagesData: InstallPackageDataPaths[], log: Log): Promise<void> { // Restore all backup composes. Do it first to make sure the next version compose is not // used unintentionally if the installed package is restored for (const pkg of packagesData) for (const { from, to } of [ { from: pkg.composeBackupPath, to: pkg.composePath }, - { from: pkg.manifestBackupPath, to: pkg.manifestPath }, + { from: pkg.manifestBackupPath, to: pkg.manifestPath } ]) try { // Don't use rename as it fails if paths are in different file systems (docker volume / docker container) fs.copyFileSync(from, to); fs.unlinkSync(from); } catch (e) { - if (!isNotFoundError(e) || pkg.isUpdate) - logs.error(`Rollback error restoring ${pkg.dnpName} ${from}`, e); + if (!isNotFoundError(e) || pkg.isUpdate) logs.error(`Rollback error restoring ${pkg.dnpName} ${from}`, e); } // Delete image files diff --git a/packages/installer/src/installer/runPackages.ts b/packages/installer/src/installer/runPackages.ts index 89a54a5bd..aa3676860 100644 --- a/packages/installer/src/installer/runPackages.ts +++ b/packages/installer/src/installer/runPackages.ts @@ -4,11 +4,7 @@ import { restartDappmanagerPatch } from "./restartPatch.js"; import { Log } from "@dappnode/logger"; import { InstallPackageData } from "@dappnode/types"; import { logs } from "@dappnode/logger"; -import { - dockerComposeUpPackage, - dockerComposeUp, - copyFileToDockerContainer, -} from "@dappnode/dockerapi"; +import { dockerComposeUpPackage, dockerComposeUp, copyFileToDockerContainer } from "@dappnode/dockerapi"; import { packageToInstallHasPid } from "@dappnode/utils"; import { httpsPortal } from "@dappnode/httpsportal"; @@ -18,10 +14,7 @@ const externalNetworkName = params.DOCKER_EXTERNAL_NETWORK_NAME; * Create and run each package container in series * The order is extremely important and should be guaranteed by `orderInstallPackages` */ -export async function runPackages( - packagesData: InstallPackageData[], - log: Log -): Promise<void> { +export async function runPackages(packagesData: InstallPackageData[], log: Log): Promise<void> { for (const pkg of packagesData) { // patch to prevent installer from crashing if (pkg.dnpName == params.dappmanagerDnpName) { @@ -31,7 +24,7 @@ export async function runPackages( composeBackupPath: pkg.composeBackupPath, restartCommand: pkg.manifest.restartCommand, restartLaunchCommand: pkg.manifest.restartLaunchCommand, - packagesData, + packagesData }); continue; @@ -50,7 +43,7 @@ export async function runPackages( // EXCEPTION!: If the compose contains: `pid:service.serviceName` // compose must start with: `noStart: false` noStart: !packageToInstallHasPid(pkg) ? true : false, - timeout: pkg.dockerTimeout, + timeout: pkg.dockerTimeout }); // Copy fileUploads if any to the container before up-ing @@ -58,23 +51,18 @@ export async function runPackages( log(pkg.dnpName, "Copying file uploads..."); logs.debug(`${pkg.dnpName} fileUploads`, pkg.fileUploads); - for (const [serviceName, serviceFileUploads] of Object.entries( - pkg.fileUploads - )) - for (const [containerPath, dataUri] of Object.entries( - serviceFileUploads - )) { + for (const [serviceName, serviceFileUploads] of Object.entries(pkg.fileUploads)) + for (const [containerPath, dataUri] of Object.entries(serviceFileUploads)) { const { dir: toPath, base: filename } = path.parse(containerPath); const service = pkg.compose.services[serviceName]; if (!service) throw Error(`No service for ${serviceName}`); const containerName = service.container_name; - if (!containerName) - throw Error(`No container name for ${serviceName}`); + if (!containerName) throw Error(`No container name for ${serviceName}`); await copyFileToDockerContainer({ containerName, dataUri, filename, - toPath, + toPath }); } } @@ -89,11 +77,7 @@ export async function runPackages( await restartDappmanagerPatch({ composePath: pkg.composePath }); return; } else { - await dockerComposeUpPackage( - { dnpName: pkg.dnpName, composePath: pkg.composePath }, - false, - pkg.containersStatus - ); + await dockerComposeUpPackage({ dnpName: pkg.dnpName, composePath: pkg.composePath }, false, pkg.containersStatus); } log(pkg.dnpName, "Package started"); diff --git a/packages/installer/src/installer/writeAndValidateFiles.ts b/packages/installer/src/installer/writeAndValidateFiles.ts index d040a6e74..8ad61238a 100644 --- a/packages/installer/src/installer/writeAndValidateFiles.ts +++ b/packages/installer/src/installer/writeAndValidateFiles.ts @@ -13,19 +13,9 @@ import { isNotFoundError, writeManifest } from "@dappnode/utils"; * Backup the previous compose if exists to .backup.yml * @param packagesData */ -export async function writeAndValidateFiles( - packagesData: InstallPackageData[], - log: Log -): Promise<void> { +export async function writeAndValidateFiles(packagesData: InstallPackageData[], log: Log): Promise<void> { for (const packageData of packagesData) { - const { - dnpName, - composePath, - composeBackupPath, - manifest, - manifestPath, - manifestBackupPath, - } = packageData; + const { dnpName, composePath, composeBackupPath, manifest, manifestPath, manifestBackupPath } = packageData; log(dnpName, "Writing files..."); // Create the repoDir if necessary diff --git a/packages/installer/src/utils.ts b/packages/installer/src/utils.ts index d87dbe346..657bb174f 100644 --- a/packages/installer/src/utils.ts +++ b/packages/installer/src/utils.ts @@ -33,9 +33,7 @@ export function isIpfsHash(hash: string): boolean { * Parses a timeout string and returns a number in seconds * @param timeout "20min", "5", undefined */ -export function parseTimeoutSeconds( - timeout: number | string | undefined -): number | undefined { +export function parseTimeoutSeconds(timeout: number | string | undefined): number | undefined { switch (typeof timeout) { case "number": { return timeout; diff --git a/packages/installer/test/int/dnpLifecycle.test.int.ts b/packages/installer/test/int/dnpLifecycle.test.int.ts index d4ef0f265..5e2a2f692 100644 --- a/packages/installer/test/int/dnpLifecycle.test.int.ts +++ b/packages/installer/test/int/dnpLifecycle.test.int.ts @@ -5,10 +5,7 @@ import { mapValues, pick } from "lodash-es"; import * as calls from "../../../dappmanager/src/calls/index.js"; import { params } from "@dappnode/params"; import { logs } from "@dappnode/logger"; -import { - getDnpFromListPackages, - getDnpState, -} from "../../../dappmanager/test/integration/testPackageUtils.js"; +import { getDnpFromListPackages, getDnpState } from "../../../dappmanager/test/integration/testPackageUtils.js"; import { PortMapping, UserSettingsAllDnps, @@ -17,7 +14,7 @@ import { PortProtocol, Compose, Manifest, - PackageEnvs, + PackageEnvs } from "@dappnode/types"; import { clearDbs, @@ -25,14 +22,10 @@ import { shellSafe, cleanRepos, cleanContainers, - sampleFile, + sampleFile } from "../../../dappmanager/test/testUtils.js"; import { stringifyPortMappings } from "@dappnode/dockercompose"; -import { - dockerContainerInspect, - dockerGetArchiveSingleFile, - listContainer, -} from "@dappnode/dockerapi"; +import { dockerContainerInspect, dockerGetArchiveSingleFile, listContainer } from "@dappnode/dockerapi"; import { parseEnvironment } from "@dappnode/utils"; import { uploadDirectoryRelease } from "./integrationSpecs/index.js"; import { MemoryWritable } from "../../../dappmanager/test/integration/testStreamUtils.js"; @@ -68,21 +61,19 @@ describe("DNP lifecycle", function () { ENV_TO_CHANGE: { key: "ENV_TO_CHANGE", value: "ORIGINAL", - newValue: "NEW_VALUE", + newValue: "NEW_VALUE" }, - ENV_DEFAULT: { key: "ENV_DEFAULT", value: "ORIGINAL" }, + ENV_DEFAULT: { key: "ENV_DEFAULT", value: "ORIGINAL" } }; const envsDep = { ENV_DEP_TO_CHANGE: { key: "ENV_DEP_TO_CHANGE", value: "ORIGINAL_DEP", - newValue: "NEW_VALUE_DEP", + newValue: "NEW_VALUE_DEP" }, - ENV_DEP_DEFAULT: { key: "ENV_DEP_DEFAULT", value: "ORIGINAL_DEP" }, + ENV_DEP_DEFAULT: { key: "ENV_DEP_DEFAULT", value: "ORIGINAL_DEP" } }; - const toEnvironment = (envs: { - [id: string]: { key: string; value: string }; - }): string[] => + const toEnvironment = (envs: { [id: string]: { key: string; value: string } }): string[] => Object.values(envs).map(({ key, value }) => `${key}=${value}`); interface PortMappingWithNew extends PortMapping { @@ -92,9 +83,7 @@ describe("DNP lifecycle", function () { portId: string; } - const addPortId = (obj: { - [id: string]: PortMappingWithNew; - }): { [id: string]: PortMappingForTest } => + const addPortId = (obj: { [id: string]: PortMappingWithNew }): { [id: string]: PortMappingForTest } => mapValues(obj, (p) => ({ ...p, portId: `${p.container}/${p.protocol}` })); const portsMain = addPortId({ // Unchanged @@ -102,22 +91,22 @@ describe("DNP lifecycle", function () { host: 1111, container: 1111, protocol: PortProtocol.UDP, - newHost: 1111, + newHost: 1111 }, // Change from a host port to a different two: { host: 2222, container: 2222, protocol: PortProtocol.TCP, - newHost: 2220, - }, + newHost: 2220 + } }); const volumesMain = { changeme: { name: "changeme-main", newHost: path.resolve(testMountpointDnpLifeCycleMain, "testMountpoint"), - container: "/temp", - }, + container: "/temp" + } }; const portsDep = addPortId({ // Change from ephemeral to a defined host port @@ -125,26 +114,26 @@ describe("DNP lifecycle", function () { host: undefined, container: 3333, protocol: PortProtocol.UDP, - newHost: 3330, + newHost: 3330 }, // Change from a defined host port to ephemeral four: { host: 4444, container: 4444, protocol: PortProtocol.TCP, - newHost: "", - }, + newHost: "" + } }); const volumesDep = { changeme: { name: "changeme-dep", newHost: path.resolve(testMountpointDnpLifeCycleDep, "testBind"), - container: "/temp", - }, + container: "/temp" + } }; const staticVolume = { name: "data", - container: "/usr", + container: "/usr" }; const manifestMain: Manifest = { @@ -152,7 +141,7 @@ describe("DNP lifecycle", function () { description: "Main DNP", type: "service", license: "GPL-3.0", - version: "0.1.0", + version: "0.1.0" }; const composeMain: Compose = { version: "3.5", @@ -163,15 +152,15 @@ describe("DNP lifecycle", function () { environment: toEnvironment(envsMain), volumes: [ `${staticVolume.name}:${staticVolume.container}`, - `${volumesMain.changeme.name}:${volumesMain.changeme.container}`, + `${volumesMain.changeme.name}:${volumesMain.changeme.container}` ], - ports: stringifyPortMappings(Object.values(portsMain)), - }, + ports: stringifyPortMappings(Object.values(portsMain)) + } }, volumes: { [staticVolume.name]: {}, - [volumesMain.changeme.name]: {}, - }, + [volumesMain.changeme.name]: {} + } }; const manifestDep: Manifest = { @@ -179,7 +168,7 @@ describe("DNP lifecycle", function () { description: "Main DNP", type: "service", license: "GPL-3.0", - version: "0.1.0", + version: "0.1.0" }; const composeDep: Compose = { version: "3.5", @@ -190,19 +179,18 @@ describe("DNP lifecycle", function () { environment: toEnvironment(envsDep), volumes: [ `${staticVolume.name}:${staticVolume.container}`, - `${volumesDep.changeme.name}:${volumesDep.changeme.container}`, + `${volumesDep.changeme.name}:${volumesDep.changeme.container}` ], - ports: stringifyPortMappings(Object.values(portsDep)), - }, + ports: stringifyPortMappings(Object.values(portsDep)) + } }, volumes: { [staticVolume.name]: {}, - [volumesDep.changeme.name]: {}, - }, + [volumesDep.changeme.name]: {} + } }; - const toDaraUrl = (s: string): string => - `data:application/json;base64,${Buffer.from(s).toString("base64")}`; + const toDaraUrl = (s: string): string => `data:application/json;base64,${Buffer.from(s).toString("base64")}`; const demoFilePath = "/usr/config.json"; const fileDataUrlMain = toDaraUrl(dnpNameMain); // The content of the test file is the name of the DNP @@ -212,46 +200,46 @@ describe("DNP lifecycle", function () { [dnpNameMain]: { environment: { [dnpNameMain]: { - [envsMain.ENV_TO_CHANGE.key]: envsMain.ENV_TO_CHANGE.newValue, - }, + [envsMain.ENV_TO_CHANGE.key]: envsMain.ENV_TO_CHANGE.newValue + } }, portMappings: { [dnpNameMain]: { - [portsMain.two.portId]: String(portsMain.two.newHost), - }, + [portsMain.two.portId]: String(portsMain.two.newHost) + } }, namedVolumeMountpoints: { - [volumesMain.changeme.name]: volumesMain.changeme.newHost, + [volumesMain.changeme.name]: volumesMain.changeme.newHost }, fileUploads: { [dnpNameMain]: { - [demoFilePath]: fileDataUrlMain, - }, - }, + [demoFilePath]: fileDataUrlMain + } + } }, [dnpNameDep]: { environment: { [dnpNameDep]: { - [envsDep.ENV_DEP_TO_CHANGE.key]: envsDep.ENV_DEP_TO_CHANGE.newValue, - }, + [envsDep.ENV_DEP_TO_CHANGE.key]: envsDep.ENV_DEP_TO_CHANGE.newValue + } }, portMappings: { [dnpNameDep]: { [portsDep.three.portId]: String(portsDep.three.newHost), - [portsDep.four.portId]: String(portsDep.four.newHost), - }, + [portsDep.four.portId]: String(portsDep.four.newHost) + } }, legacyBindVolumes: { [dnpNameDep]: { - [volumesDep.changeme.name]: volumesDep.changeme.newHost, - }, + [volumesDep.changeme.name]: volumesDep.changeme.newHost + } }, fileUploads: { [dnpNameDep]: { - [demoFilePath]: fileDataUrlDep, - }, - }, - }, + [demoFilePath]: fileDataUrlDep + } + } + } }; let mainDnpReleaseHash: string; @@ -278,35 +266,29 @@ describe("DNP lifecycle", function () { await shellSafe("docker network rm dncore_network"); }); - before( - `Preparing releases for ${dnpNameMain} and ${dnpNameDep}`, - async () => { - // Prepare a package release with dependencies - const depDnpReleaseHash = await uploadDirectoryRelease({ - manifest: manifestDep, - compose: composeDep, - }); - mainDnpReleaseHash = await uploadDirectoryRelease({ - manifest: { - ...manifestMain, - dependencies: { [dnpNameDep]: depDnpReleaseHash }, - }, - compose: composeMain, - }); - } - ); + before(`Preparing releases for ${dnpNameMain} and ${dnpNameDep}`, async () => { + // Prepare a package release with dependencies + const depDnpReleaseHash = await uploadDirectoryRelease({ + manifest: manifestDep, + compose: composeDep + }); + mainDnpReleaseHash = await uploadDirectoryRelease({ + manifest: { + ...manifestMain, + dependencies: { [dnpNameDep]: depDnpReleaseHash } + }, + compose: composeMain + }); + }); before("Should resolve a request", async () => { const result = await calls.fetchDnpRequest({ - id: mainDnpReleaseHash, + id: mainDnpReleaseHash }); console.log(result); expect(result.dnpName, "Wrong result name").to.equal(dnpNameMain); expect(result.compatible, "Result is not compatible").to.be.ok; - expect( - result.compatible.dnps, - "Resolved state should include this dnp" - ).to.have.property(dnpNameMain); + expect(result.compatible.dnps, "Resolved state should include this dnp").to.have.property(dnpNameMain); }); before("Should install DNP", async () => { @@ -314,7 +296,7 @@ describe("DNP lifecycle", function () { name: dnpNameMain, version: mainDnpReleaseHash, userSettings, - options: { BYPASS_SIGNED_RESTRICTION: true }, + options: { BYPASS_SIGNED_RESTRICTION: true } }); }); @@ -343,38 +325,32 @@ describe("DNP lifecycle", function () { { containerName: containerMain.containerName }, { [envsMain.ENV_TO_CHANGE.key]: envsMain.ENV_TO_CHANGE.newValue, - [envsMain.ENV_DEFAULT.key]: envsMain.ENV_DEFAULT.value, + [envsMain.ENV_DEFAULT.key]: envsMain.ENV_DEFAULT.value } ); }); it(`${dnpNameMain} port mappings`, () => { - const port1111 = containerMain.ports.find( - (port) => port.container === portsMain.one.container - ); - const port2222 = containerMain.ports.find( - (port) => port.container === portsMain.two.container - ); + const port1111 = containerMain.ports.find((port) => port.container === portsMain.one.container); + const port2222 = containerMain.ports.find((port) => port.container === portsMain.two.container); if (!port1111) throw Error(`Port 1111 not found`); if (!port2222) throw Error(`Port 2222 not found`); expect(port1111).to.deep.equal({ host: portsMain.one.host, container: portsMain.one.container, protocol: portsMain.one.protocol, - deletable: false, + deletable: false }); expect(port2222).to.deep.equal({ host: portsMain.two.newHost, container: portsMain.two.container, protocol: portsMain.two.protocol, - deletable: false, + deletable: false }); }); it(`${dnpNameMain} name volume paths`, () => { - const changemeVolume = containerMain.volumes.find( - (vol) => vol.container === volumesMain.changeme.container - ); + const changemeVolume = containerMain.volumes.find((vol) => vol.container === volumesMain.changeme.container); if (!changemeVolume) throw Error(`Volume changeme not found`); // Using this particular type of bind, the volume path in docker inspect @@ -390,7 +366,7 @@ describe("DNP lifecycle", function () { it(`${dnpNameMain} fileuploads`, async () => { const result = await copyFileFrom({ containerName: containerMain.containerName, - fromPath: demoFilePath, + fromPath: demoFilePath }); expect(toDaraUrl(result)).to.equal(fileDataUrlMain); }); @@ -400,20 +376,16 @@ describe("DNP lifecycle", function () { { containerName: containerDep.containerName }, { [envsDep.ENV_DEP_TO_CHANGE.key]: envsDep.ENV_DEP_TO_CHANGE.newValue, - [envsDep.ENV_DEP_DEFAULT.key]: envsDep.ENV_DEP_DEFAULT.value, + [envsDep.ENV_DEP_DEFAULT.key]: envsDep.ENV_DEP_DEFAULT.value } ); }); it(`${dnpNameDep} port mappings`, () => { // Change from ephemeral to a defined host port - const port3333 = containerDep.ports.find( - (port) => port.container === portsDep.three.container - ); + const port3333 = containerDep.ports.find((port) => port.container === portsDep.three.container); // Change from a defined host port to ephemeral - const port4444 = containerDep.ports.find( - (port) => port.container === portsDep.four.container - ); + const port4444 = containerDep.ports.find((port) => port.container === portsDep.four.container); // Make sure port 4444 is ephemeral if (!port4444) throw Error(`Port 4444 not found`); @@ -425,9 +397,7 @@ describe("DNP lifecycle", function () { }); it(`${dnpNameDep} name volume paths`, () => { - const changemeVolume = containerDep.volumes.find( - (vol) => vol.container === volumesDep.changeme.container - ); + const changemeVolume = containerDep.volumes.find((vol) => vol.container === volumesDep.changeme.container); if (!changemeVolume) throw Error(`Volume changeme not found`); expect(changemeVolume.host).to.equal(volumesDep.changeme.newHost); }); @@ -435,7 +405,7 @@ describe("DNP lifecycle", function () { it(`${dnpNameDep} fileuploads`, async () => { const result = await copyFileFrom({ containerName: containerDep.containerName, - fromPath: demoFilePath, + fromPath: demoFilePath }); expect(toDaraUrl(result)).to.equal(fileDataUrlDep); }); @@ -459,14 +429,14 @@ describe("DNP lifecycle", function () { it(`Should call logPackage for ${dnpNameMain}`, async () => { const result = await calls.packageLog({ - containerName: containerMain.containerName, + containerName: containerMain.containerName }); expect(result).to.be.a("string"); }); it(`Should call logPackage for ${dnpNameDep}`, async () => { const result = await calls.packageLog({ - containerName: containerDep.containerName, + containerName: containerDep.containerName }); expect(result).to.be.a("string"); }); @@ -484,52 +454,45 @@ describe("DNP lifecycle", function () { it("Should update DNP envs and reset", async () => { const dnpPrevEnvs = await getContainerEnvironment({ - containerName: containerMain.containerName, + containerName: containerMain.containerName }); // Use randomize value, different on each run const envValue = String(Date.now()); await calls.packageSetEnvironment({ dnpName: dnpNameMain, - environmentByService: { [dnpNameMain]: { time: envValue } }, + environmentByService: { [dnpNameMain]: { time: envValue } } }); const dnpNextEnvs = await getContainerEnvironment({ - containerName: containerMain.containerName, + containerName: containerMain.containerName }); - expect( - pick(dnpNextEnvs, ["time", ...Object.keys(dnpPrevEnvs)]) - ).to.deep.equal({ + expect(pick(dnpNextEnvs, ["time", ...Object.keys(dnpPrevEnvs)])).to.deep.equal({ ...dnpPrevEnvs, - time: envValue, + time: envValue }); }); it(`Should update the port mappings of ${dnpNameMain}`, async () => { const portNumber = 13131; const protocol = PortProtocol.TCP; - const portMappings: PortMapping[] = [ - { host: portNumber, container: portNumber, protocol }, - ]; + const portMappings: PortMapping[] = [{ host: portNumber, container: portNumber, protocol }]; await calls.packageSetPortMappings({ dnpName: dnpNameMain, - portMappingsByService: { [dnpNameMain]: portMappings }, + portMappingsByService: { [dnpNameMain]: portMappings } }); const dnp = await getDnpFromListPackages(dnpNameMain); if (!dnp) throw Error(`${dnpNameMain} is not found running`); - const addedPort = dnp.containers[0].ports.find( - (p) => p.container === portNumber - ); - if (!addedPort) - throw Error(`Added port on ${portNumber} ${protocol} not found`); + const addedPort = dnp.containers[0].ports.find((p) => p.container === portNumber); + if (!addedPort) throw Error(`Added port on ${portNumber} ${protocol} not found`); expect(addedPort).to.deep.equal({ host: portNumber, container: portNumber, protocol, - deletable: true, + deletable: true }); }); }); @@ -597,7 +560,7 @@ describe("DNP lifecycle", function () { containerName: containerMain.containerName, dataUri: sampleFile.dataUri, filename: sampleFile.filename, - toPath: sampleFile.containerPath, + toPath: sampleFile.containerPath }); }); @@ -605,7 +568,7 @@ describe("DNP lifecycle", function () { it("Should copy the file FROM the container", async () => { const result = await copyFileFrom({ containerName: containerMain.containerName, - fromPath: sampleFile.containerPath, + fromPath: sampleFile.containerPath }); expect(toDaraUrl(result)).to.equal(sampleFile.dataUri, "Wrong dataUri"); }); @@ -654,11 +617,7 @@ describe("DNP lifecycle", function () { * Note: Likely to include additional ENVs from the ones defined in the compose * @param containerNameOrId */ -async function getContainerEnvironment({ - containerName, -}: { - containerName: string; -}): Promise<PackageEnvs> { +async function getContainerEnvironment({ containerName }: { containerName: string }): Promise<PackageEnvs> { const container = await listContainer({ containerName }); const containerData = await dockerContainerInspect(container.containerId); return parseEnvironment(containerData.Config.Env); @@ -680,13 +639,7 @@ async function assertEnvironment( * @param containerName * @param filepath */ -async function copyFileFrom({ - containerName, - fromPath, -}: { - containerName: string; - fromPath: string; -}): Promise<string> { +async function copyFileFrom({ containerName, fromPath }: { containerName: string; fromPath: string }): Promise<string> { const sink = new MemoryWritable<Buffer>(); await dockerGetArchiveSingleFile(containerName, fromPath, sink); diff --git a/packages/installer/test/int/fetchRelease.test.int.ts b/packages/installer/test/int/fetchRelease.test.int.ts index b469023bc..5965a43cc 100644 --- a/packages/installer/test/int/fetchRelease.test.int.ts +++ b/packages/installer/test/int/fetchRelease.test.int.ts @@ -7,19 +7,13 @@ import { createTestDir, cleanRepos, cleanContainers, - shellSafe, + shellSafe } from "../../../dappmanager/test/testUtils.js"; import { uploadDirectoryRelease } from "./integrationSpecs/index.js"; import { dockerComposeUp } from "@dappnode/dockerapi"; import { ComposeEditor } from "@dappnode/dockercompose"; import { validatePath } from "@dappnode/utils"; -import { - RequestedDnp, - Manifest, - SetupWizard, - getContainerName, - getImageTag, -} from "@dappnode/types"; +import { RequestedDnp, Manifest, SetupWizard, getContainerName, getImageTag } from "@dappnode/types"; describe("Fetch releases", () => { const dnpNameMain = "main.dnp.dappnode.eth"; @@ -57,7 +51,7 @@ describe("Fetch releases", () => { description: "Main DNP", license: "GPL-3.0", type: "service", - avatar: "/ipfs/QmNrfF93ppvjDGeabQH8H8eeCDLci2F8fptkvj94WN78pt", + avatar: "/ipfs/QmNrfF93ppvjDGeabQH8H8eeCDLci2F8fptkvj94WN78pt" }; const composeMain = new ComposeEditor({ @@ -67,15 +61,15 @@ describe("Fetch releases", () => { container_name: getContainerName({ dnpName: dnpNameMain, serviceName: dnpNameMain, - isCore: false, + isCore: false }), image: getImageTag({ dnpName: dnpNameMain, serviceName: dnpNameMain, - version: mainVersion, - }), - }, - }, + version: mainVersion + }) + } + } }); const setupWizard: SetupWizard = { @@ -85,9 +79,9 @@ describe("Fetch releases", () => { id: "mockVar", target: { type: "environment", name: "MOCK_VAR" }, title: "Mock var", - description: "Mock var description", - }, - ], + description: "Mock var description" + } + ] }; const disclaimer = "Warning!\n\nThis is really dangerous"; @@ -98,7 +92,7 @@ describe("Fetch releases", () => { manifest: mainDnpManifest, compose: composeMain.output(), setupWizard, - disclaimer, + disclaimer }); // Up mock docker packages @@ -123,8 +117,8 @@ describe("Fetch releases", () => { version: mainVersion, type: "service", disclaimer: { - message: disclaimer, - }, + message: disclaimer + } }, specialPermissions: { [dnpNameMain]: [] }, @@ -134,7 +128,7 @@ describe("Fetch releases", () => { isUpdated: false, isInstalled: true, settings: { - [dnpNameMain]: {}, + [dnpNameMain]: {} }, compatible: { requiresDockerUpdate: false, @@ -144,24 +138,22 @@ describe("Fetch releases", () => { isCompatible: true, error: "", dnps: { - [dnpNameMain]: { from: mainVersion, to: mainDnpReleaseHash }, - }, + [dnpNameMain]: { from: mainVersion, to: mainDnpReleaseHash } + } }, available: { isAvailable: true, - message: "", + message: "" }, // Mock, ommited below imageSize: 0, signedSafeAll: false, signedSafe: { - [dnpNameMain]: { safe: false, message: "Unsafe origin, not signed" }, - }, + [dnpNameMain]: { safe: false, message: "Unsafe origin, not signed" } + } }; - expect(omit(result, ["imageSize"])).to.deep.equal( - omit(expectRequestDnp, ["imageSize"]) - ); + expect(omit(result, ["imageSize"])).to.deep.equal(omit(expectRequestDnp, ["imageSize"])); after(async () => { await shellSafe(`docker compose -f ${composePathMain} down -v`); diff --git a/packages/installer/test/int/integrationSpecs/buildReleaseDirectory.ts b/packages/installer/test/int/integrationSpecs/buildReleaseDirectory.ts index e97dcc201..7f3b597eb 100644 --- a/packages/installer/test/int/integrationSpecs/buildReleaseDirectory.ts +++ b/packages/installer/test/int/integrationSpecs/buildReleaseDirectory.ts @@ -5,18 +5,8 @@ import { mapValues } from "lodash-es"; import { shell } from "@dappnode/utils"; import { yamlDump } from "@dappnode/utils"; import { getContainerName, getImageTag } from "@dappnode/utils"; -import { - Manifest, - Compose, - SetupWizard, - ComposeService, -} from "@dappnode/types"; -import { - testDir, - manifestFileName, - composeFileName, - ipfs, -} from "../../testUtils.js"; +import { Manifest, Compose, SetupWizard, ComposeService } from "@dappnode/types"; +import { testDir, manifestFileName, composeFileName, ipfs } from "../../testUtils.js"; import { ipfsAddAll } from "../../testUtils.js"; import { saveNewImageToDisk } from "./mockImage.js"; import { saveMockAvatarTo } from "./mockAvatar.js"; @@ -44,7 +34,7 @@ export async function uploadDirectoryRelease({ compose, setupWizard, disclaimer, - signReleaseWithPrivKey, + signReleaseWithPrivKey }: { manifest: Manifest; compose: ComposeUncomplete; @@ -56,20 +46,15 @@ export async function uploadDirectoryRelease({ await shell(`rm -rf ${releaseDir}`); // Clean dir before populating fs.mkdirSync(releaseDir, { recursive: true }); - const writeAsset = (fileName: string, data: string): void => - fs.writeFileSync(path.join(releaseDir, fileName), data); - const writeJson = <T>(fileName: string, jsonData: T): void => - writeAsset(fileName, JSON.stringify(jsonData, null, 2)); + const writeAsset = (fileName: string, data: string): void => fs.writeFileSync(path.join(releaseDir, fileName), data); + const writeJson = <T>(fileName: string, jsonData: T): void => writeAsset(fileName, JSON.stringify(jsonData, null, 2)); writeJson(manifestFileName, manifest); // Manifest writeAsset(composeFileName, yamlDump(completeCompose(compose, manifest))); // Compose saveMockAvatarTo(path.join(releaseDir, "avatar.png")); // Avatar // const filesToUpload = [manifestFileNoImage, composeFile, imageFile]; const serviceNames = Object.keys(compose.services); - await saveNewImageToDisk( - { dnpName: manifest.name, version: manifest.version, serviceNames }, - releaseDir - ); + await saveNewImageToDisk({ dnpName: manifest.name, version: manifest.version, serviceNames }, releaseDir); // Other optional files if (setupWizard) writeJson("setup-wizard.json", setupWizard); @@ -86,8 +71,7 @@ export async function uploadDirectoryRelease({ filesNames.push(file.name); } for (const fileToCheck of [manifestFileName, composeFileName]) - if (!filesNames.includes(fileToCheck)) - throw Error(`No ${fileToCheck} uploaded`); + if (!filesNames.includes(fileToCheck)) throw Error(`No ${fileToCheck} uploaded`); if (signReleaseWithPrivKey) { const wallet = new ethers.Wallet(signReleaseWithPrivKey); @@ -101,10 +85,7 @@ export async function uploadDirectoryRelease({ * Utility to write valid compose files * prevents having to write valid container_name, image per service */ -export function completeCompose( - composeUncomplete: ComposeUncomplete, - manifest: Manifest -): Compose { +export function completeCompose(composeUncomplete: ComposeUncomplete, manifest: Manifest): Compose { const dnpName = manifest.name; const version = manifest.version; const isCore = manifest.type === "dncore"; @@ -113,7 +94,7 @@ export function completeCompose( services: mapValues(composeUncomplete.services, (service, serviceName) => ({ container_name: getContainerName({ dnpName, serviceName, isCore }), image: getImageTag({ dnpName, serviceName, version }), - ...service, - })), + ...service + })) }; } diff --git a/packages/installer/test/int/integrationSpecs/mockImage.ts b/packages/installer/test/int/integrationSpecs/mockImage.ts index 828ee6abd..f1b1a5782 100644 --- a/packages/installer/test/int/integrationSpecs/mockImage.ts +++ b/packages/installer/test/int/integrationSpecs/mockImage.ts @@ -4,9 +4,7 @@ import { shell } from "@dappnode/utils"; import { fileURLToPath } from "url"; import { validatePath, getImageTag } from "@dappnode/utils"; -const dockerContextPath = path.resolve( - path.dirname(fileURLToPath(import.meta.url)) -); +const dockerContextPath = path.resolve(path.dirname(fileURLToPath(import.meta.url))); const imageTag = "mocktest-dappnode-test-image:0.0.0"; export const mockImageEnvNAME = "NAME"; @@ -29,26 +27,16 @@ export async function buildMockImage(): Promise<string> { * @returns "mock-test.public.dappnode.eth_0.0.1.tar.xz" */ export async function saveNewImageToDisk( - { - dnpName, - version, - serviceNames - }: { dnpName: string; version: string; serviceNames: string[] }, + { dnpName, version, serviceNames }: { dnpName: string; version: string; serviceNames: string[] }, dirToSaveTo: string = testDir ): Promise<string> { const imageTag = await buildMockImage(); if (!serviceNames) serviceNames = [dnpName]; - const newImageTags = serviceNames.map(serviceName => - getImageTag({ dnpName, serviceName, version }) - ); - for (const newImageTag of newImageTags) - await shell(["docker", "tag", imageTag, newImageTag]); + const newImageTags = serviceNames.map((serviceName) => getImageTag({ dnpName, serviceName, version })); + for (const newImageTag of newImageTags) await shell(["docker", "tag", imageTag, newImageTag]); - const newImagePath = path.resolve( - dirToSaveTo, - `${dnpName}_${version}.tar.xz` - ); + const newImagePath = path.resolve(dirToSaveTo, `${dnpName}_${version}.tar.xz`); validatePath(newImagePath); await shell(`docker save ${newImageTags.join(" ")} | xz > ${newImagePath}`); diff --git a/packages/installer/test/int/integrationSpecs/signRelease.ts b/packages/installer/test/int/integrationSpecs/signRelease.ts index e94a9e54e..c71dfd4f7 100644 --- a/packages/installer/test/int/integrationSpecs/signRelease.ts +++ b/packages/installer/test/int/integrationSpecs/signRelease.ts @@ -7,10 +7,7 @@ import { CID } from "kubo-rpc-client"; const signatureFilename = "signature.json"; -export async function signRelease( - wallet: ethers.Wallet, - dnpReleaseHash: string -): Promise<string> { +export async function signRelease(wallet: ethers.Wallet, dnpReleaseHash: string): Promise<string> { const releaseFiles = await dappnodeInstaller.list(dnpReleaseHash); const cidOpts: ReleaseSignature["cid"] = { version: 0, base: "base58btc" }; @@ -22,21 +19,19 @@ export async function signRelease( version: 1, cid: cidOpts, signature_protocol: "ECDSA_256", - signature: flatSig, + signature: flatSig }; const signatureIpfsEntry = await ipfs.add(JSON.stringify(signature, null, 2)); - const getRes: IpfsDagGetResult<IpfsDagPbValue> = await ipfs.dag.get( - CID.parse(dnpReleaseHash) - ); + const getRes: IpfsDagGetResult<IpfsDagPbValue> = await ipfs.dag.get(CID.parse(dnpReleaseHash)); // Mutate dag-pb value appending a new Link // TODO: What happens if the block becomes too big getRes.value.Links.push({ Hash: signatureIpfsEntry.cid, Name: signatureFilename, - Tsize: signatureIpfsEntry.size, + Tsize: signatureIpfsEntry.size }); // DAG-PB form (links must be sorted by Name bytes) @@ -44,7 +39,7 @@ export async function signRelease( const newReleaseCid = await ipfs.dag.put(getRes.value, { storeCodec: "dag-pb", - hashAlg: "sha2-256", + hashAlg: "sha2-256" }); // Validate that the new release hash contains all previous files + signature @@ -54,14 +49,9 @@ export async function signRelease( dirFilesNames.push(file.name); } const filesNamesStr = serializeDir(dirFilesNames); - const expectedFns = serializeDir([ - ...releaseFiles.map((file) => file.name), - signatureFilename, - ]); + const expectedFns = serializeDir([...releaseFiles.map((file) => file.name), signatureFilename]); if (filesNamesStr !== expectedFns) { - throw Error( - `Wrong files in new release: ${filesNamesStr} - expected: ${expectedFns}` - ); + throw Error(`Wrong files in new release: ${filesNamesStr} - expected: ${expectedFns}`); } return newReleaseCid.toV0().toString(); diff --git a/packages/installer/test/int/integrationSpecs/testReleaseUtils.ts b/packages/installer/test/int/integrationSpecs/testReleaseUtils.ts index c6c9cc8a4..0adcfeed8 100644 --- a/packages/installer/test/int/integrationSpecs/testReleaseUtils.ts +++ b/packages/installer/test/int/integrationSpecs/testReleaseUtils.ts @@ -1,18 +1,14 @@ import { cleanRepos } from "../../testUtils.js"; import { shell } from "@dappnode/utils"; -export async function cleanInstallationArtifacts( - partialContainerName: string -): Promise<void> { +export async function cleanInstallationArtifacts(partialContainerName: string): Promise<void> { await cleanRepos(); - const containersToKill = await shell( - `docker ps -f name=${partialContainerName} -aq` - ); + const containersToKill = await shell(`docker ps -f name=${partialContainerName} -aq`); // Kill one by one. Otherwise if container 1 errors, the rest won't be deleted for (const containerToKill of containersToKill.trim().split(/\s+/)) if (containerToKill) - await shell(`docker rm -v -f ${containerToKill}`).catch(e => { + await shell(`docker rm -v -f ${containerToKill}`).catch((e) => { console.warn(`Error cleaning container ${containerToKill}`, e); }); } diff --git a/packages/installer/test/int/releaseFormat.test.int.ts b/packages/installer/test/int/releaseFormat.test.int.ts index ab0b318f7..c53a3c88e 100644 --- a/packages/installer/test/int/releaseFormat.test.int.ts +++ b/packages/installer/test/int/releaseFormat.test.int.ts @@ -2,18 +2,11 @@ import "mocha"; import { expect } from "chai"; import { mapValues } from "lodash-es"; import * as calls from "../../../dappmanager/src/calls/index.js"; -import { - createTestDir, - beforeAndAfter, - cleanTestDir, -} from "../../../dappmanager/test/testUtils.js"; +import { createTestDir, beforeAndAfter, cleanTestDir } from "../../../dappmanager/test/testUtils.js"; import { params } from "@dappnode/params"; import { shell } from "@dappnode/utils"; import { TrustedReleaseKey } from "@dappnode/types"; -import { - cleanInstallationArtifacts, - uploadDirectoryRelease, -} from "./integrationSpecs/index.js"; +import { cleanInstallationArtifacts, uploadDirectoryRelease } from "./integrationSpecs/index.js"; import * as db from "@dappnode/db"; import { mockImageEnvNAME } from "./integrationSpecs/mockImage.js"; @@ -40,9 +33,7 @@ describe("Release format tests", () => { // The mockImage used for this test will print to stdout the value // of the env `mockImageEnvNAME`. It will be used to assert that the // package is running correctly - const mockEnvs = (expectedValue: string): string[] => [ - [mockImageEnvNAME, expectedValue].join("="), - ]; + const mockEnvs = (expectedValue: string): string[] => [[mockImageEnvNAME, expectedValue].join("=")]; interface TestCase { id: string; @@ -70,18 +61,18 @@ describe("Release format tests", () => { version: version, type: "service", license: "GPL-3.0", - description: "mock-test description", + description: "mock-test description" }, compose: { version: "3.5", services: { [dnpName]: { restart: "unless-stopped", - environment: mockEnvs(expectedEnvValue), - }, - }, - }, - }), + environment: mockEnvs(expectedEnvValue) + } + } + } + }) }; }, @@ -89,9 +80,7 @@ describe("Release format tests", () => { const dnpName = testMockPrefix + "multi-service.dnp.dappnode.eth"; const version = "0.3.0"; const serviceNames = { frontend: "frontend", backend: "backend" }; - const expectedEnvValues = mapValues(serviceNames, (value) => - [value, dnpName].join(".") - ); + const expectedEnvValues = mapValues(serviceNames, (value) => [value, dnpName].join(".")); return { id: "Multi-service-type", dnpName, @@ -104,29 +93,28 @@ describe("Release format tests", () => { version: version, type: "service", license: "GPL-3.0", - description: "mock-test description", + description: "mock-test description" }, compose: { version: "3.5", services: { [serviceNames.frontend]: { restart: "unless-stopped", - environment: mockEnvs(expectedEnvValues.frontend), + environment: mockEnvs(expectedEnvValues.frontend) }, [serviceNames.backend]: { restart: "unless-stopped", - environment: mockEnvs(expectedEnvValues.backend), - }, - }, - }, - }), + environment: mockEnvs(expectedEnvValues.backend) + } + } + } + }) }; }, (): TestCase => { // Sign the string message - const privateKey = - "0x0123456789012345678901234567890123456789012345678901234567890123"; + const privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123"; const pubkey = "0x14791697260E4c9A71f18484C9f997B308e59325"; const dnpName = testMockPrefix + "directory.dnp.dappnode.eth"; @@ -142,7 +130,7 @@ describe("Release format tests", () => { name: "Test key", signatureProtocol: "ECDSA_256", dnpNameSuffix: ".dnp.dappnode.eth", - key: pubkey, + key: pubkey }, prepareRelease: async (): Promise<string> => uploadDirectoryRelease({ @@ -151,40 +139,31 @@ describe("Release format tests", () => { version: version, type: "service", license: "GPL-3.0", - description: "mock-test description", + description: "mock-test description" }, compose: { version: "3.5", services: { [dnpName]: { restart: "unless-stopped", - environment: mockEnvs(expectedEnvValue), - }, - }, + environment: mockEnvs(expectedEnvValue) + } + } }, - signReleaseWithPrivKey: privateKey, - }), + signReleaseWithPrivKey: privateKey + }) }; - }, + } ]; before("Create DAppNode docker network", async () => { const dncoreNetwork = params.DOCKER_PRIVATE_NETWORK_NAME; - const networkExists = await shell( - `docker network ls --filter name=${dncoreNetwork} -q` - ); + const networkExists = await shell(`docker network ls --filter name=${dncoreNetwork} -q`); if (!networkExists) await shell(`docker network create ${dncoreNetwork}`); }); for (const releaseTest of releaseTests) { - const { - id, - dnpName, - version, - prepareRelease, - expectedEnvValues, - trustedReleaseKey, - } = releaseTest(); + const { id, dnpName, version, prepareRelease, expectedEnvValues, trustedReleaseKey } = releaseTest(); describe(id, () => { let releaseHash: string; @@ -214,8 +193,7 @@ describe("Release format tests", () => { if (trustedReleaseKey) { // Persist trustedPubkey to local db const trustedKeysAdded = db.releaseKeysTrusted.get(); - if (!trustedKeysAdded.includes(trustedReleaseKey)) - await calls.releaseTrustedKeyAdd(trustedReleaseKey); + if (!trustedKeysAdded.includes(trustedReleaseKey)) await calls.releaseTrustedKeyAdd(trustedReleaseKey); } await calls.packageInstall({ @@ -224,8 +202,8 @@ describe("Release format tests", () => { // userSetEnvs: { [releaseDnpName]: { NAME: nameEnv } } options: { // Only bypass signed restriction if no release key is specified - BYPASS_SIGNED_RESTRICTION: trustedReleaseKey === undefined, - }, + BYPASS_SIGNED_RESTRICTION: trustedReleaseKey === undefined + } }); // Verify it is running correctly @@ -233,22 +211,14 @@ describe("Release format tests", () => { const dnp = dnps.find((d) => d.dnpName === dnpName); if (!dnp) throw Error(`DNP ${dnpName} not found`); - for (const [serviceName, expectedEnvValue] of Object.entries( - expectedEnvValues - )) { - const container = dnp.containers.find( - (c) => c.serviceName === serviceName - ); - if (!container) - throw Error(`No service found for ${serviceName} ${dnpName}`); + for (const [serviceName, expectedEnvValue] of Object.entries(expectedEnvValues)) { + const container = dnp.containers.find((c) => c.serviceName === serviceName); + if (!container) throw Error(`No service found for ${serviceName} ${dnpName}`); // The mockImage used for this test will print to stdout the value of an ENV // It is used to assert that the package is running correctly const result = await calls.packageLog(container); - expect(result).to.include( - expectedEnvValue, - `Wrong log from ${serviceName} ${dnpName} after installation` - ); + expect(result).to.include(expectedEnvValue, `Wrong log from ${serviceName} ${dnpName} after installation`); } }); }); diff --git a/packages/installer/test/int/signedRelease.test.int.ts b/packages/installer/test/int/signedRelease.test.int.ts index c5298475d..de34046ca 100644 --- a/packages/installer/test/int/signedRelease.test.int.ts +++ b/packages/installer/test/int/signedRelease.test.int.ts @@ -8,8 +8,7 @@ import { uploadDirectoryRelease } from "./integrationSpecs/index.js"; import { signRelease } from "./integrationSpecs/signRelease.js"; // Sign the string message -const privateKey = - "0x0111111111111111111111111111111111111111111111111111111111111111"; +const privateKey = "0x0111111111111111111111111111111111111111111111111111111111111111"; describe("Sign release", () => { it("Sign uploaded release", async () => { @@ -21,7 +20,7 @@ describe("Sign release", () => { version, description: "Main DNP", type: "service", - license: "GPL-3.0", + license: "GPL-3.0" }; const composeMain = new ComposeEditor({ @@ -31,21 +30,21 @@ describe("Sign release", () => { container_name: getContainerName({ dnpName: dnpName, serviceName: dnpName, - isCore: false, + isCore: false }), image: getImageTag({ dnpName: dnpName, serviceName: dnpName, - version, - }), - }, - }, + version + }) + } + } }); // Create release const dnpReleaseHash = await uploadDirectoryRelease({ manifest: mainDnpManifest, - compose: composeMain.output(), + compose: composeMain.output() }); const wallet = new ethers.Wallet(privateKey); @@ -56,7 +55,7 @@ describe("Sign release", () => { const expectedSignatureStatus: typeof mainRelease.signatureStatus = { status: ReleaseSignatureStatusCode.signedByUnknownKey, signatureProtocol: "ECDSA_256", - key: wallet.address, + key: wallet.address }; expect(mainRelease.signatureStatus).to.deep.equal(expectedSignatureStatus); }); diff --git a/packages/installer/test/testUtils.ts b/packages/installer/test/testUtils.ts index 1b31c29d4..46cafa843 100644 --- a/packages/installer/test/testUtils.ts +++ b/packages/installer/test/testUtils.ts @@ -4,7 +4,7 @@ import { InstallPackageData, PackageRelease, Compose, - ReleaseSignatureStatusCode, + ReleaseSignatureStatusCode } from "@dappnode/types"; import { DappnodeInstaller } from "../src/dappnodeInstaller.js"; import { params } from "@dappnode/params"; @@ -18,7 +18,7 @@ import { ethers } from "ethers"; // TODO setup a local ipfs node for these tests export const ipfs = create({ - url: "https://api.ipfs.dappnode.io", + url: "https://api.ipfs.dappnode.io" }); /** @@ -28,12 +28,11 @@ export const ipfs = create({ * @returns */ export async function ipfsAddAll(dirPath: string): Promise<unknown[]> { - if (!fs.existsSync(dirPath)) - throw Error(`ipfsAddAll error: no file found at: ${dirPath}`); + if (!fs.existsSync(dirPath)) throw Error(`ipfsAddAll error: no file found at: ${dirPath}`); const files = fs.readdirSync(dirPath).map((file) => { return { path: path.join(dirPath, file), - content: fs.readFileSync(path.join(dirPath, file)), + content: fs.readFileSync(path.join(dirPath, file)) }; }); return all(ipfs.addAll(files)); @@ -41,9 +40,7 @@ export async function ipfsAddAll(dirPath: string): Promise<unknown[]> { export const dappnodeInstaller = new DappnodeInstaller( "https://api.ipfs.dappnode.io", - new ethers.JsonRpcProvider( - `https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}` - ) + new ethers.JsonRpcProvider(`https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}`) ); export const testDir = "./test_files/"; @@ -79,7 +76,7 @@ export const mockContainer: PackageContainer = { defaultVolumes: [], dependencies: {}, origin: "", - avatarUrl: "", + avatarUrl: "" }; export const mockDnp: InstalledPackageData = { @@ -91,7 +88,7 @@ export const mockDnp: InstalledPackageData = { dependencies: {}, origin: "", avatarUrl: "", - containers: [mockContainer], + containers: [mockContainer] }; export const mockCompose: Compose = { @@ -99,9 +96,9 @@ export const mockCompose: Compose = { services: { [mockDnpName]: { image: `${mockDnpName}:${mockDnpVersion}`, - container_name: `DAppNodePackage-${mockDnpName}`, - }, - }, + container_name: `DAppNodePackage-${mockDnpName}` + } + } }; export const mockRelease: PackageRelease = { @@ -115,7 +112,7 @@ export const mockRelease: PackageRelease = { warnings: {}, isCore: false, signedSafe: true, - signatureStatus: { status: ReleaseSignatureStatusCode.notSigned }, + signatureStatus: { status: ReleaseSignatureStatusCode.notSigned } }; export const mockPackageData: InstallPackageData = { @@ -127,7 +124,7 @@ export const mockPackageData: InstallPackageData = { manifestPath: "mock/path/manifest.json", manifestBackupPath: "mock/path/manifest.backup.json", dockerTimeout: undefined, - containersStatus: {}, + containersStatus: {} }; export async function cleanRepos(): Promise<void> { diff --git a/packages/installer/test/unit/calls/sortPackages.test.ts b/packages/installer/test/unit/calls/sortPackages.test.ts index 955b66dd5..2fed8c2ad 100644 --- a/packages/installer/test/unit/calls/sortPackages.test.ts +++ b/packages/installer/test/unit/calls/sortPackages.test.ts @@ -8,16 +8,16 @@ describe("sortPackages for UI display", () => { const sampleDnps: MockDnp[] = [ { dnpName: "b", - containers: [], + containers: [] }, { dnpName: "a", containers: [ { serviceName: "c", isMain: false }, { serviceName: "b", isMain: true }, - { serviceName: "a", isMain: false }, - ], - }, + { serviceName: "a", isMain: false } + ] + } ]; const expectedSortedDnps: MockDnp[] = [ @@ -26,13 +26,13 @@ describe("sortPackages for UI display", () => { containers: [ { serviceName: "b", isMain: true }, { serviceName: "a", isMain: false }, - { serviceName: "c", isMain: false }, - ], + { serviceName: "c", isMain: false } + ] }, { dnpName: "b", - containers: [], - }, + containers: [] + } ]; const sortedDnps = sortPackages(fromSampleDnps(sampleDnps)); @@ -53,8 +53,8 @@ describe("sortPackages for UI display", () => { ...dnp, containers: dnp.containers.map((container) => ({ ...mockContainer, - ...container, - })), + ...container + })) })); } @@ -63,8 +63,8 @@ describe("sortPackages for UI display", () => { dnpName: dnp.dnpName, containers: dnp.containers.map((container) => ({ serviceName: container.serviceName, - isMain: container.isMain ?? false, - })), + isMain: container.isMain ?? false + })) })); } }); diff --git a/packages/installer/test/unit/dappGet/aggregate/aggregateDependencies.test.ts b/packages/installer/test/unit/dappGet/aggregate/aggregateDependencies.test.ts index 4079afe37..34cf1c1e9 100644 --- a/packages/installer/test/unit/dappGet/aggregate/aggregateDependencies.test.ts +++ b/packages/installer/test/unit/dappGet/aggregate/aggregateDependencies.test.ts @@ -32,14 +32,14 @@ describe("dappGet/aggregate/aggregateDependencies", () => { "0.1.1": { "dependency.dnp.dappnode.eth": "^0.1.1" }, "0.1.2": { "dependency.dnp.dappnode.eth": "^0.1.1" }, "0.2.0": { "dependency.dnp.dappnode.eth": "^0.1.1" }, - "0.2.1": { "dependency.dnp.dappnode.eth": "^0.1.1" }, + "0.2.1": { "dependency.dnp.dappnode.eth": "^0.1.1" } }, "dependency.dnp.dappnode.eth": { "0.1.0": {}, "0.1.1": {}, "0.1.2": {}, - "0.2.0": {}, - }, + "0.2.0": {} + } }; const dappGetFetcher = new DappGetFetcherMock(mockDnps); @@ -52,35 +52,35 @@ describe("dappGet/aggregate/aggregateDependencies", () => { name: dnpName, versionRange, dnps, - dappGetFetcher, + dappGetFetcher }); expect(dnps).to.deep.equal({ "kovan.dnp.dappnode.eth": { versions: { - "0.1.0": { "dependency.dnp.dappnode.eth": "^0.1.1" }, - }, + "0.1.0": { "dependency.dnp.dappnode.eth": "^0.1.1" } + } }, "dependency.dnp.dappnode.eth": { versions: { "0.1.1": {}, - "0.1.2": {}, - }, - }, + "0.1.2": {} + } + } }); }); it("should not crash with circular dependencies", async () => { const mockDnps: MockDnps = { "dnpA.dnp.dappnode.eth": { - "0.1.0": { "dnpB.dnp.dappnode.eth": "^0.1.0" }, + "0.1.0": { "dnpB.dnp.dappnode.eth": "^0.1.0" } }, "dnpB.dnp.dappnode.eth": { - "0.1.0": { "dnpC.dnp.dappnode.eth": "^0.1.0" }, + "0.1.0": { "dnpC.dnp.dappnode.eth": "^0.1.0" } }, "dnpC.dnp.dappnode.eth": { - "0.1.0": { "dnpA.dnp.dappnode.eth": "^0.1.0" }, - }, + "0.1.0": { "dnpA.dnp.dappnode.eth": "^0.1.0" } + } }; const dappGetFetcher = new DappGetFetcherMock(mockDnps); @@ -93,19 +93,19 @@ describe("dappGet/aggregate/aggregateDependencies", () => { name: dnpName, versionRange, dnps, - dappGetFetcher, + dappGetFetcher }); expect(dnps).to.deep.equal({ "dnpA.dnp.dappnode.eth": { - versions: { "0.1.0": { "dnpB.dnp.dappnode.eth": "^0.1.0" } }, + versions: { "0.1.0": { "dnpB.dnp.dappnode.eth": "^0.1.0" } } }, "dnpB.dnp.dappnode.eth": { - versions: { "0.1.0": { "dnpC.dnp.dappnode.eth": "^0.1.0" } }, + versions: { "0.1.0": { "dnpC.dnp.dappnode.eth": "^0.1.0" } } }, "dnpC.dnp.dappnode.eth": { - versions: { "0.1.0": { "dnpA.dnp.dappnode.eth": "^0.1.0" } }, - }, + versions: { "0.1.0": { "dnpA.dnp.dappnode.eth": "^0.1.0" } } + } }); }); }); diff --git a/packages/installer/test/unit/dappGet/aggregate/getRelevantInstalledDnps.test.ts b/packages/installer/test/unit/dappGet/aggregate/getRelevantInstalledDnps.test.ts index aaaec6875..68d4b3e17 100644 --- a/packages/installer/test/unit/dappGet/aggregate/getRelevantInstalledDnps.test.ts +++ b/packages/installer/test/unit/dappGet/aggregate/getRelevantInstalledDnps.test.ts @@ -24,7 +24,7 @@ describe("dappGet/aggregate/getRelevantInstalledDnps", () => { ...mockDnp, version: "0.1.0", dnpName: "dnp-b.eth", - dependencies: { "dnp-c.eth": "0.1.0" }, + dependencies: { "dnp-c.eth": "0.1.0" } }; const dnpList: InstalledPackageData[] = [ relevantPkg, @@ -35,15 +35,15 @@ describe("dappGet/aggregate/getRelevantInstalledDnps", () => { containers: [ { ...mockContainer, - containerId: "17628371823", - }, - ], - }, + containerId: "17628371823" + } + ] + } ]; const relevantInstalledDnps = getRelevantInstalledDnps({ requestedDnps: ["dnp-a.eth", "dnp-c.eth"], - installedDnps: dnpList, + installedDnps: dnpList }); expect(relevantInstalledDnps).to.deep.equal([relevantPkg]); @@ -55,38 +55,38 @@ describe("dappGet/aggregate/getRelevantInstalledDnps", () => { ...mockDnp, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest", - "letsencrypt-nginx.dnp.dappnode.eth": "latest", + "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, dnpName: "web.dnp.dappnode.eth", - version: "0.0.0", + version: "0.0.0" }, { ...mockDnp, dnpName: "vpn.dnp.dappnode.eth", - version: "0.1.16", + version: "0.1.16" }, { ...mockDnp, dnpName: "bind.dnp.dappnode.eth", - version: "0.1.5", + version: "0.1.5" }, { ...mockDnp, dnpName: "core.dnp.dappnode.eth", - version: "0.1.7", + version: "0.1.7" }, { ...mockDnp, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest" }, dnpName: "nginx-proxy.dnp.dappnode.eth", - version: "0.0.3", + version: "0.0.3" }, { ...mockDnp, dependencies: { "web.dnp.dappnode.eth": "latest" }, dnpName: "letsencrypt-nginx.dnp.dappnode.eth", - version: "0.0.4", - }, + version: "0.0.4" + } ]; const expectedRelevantInstalledDnps: InstalledPackageData[] = [ @@ -94,24 +94,24 @@ describe("dappGet/aggregate/getRelevantInstalledDnps", () => { ...mockDnp, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest", - "letsencrypt-nginx.dnp.dappnode.eth": "latest", + "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, dnpName: "web.dnp.dappnode.eth", - version: "0.0.0", + version: "0.0.0" }, { ...mockDnp, dependencies: { - "web.dnp.dappnode.eth": "latest", + "web.dnp.dappnode.eth": "latest" }, dnpName: "letsencrypt-nginx.dnp.dappnode.eth", - version: "0.0.4", - }, + version: "0.0.4" + } ]; const relevantInstalledDnps = getRelevantInstalledDnps({ requestedDnps: ["nginx-proxy.dnp.dappnode.eth"], - installedDnps: dnpList.filter((pkg) => valid(pkg.version)), + installedDnps: dnpList.filter((pkg) => valid(pkg.version)) }); expect(relevantInstalledDnps).to.deep.equal(expectedRelevantInstalledDnps); diff --git a/packages/installer/test/unit/dappGet/aggregate/index.test.ts b/packages/installer/test/unit/dappGet/aggregate/index.test.ts index 824786ce3..9e236dcca 100644 --- a/packages/installer/test/unit/dappGet/aggregate/index.test.ts +++ b/packages/installer/test/unit/dappGet/aggregate/index.test.ts @@ -38,40 +38,40 @@ const dnpList: InstalledPackageData[] = [ ...mockDnp, dependencies: { [nginxId]: "latest", - "letsencrypt-nginx.dnp.dappnode.eth": "latest", + "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, dnpName: "web.dnp.dappnode.eth", version: "0.0.0", - origin: undefined, + origin: undefined }, { ...mockDnp, dependencies: {}, dnpName: "vpn.dnp.dappnode.eth", version: "0.1.16", - origin: undefined, + origin: undefined }, { ...mockDnp, dependencies: { [nginxId]: "latest" }, dnpName: nginxId, version: "0.0.3", - origin: undefined, + origin: undefined }, { ...mockDnp, dependencies: { "web.dnp.dappnode.eth": "latest" }, dnpName: "letsencrypt-nginx.dnp.dappnode.eth", version: "0.0.4", - origin: "/ipfs/Qm1234", - }, + origin: "/ipfs/Qm1234" + } ]; const aggregateDependenciesSpy = sinon.spy(); async function aggregateDependencies({ name, versionRange, - dnps, + dnps }: { name: string; versionRange: string; @@ -82,15 +82,15 @@ async function aggregateDependencies({ dnps[nginxId] = { versions: { ...(dnps[nginxId] ? dnps[nginxId].versions || {} : {}), - "0.1.0": { [depId]: "^0.1.1" }, - }, + "0.1.0": { [depId]: "^0.1.1" } + } }; dnps[depId] = { versions: { ...(dnps[depId] ? dnps[depId].versions || {} : {}), "0.1.1": {}, - "0.1.2": {}, - }, + "0.1.2": {} + } }; return; } @@ -99,20 +99,15 @@ async function aggregateDependencies({ dnps[dnp.dnpName] = { versions: { ...(dnps[dnp.dnpName] ? dnps[dnp.dnpName].versions || {} : {}), - [dnp.version]: dnp.dependencies, - }, + [dnp.version]: dnp.dependencies + } }; } } function getRelevantInstalledDnps(): InstalledPackageData[] { - const relevantInstalledDnpNames = [ - "web.dnp.dappnode.eth", - "letsencrypt-nginx.dnp.dappnode.eth", - ]; - return dnpList.filter((dnp) => - relevantInstalledDnpNames.includes(dnp.dnpName) - ); + const relevantInstalledDnpNames = ["web.dnp.dappnode.eth", "letsencrypt-nginx.dnp.dappnode.eth"]; + return dnpList.filter((dnp) => relevantInstalledDnpNames.includes(dnp.dnpName)); } const dappGetFetcherEmpty = new DappGetFetcherMock({}); @@ -124,18 +119,10 @@ describe.skip("dappGet/aggregate", () => { const mock = await rewiremock.around( () => import("../../../../src/dappGet/aggregate/index.js"), (mock) => { - mock( - () => - import( - "../../../../src/dappGet/aggregate/getRelevantInstalledDnps.js" - ) - ) + mock(() => import("../../../../src/dappGet/aggregate/getRelevantInstalledDnps.js")) .withDefault(getRelevantInstalledDnps) .toBeUsed(); - mock( - () => - import("../../../../src/dappGet/aggregate/aggregateDependencies.js") - ) + mock(() => import("../../../../src/dappGet/aggregate/aggregateDependencies.js")) .withDefault(aggregateDependencies) .toBeUsed(); } @@ -146,21 +133,19 @@ describe.skip("dappGet/aggregate", () => { it("Should label the packages correctly", async () => { const req = { name: nginxId, - ver: "^0.1.0", + ver: "^0.1.0" }; const dappnodeInstaller = new DappnodeInstaller( "https://api.ipfs.dappnode.io", - new ethers.JsonRpcProvider( - `https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}` - ) + new ethers.JsonRpcProvider(`https://mainnet.infura.io/v3/${process.env.INFURA_MAINNET_KEY}`) ); const dnps = await aggregate({ req, dnpList, dappGetFetcher: dappGetFetcherEmpty, - dappnodeInstaller, + dappnodeInstaller }); expect(dnps).to.deep.equal( @@ -168,34 +153,34 @@ describe.skip("dappGet/aggregate", () => { [depId]: { versions: { "0.1.1": {}, - "0.1.2": {}, - }, + "0.1.2": {} + } }, "letsencrypt-nginx.dnp.dappnode.eth": { isInstalled: true, versions: { "0.0.4": { - "web.dnp.dappnode.eth": "*", - }, - }, + "web.dnp.dappnode.eth": "*" + } + } }, [nginxId]: { isRequest: true, versions: { "0.1.0": { - [depId]: "^0.1.1", - }, - }, + [depId]: "^0.1.1" + } + } }, "web.dnp.dappnode.eth": { isInstalled: true, versions: { "0.0.0": { "letsencrypt-nginx.dnp.dappnode.eth": "latest", - [nginxId]: "latest", - }, - }, - }, + [nginxId]: "latest" + } + } + } }, "Should label the packages correctly" ); @@ -204,25 +189,18 @@ describe.skip("dappGet/aggregate", () => { // For user request, the version range is the one set by the user { name: nginxId, versionRange: "^0.1.0" }, // For state packages, the version range is greater or equal than the current - { name: "web.dnp.dappnode.eth", versionRange: ">=0.0.0" }, + { name: "web.dnp.dappnode.eth", versionRange: ">=0.0.0" } // For state packages, if there is a specified origin, use cached local dependencies // { // name: "letsencrypt-nginx.dnp.dappnode.eth", // versionRange: "/ipfs/Qm1234" // } ]; - sinon.assert.callCount( - aggregateDependenciesSpy, - dnpAggregateDependenciesCalls.length - ); + sinon.assert.callCount(aggregateDependenciesSpy, dnpAggregateDependenciesCalls.length); dnpAggregateDependenciesCalls.forEach((callArgs, i) => { - const { name, versionRange } = - aggregateDependenciesSpy.getCall(i).lastArg; - expect({ name, versionRange }).to.deep.equal( - callArgs, - `Wrong arguments for call ${i} to aggregateDependencies` - ); + const { name, versionRange } = aggregateDependenciesSpy.getCall(i).lastArg; + expect({ name, versionRange }).to.deep.equal(callArgs, `Wrong arguments for call ${i} to aggregateDependencies`); }); }); }); diff --git a/packages/installer/test/unit/dappGet/index.test.ts b/packages/installer/test/unit/dappGet/index.test.ts index f718de6c8..b8d6a71e4 100644 --- a/packages/installer/test/unit/dappGet/index.test.ts +++ b/packages/installer/test/unit/dappGet/index.test.ts @@ -9,8 +9,6 @@ import { dappnodeInstaller, mockDnp } from "../../testUtils.js"; import { DappGetDnps } from "../../../src/dappGet/types.js"; import { DappGetFetcher } from "../../../src/dappGet/fetch/index.js"; -/* eslint-disable max-len */ - /** * Purpose of the test. Make sure packages are moved to the alreadyUpgraded object */ @@ -29,26 +27,26 @@ describe.skip("dappGet", function () { ...mockDnp, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest", - "letsencrypt-nginx.dnp.dappnode.eth": "latest", + "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, dnpName: "web.dnp.dappnode.eth", version: "0.1.0", - origin: undefined, + origin: undefined }, { ...mockDnp, dependencies: { "nginx-proxy.dnp.dappnode.eth": "latest" }, dnpName: "nginx-proxy.dnp.dappnode.eth", version: "0.0.3", - origin: undefined, + origin: undefined }, { ...mockDnp, dependencies: { "web.dnp.dappnode.eth": "latest" }, dnpName: "letsencrypt-nginx.dnp.dappnode.eth", version: "0.0.4", - origin: "/ipfs/Qm1234", - }, + origin: "/ipfs/Qm1234" + } ]; } @@ -57,7 +55,7 @@ describe.skip("dappGet", function () { } // IDE and rewiremock can figure out the type on their own - /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ + function resolve() { return { success: true, @@ -65,8 +63,8 @@ describe.skip("dappGet", function () { state: { "nginx-proxy.dnp.dappnode.eth": "0.0.4", "letsencrypt-nginx.dnp.dappnode.eth": "0.0.4", - "web.dnp.dappnode.eth": "0.1.0", - }, + "web.dnp.dappnode.eth": "0.1.0" + } }; } @@ -94,18 +92,18 @@ describe.skip("dappGet", function () { dappnodeInstaller, { name: "nginx-proxy.dnp.dappnode.eth", - ver: "^0.1.0", + ver: "^0.1.0" }, dappGetOptions, dappGetFetcher ); expect(state).to.deep.equal({ - "nginx-proxy.dnp.dappnode.eth": "0.0.4", + "nginx-proxy.dnp.dappnode.eth": "0.0.4" }); expect(alreadyUpdated).to.deep.equal({ "letsencrypt-nginx.dnp.dappnode.eth": "0.0.4", - "web.dnp.dappnode.eth": "0.1.0", + "web.dnp.dappnode.eth": "0.1.0" }); }); diff --git a/packages/installer/test/unit/dappGet/integration.test.ts b/packages/installer/test/unit/dappGet/integration.test.ts index 8c589109b..d6491d291 100644 --- a/packages/installer/test/unit/dappGet/integration.test.ts +++ b/packages/installer/test/unit/dappGet/integration.test.ts @@ -14,15 +14,10 @@ import { dappGet as dappGetType } from "../../../src/dappGet/index.js"; import aggregateType from "../../../src/dappGet/aggregate/index.js"; import { dappnodeInstaller } from "../../testUtils.js"; -/* eslint-disable no-console */ - const log = false; function logBig(...args: string[]): void { const b = "=".repeat(20); - if (log) - logs.info( - `\n${b}\n${args.map((s: string) => String(s)).join(`\n${b}\n`)}\n${b}'\n` - ); + if (log) logs.info(`\n${b}\n${args.map((s: string) => String(s)).join(`\n${b}\n`)}\n${b}'\n`); } /** @@ -39,9 +34,7 @@ describe.skip("dappGet integration test", async () => { const casesFolder = path.join(__dirname, "cases"); for (const casePath of fs.readdirSync(casesFolder)) { // Load the case data with ES6 import - const caseData: DappgetTestCase = await import( - path.join(casesFolder, casePath) - ).then((m) => m.default); + const caseData: DappgetTestCase = await import(path.join(casesFolder, casePath)).then((m) => m.default); describe.skip(`Case: ${caseData.name}`, () => { // Prepare dependencies @@ -51,17 +44,14 @@ describe.skip("dappGet integration test", async () => { .map((dnpName) => { const installedVersion = caseData.dnps[dnpName].installed || ""; const dnp = caseData.dnps[dnpName].versions[installedVersion]; - if (!dnp) - throw Error( - `The installed version must be defined: ${dnpName} @ ${installedVersion}` - ); + if (!dnp) throw Error(`The installed version must be defined: ${dnpName} @ ${installedVersion}`); return { ...mockDnp, dnpName: dnpName, version: installedVersion, origin: undefined, - dependencies: dnp || {}, + dependencies: dnp || {} }; }); @@ -70,9 +60,7 @@ describe.skip("dappGet integration test", async () => { return dnpList; } - const dappGetFetcher = new DappGetFetcherMock( - mapValues(caseData.dnps, (dnp) => dnp.versions) - ); + const dappGetFetcher = new DappGetFetcherMock(mapValues(caseData.dnps, (dnp) => dnp.versions)); let dappGet: typeof dappGetType; let aggregate: typeof aggregateType; @@ -86,9 +74,7 @@ describe.skip("dappGet integration test", async () => { .toBeUsed(); } ); - const aggregateImport = await rewiremock.around( - () => import("../../../src/dappGet/aggregate/index.js") - ); + const aggregateImport = await rewiremock.around(() => import("../../../src/dappGet/aggregate/index.js")); dappGet = dappGetImport.dappGet; aggregate = aggregateImport.default; }); @@ -98,26 +84,20 @@ describe.skip("dappGet integration test", async () => { dappnodeInstaller, req: caseData.req, dnpList, - dappGetFetcher, + dappGetFetcher }); logBig(" Aggregated DNPs", JSON.stringify(dnps, null, 2)); expectNotEmpty(dnps); - expect( - dnps, - "Make sure the aggregation object includes the requested package" - ).to.have.property(caseData.req.name); + expect(dnps, "Make sure the aggregation object includes the requested package").to.have.property( + caseData.req.name + ); if (caseData.expectedAggregate) { expect(dnps).to.deep.equal(caseData.expectedAggregate); } }); it("Should return the expect result", async () => { - const result = await dappGet( - dappnodeInstaller, - caseData.req, - {}, - dappGetFetcher - ); + const result = await dappGet(dappnodeInstaller, caseData.req, {}, dappGetFetcher); const { state, alreadyUpdated } = result; logBig(" DNPs result", JSON.stringify(result, null, 2)); @@ -132,6 +112,5 @@ describe.skip("dappGet integration test", async () => { }); function expectNotEmpty(obj: unknown): void { - expect(isEmpty(obj), "Obj must not be empty: " + JSON.stringify(obj, null, 2)) - .to.be.false; + expect(isEmpty(obj), "Obj must not be empty: " + JSON.stringify(obj, null, 2)).to.be.false; } diff --git a/packages/installer/test/unit/dappGet/resolve/index.test.ts b/packages/installer/test/unit/dappGet/resolve/index.test.ts index c6985f16e..f436afe80 100644 --- a/packages/installer/test/unit/dappGet/resolve/index.test.ts +++ b/packages/installer/test/unit/dappGet/resolve/index.test.ts @@ -19,27 +19,27 @@ describe.skip("dappGet/resolve/resolve", () => { "dependency.dnp.dappnode.eth": { versions: { "0.1.1": {}, - "0.1.2": {}, - }, + "0.1.2": {} + } }, "letsencrypt-nginx.dnp.dappnode.eth": { isInstalled: true, versions: { - "0.0.4": { "web.dnp.dappnode.eth": "*" }, - }, + "0.0.4": { "web.dnp.dappnode.eth": "*" } + } }, "nginx-proxy.dnp.dappnode.eth": { isRequest: true, versions: { - "0.0.3": { "dependency.dnp.dappnode.eth": "*" }, - }, + "0.0.3": { "dependency.dnp.dappnode.eth": "*" } + } }, "web.dnp.dappnode.eth": { isInstalled: true, versions: { - "0.1.0": { "letsencrypt-nginx.dnp.dappnode.eth": "*" }, - }, - }, + "0.1.0": { "letsencrypt-nginx.dnp.dappnode.eth": "*" } + } + } }; const { success, message, state } = resolve(dnps); expect(success).to.equal(true); @@ -48,7 +48,7 @@ describe.skip("dappGet/resolve/resolve", () => { "dependency.dnp.dappnode.eth": "0.1.2", "letsencrypt-nginx.dnp.dappnode.eth": "0.0.4", "nginx-proxy.dnp.dappnode.eth": "0.0.3", - "web.dnp.dappnode.eth": "0.1.0", + "web.dnp.dappnode.eth": "0.1.0" }); }); @@ -57,15 +57,15 @@ describe.skip("dappGet/resolve/resolve", () => { "kovan.dnp.dappnode.eth": { isRequest: true, versions: { - "0.1.1": {}, - }, - }, + "0.1.1": {} + } + } }; const { success, message, state } = resolve(dnps); expect(success).to.equal(true); expect(message).to.equal("Found compatible state at case 1/1"); expect(state).to.deep.equal({ - "kovan.dnp.dappnode.eth": "0.1.1", + "kovan.dnp.dappnode.eth": "0.1.1" }); }); @@ -75,10 +75,9 @@ describe.skip("dappGet/resolve/resolve", () => { isRequest: true, versions: { "/ipfs/QmV33iaboYzMgtcKur9JXbRmvkeeKbQSav8DSk1Emeyw1X": { - "bitcoind.dnp.dappnode.eth": - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", - }, - }, + "bitcoind.dnp.dappnode.eth": "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws" + } + } }, "bitcoind.dnp.dappnode.eth": { isInstalled: true, @@ -87,18 +86,16 @@ describe.skip("dappGet/resolve/resolve", () => { "0.1.0": {}, "0.1.1": {}, "0.1.2": {}, - "0.1.3": {}, - }, - }, + "0.1.3": {} + } + } }; const { success, message, state } = resolve(dnps); expect(success).to.equal(true); expect(message).to.equal("Found compatible state at case 1/5"); expect(state).to.deep.equal({ - "bitcoind.dnp.dappnode.eth": - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", - "lnd.dnp.dappnode.eth": - "/ipfs/QmV33iaboYzMgtcKur9JXbRmvkeeKbQSav8DSk1Emeyw1X", + "bitcoind.dnp.dappnode.eth": "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", + "lnd.dnp.dappnode.eth": "/ipfs/QmV33iaboYzMgtcKur9JXbRmvkeeKbQSav8DSk1Emeyw1X" }); }); @@ -107,15 +104,15 @@ describe.skip("dappGet/resolve/resolve", () => { "dependency.dnp.dappnode.eth": { versions: { "0.1.0": {}, - "0.1.1": {}, - }, + "0.1.1": {} + } }, "mainDnp.dnp.dappnode.eth": { isRequest: true, versions: { - "0.1.0": { "dependency.dnp.dappnode.eth": "0.1.2" }, - }, - }, + "0.1.0": { "dependency.dnp.dappnode.eth": "0.1.2" } + } + } }; const { success, message, state } = resolve(dnps); expect(success).to.equal(false); diff --git a/packages/installer/test/unit/dappGet/resolve/permutations.test.ts b/packages/installer/test/unit/dappGet/resolve/permutations.test.ts index d4d8370ef..1e7f55cc2 100644 --- a/packages/installer/test/unit/dappGet/resolve/permutations.test.ts +++ b/packages/installer/test/unit/dappGet/resolve/permutations.test.ts @@ -1,9 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - PermutationInterface, - PermutationsTableInterface, -} from "../../../../src/dappGet/types.js"; +import { PermutationInterface, PermutationsTableInterface } from "../../../../src/dappGet/types.js"; /** * Purpose of the test. Make sure it is able to pick up relevant installed DNPs @@ -29,61 +26,57 @@ describe.skip("dappGet/resolve/permutations", () => { "dependency.dnp.dappnode.eth": { versions: { "0.1.0": {}, - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws": {}, - }, + "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws": {} + } }, "letsencrypt-nginx.dnp.dappnode.eth": { isInstalled: true, versions: { "0.1.0": { "web.dnp.dappnode.eth": "latest" }, - "0.1.1": { "web.dnp.dappnode.eth": "latest" }, - }, + "0.1.1": { "web.dnp.dappnode.eth": "latest" } + } }, "nginx-proxy.dnp.dappnode.eth": { isRequest: true, versions: { "0.1.8": { "nginx-proxy.dnp.dappnode.eth": "latest" }, - "0.1.7": { "nginx-proxy.dnp.dappnode.eth": "latest" }, - }, + "0.1.7": { "nginx-proxy.dnp.dappnode.eth": "latest" } + } }, "web.dnp.dappnode.eth": { isInstalled: true, versions: { - "0.1.2": { "letsencrypt-nginx.dnp.dappnode.eth": "latest" }, - }, - }, + "0.1.2": { "letsencrypt-nginx.dnp.dappnode.eth": "latest" } + } + } }; permutationsTable = permutations.getPermutationsTable(dnps); expect(permutationsTable).to.deep.equal([ { name: "dependency.dnp.dappnode.eth", - versions: [ - null, - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", - "0.1.0", - ], + versions: [null, "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", "0.1.0"], n: 3, - m: 1, + m: 1 }, { name: "letsencrypt-nginx.dnp.dappnode.eth", versions: ["0.1.0", "0.1.1"], n: 2, - m: 3, + m: 3 }, { name: "web.dnp.dappnode.eth", versions: ["0.1.2"], n: 1, - m: 6, + m: 6 }, { name: "nginx-proxy.dnp.dappnode.eth", versions: ["0.1.8", "0.1.7"], n: 2, - m: 6, - }, + m: 6 + } ]); permutationsNumber = permutations.getTotalPermutations(permutationsTable); @@ -96,7 +89,7 @@ describe.skip("dappGet/resolve/permutations", () => { "dependency.dnp.dappnode.eth": null, "letsencrypt-nginx.dnp.dappnode.eth": "0.1.0", "web.dnp.dappnode.eth": "0.1.2", - "nginx-proxy.dnp.dappnode.eth": "0.1.8", + "nginx-proxy.dnp.dappnode.eth": "0.1.8" }); }); @@ -105,12 +98,10 @@ describe.skip("dappGet/resolve/permutations", () => { const dnps = { A: { isRequest: true, versions: { "1.0.0": {}, "2.0.0": {} } }, B: { isInstalled: true, versions: { "1.0.0": {}, "2.0.0": {} } }, - C: { versions: { "1.0.0": {}, "2.0.0": {} } }, + C: { versions: { "1.0.0": {}, "2.0.0": {} } } }; const permutationsTable = permutations.getPermutationsTable(dnps); - const permutationsNumber = permutations.getTotalPermutations( - permutationsTable - ); + const permutationsNumber = permutations.getTotalPermutations(permutationsTable); const _permutations: PermutationInterface[] = []; for (let i = 0; i < permutationsNumber; i++) { _permutations.push(permutations.getPermutation(permutationsTable, i)); @@ -127,7 +118,7 @@ describe.skip("dappGet/resolve/permutations", () => { { C: "1.0.0", B: "1.0.0", A: "1.0.0" }, { C: null, B: "2.0.0", A: "1.0.0" }, { C: "2.0.0", B: "2.0.0", A: "1.0.0" }, - { C: "1.0.0", B: "2.0.0", A: "1.0.0" }, + { C: "1.0.0", B: "2.0.0", A: "1.0.0" } ]); }); }); diff --git a/packages/installer/test/unit/dappGet/resolve/prioritizeDnps.test.ts b/packages/installer/test/unit/dappGet/resolve/prioritizeDnps.test.ts index d5b9cc192..f68d0586f 100644 --- a/packages/installer/test/unit/dappGet/resolve/prioritizeDnps.test.ts +++ b/packages/installer/test/unit/dappGet/resolve/prioritizeDnps.test.ts @@ -20,7 +20,7 @@ describe.skip("dappGet/resolve/prioritizeDnps", () => { B: { isInstalled: true, versions: {} }, C: { isInstalled: true, versions: {} }, D: { versions: {} }, - E: { versions: {} }, + E: { versions: {} } }; const dnpsArray = prioritizeDnps(dnps); expect(dnpsArray).to.deep.equal([ @@ -28,7 +28,7 @@ describe.skip("dappGet/resolve/prioritizeDnps", () => { { name: "E", versions: {} }, { name: "B", isInstalled: true, versions: {} }, { name: "C", isInstalled: true, versions: {} }, - { name: "A", isRequest: true, versions: {} }, + { name: "A", isRequest: true, versions: {} } ]); }); }); diff --git a/packages/installer/test/unit/dappGet/resolve/prioritizeVersions.test.ts b/packages/installer/test/unit/dappGet/resolve/prioritizeVersions.test.ts index 90e342e56..1dea359f7 100644 --- a/packages/installer/test/unit/dappGet/resolve/prioritizeVersions.test.ts +++ b/packages/installer/test/unit/dappGet/resolve/prioritizeVersions.test.ts @@ -17,7 +17,7 @@ describe.skip("dappGet/resolve/prioritizeVersions", () => { it("should order versions: requested DNP. Prioritize newer versions", async () => { const dnp = { isRequest: true, - versions: { "0.1.0": {}, "0.1.1": {} }, + versions: { "0.1.0": {}, "0.1.1": {} } }; const versions = prioritizeVersions(dnp); expect(versions).to.deep.equal(["0.1.1", "0.1.0"]); @@ -29,21 +29,17 @@ describe.skip("dappGet/resolve/prioritizeVersions", () => { versions: { "0.1.0": {}, "0.1.1": {}, - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws": {}, - }, + "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws": {} + } }; const versions = prioritizeVersions(dnp); - expect(versions).to.deep.equal([ - "/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", - "0.1.1", - "0.1.0", - ]); + expect(versions).to.deep.equal(["/ipfs/QmbPVaVVLHoFyJyzxHmok9kJYFAzq6R2UBvhEAuAQYc3ws", "0.1.1", "0.1.0"]); }); it("should order versions: state DNP. Prioritize older versions", async () => { const dnp = { isInstalled: true, - versions: { "0.1.0": {}, "0.1.1": {} }, + versions: { "0.1.0": {}, "0.1.1": {} } }; const versions = prioritizeVersions(dnp); expect(versions).to.deep.equal(["0.1.0", "0.1.1"]); @@ -51,7 +47,7 @@ describe.skip("dappGet/resolve/prioritizeVersions", () => { it("should order versions: not installed DNP. Prioritize newer versions + null", async () => { const dnp = { - versions: { "0.1.0": {}, "0.1.1": {} }, + versions: { "0.1.0": {}, "0.1.1": {} } }; const versions = prioritizeVersions(dnp); expect(versions).to.deep.equal([null, "0.1.1", "0.1.0"]); diff --git a/packages/installer/test/unit/dappGet/resolve/verifyState.test.ts b/packages/installer/test/unit/dappGet/resolve/verifyState.test.ts index 641867df9..9d435a4f0 100644 --- a/packages/installer/test/unit/dappGet/resolve/verifyState.test.ts +++ b/packages/installer/test/unit/dappGet/resolve/verifyState.test.ts @@ -6,27 +6,27 @@ describe.skip("verifyState", () => { const dnps = { A: { versions: { - "1.0.0": { C: "^1.0.0" }, - }, + "1.0.0": { C: "^1.0.0" } + } }, B: { versions: { - "1.0.0": { C: "^1.0.0" }, - }, + "1.0.0": { C: "^1.0.0" } + } }, C: { versions: { "1.0.0": {}, - "2.0.0": {}, - }, - }, + "2.0.0": {} + } + } }; it("should return true for a valid state", () => { const state = { A: "1.0.0", B: "1.0.0", - C: "1.0.0", + C: "1.0.0" }; const res = verifyState(state, dnps); expect(res.valid).to.be.true; @@ -34,7 +34,7 @@ describe.skip("verifyState", () => { it("should return false, dependency no installed", () => { const state = { - A: "1.0.0", + A: "1.0.0" }; // { req: 'A@1.0.0', dep: 'C', depVer: undefined, reqRange: '^1.0.0' } const res = verifyState(state, dnps); @@ -42,14 +42,14 @@ describe.skip("verifyState", () => { expect(res.reason).to.deep.equal({ req: "A@1.0.0", dep: "C@no-version", - range: "^1.0.0", + range: "^1.0.0" }); }); it("should return false, invalid dependency", () => { const state = { A: "1.0.0", - C: "2.0.0", + C: "2.0.0" }; // { req: 'A@1.0.0', dep: 'C', depVer: '2.0.0', reqRange: '^1.0.0' } const res = verifyState(state, dnps); @@ -57,7 +57,7 @@ describe.skip("verifyState", () => { expect(res.reason).to.deep.equal({ req: "A@1.0.0", dep: "C@2.0.0", - range: "^1.0.0", + range: "^1.0.0" }); }); }); diff --git a/packages/installer/test/unit/dappGet/testHelpers.ts b/packages/installer/test/unit/dappGet/testHelpers.ts index 30f6eb5bb..5b6a315b3 100644 --- a/packages/installer/test/unit/dappGet/testHelpers.ts +++ b/packages/installer/test/unit/dappGet/testHelpers.ts @@ -30,7 +30,7 @@ export interface MockDnps { } // No need to re-define a nested module object type -/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */ + export class DappGetFetcherMock extends DappGetFetcher { dnps: MockDnps; @@ -45,33 +45,20 @@ export class DappGetFetcherMock extends DappGetFetcher { return dnp; } - async dependencies( - dappnodeInstaller: DappnodeInstaller, - name: string, - version: string - ): Promise<Dependencies> { + async dependencies(dappnodeInstaller: DappnodeInstaller, name: string, version: string): Promise<Dependencies> { const dnp = this.getDnp(name); const dependencies = dnp[version]; - if (!dependencies) - throw Error(`Version ${name} @ ${version} is not in the case definition`); + if (!dependencies) throw Error(`Version ${name} @ ${version} is not in the case definition`); return dependencies; } - async versions( - dappnodeInstaller: DappnodeInstaller, - name: string, - versionRange: string - ): Promise<string[]> { + async versions(dappnodeInstaller: DappnodeInstaller, name: string, versionRange: string): Promise<string[]> { const dnp = this.getDnp(name); const allVersions = Object.keys(dnp); - const validVersions = allVersions.filter((version) => - safeSemver.satisfies(version, versionRange) - ); + const validVersions = allVersions.filter((version) => safeSemver.satisfies(version, versionRange)); if (!validVersions.length) { const versions = allVersions.join(", "); - throw Error( - `No version satisfy ${name} @ ${versionRange}, versions: ${versions}` - ); + throw Error(`No version satisfy ${name} @ ${versionRange}, versions: ${versions}`); } return validVersions; } diff --git a/packages/installer/test/unit/ethClient/fullNodeEdit.test.ts b/packages/installer/test/unit/ethClient/fullNodeEdit.test.ts index bb097bb78..1198d4af6 100644 --- a/packages/installer/test/unit/ethClient/fullNodeEdit.test.ts +++ b/packages/installer/test/unit/ethClient/fullNodeEdit.test.ts @@ -2,10 +2,7 @@ import "mocha"; import { expect } from "chai"; import { shellSafe } from "@dappnode/utils"; import fs from "fs"; -import { - ethereumClient, - ComposeAliasEditorAction, -} from "../../../src/ethClient/index.js"; +import { ethereumClient, ComposeAliasEditorAction } from "../../../src/ethClient/index.js"; import { params } from "@dappnode/params"; // The following test will wite a compose with the alias fullnode.dappnode: @@ -95,10 +92,7 @@ networks: // Create necessary dir await shellSafe(`mkdir ${dnpRepoExamplePath}`); // Create example compose with fullnode - fs.writeFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - composeWithFullnodeAlias - ); + fs.writeFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, composeWithFullnodeAlias); }); it("Should remove alias: fullnode.dappnode", () => { @@ -107,14 +101,11 @@ networks: action: ComposeAliasEditorAction.REMOVE, execClientDnpName: dnpName, execClientServiceName: serviceName, - alias: params.FULLNODE_ALIAS, + alias: params.FULLNODE_ALIAS }); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); expect(composeAfter.trim()).to.equal(composeWithOutFullnodeAlias.trim()); }); @@ -125,14 +116,11 @@ networks: action: ComposeAliasEditorAction.ADD, execClientDnpName: dnpName, execClientServiceName: serviceName, - alias: params.FULLNODE_ALIAS, + alias: params.FULLNODE_ALIAS }); // Get edited compose - const composeAfter = fs.readFileSync( - `${dnpRepoExamplePath}/docker-compose.yml`, - "utf-8" - ); + const composeAfter = fs.readFileSync(`${dnpRepoExamplePath}/docker-compose.yml`, "utf-8"); expect(composeAfter.trim()).to.equal(composeWithFullnodeAlias.trim()); }); diff --git a/packages/installer/test/unit/ethClient/localFallbackVersions.test.ts b/packages/installer/test/unit/ethClient/localFallbackVersions.test.ts index d5c969bc6..a7a3a39fd 100644 --- a/packages/installer/test/unit/ethClient/localFallbackVersions.test.ts +++ b/packages/installer/test/unit/ethClient/localFallbackVersions.test.ts @@ -1,9 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - parseContentHashFile, - loadContentHashes, -} from "../../../src/ethClient/index.js"; +import { parseContentHashFile, loadContentHashes } from "../../../src/ethClient/index.js"; describe("apm > localFallbackVersions", () => { describe("parseContentHashFile", () => { @@ -14,10 +11,8 @@ openethereum.dnp.dappnode.eth,/ipfs/QmbHRZTW9ubWUGp41wbCVnVXaUoUmyM9Tv689EvLbRTQ `; const expectedContentHashes = { - "geth.dnp.dappnode.eth": - "/ipfs/QmNqDvqAyy3pN3PvymB6chM7S1FgYyive8LosVKUuaDdfd", - "openethereum.dnp.dappnode.eth": - "/ipfs/QmbHRZTW9ubWUGp41wbCVnVXaUoUmyM9Tv689EvLbRTQCK", + "geth.dnp.dappnode.eth": "/ipfs/QmNqDvqAyy3pN3PvymB6chM7S1FgYyive8LosVKUuaDdfd", + "openethereum.dnp.dappnode.eth": "/ipfs/QmbHRZTW9ubWUGp41wbCVnVXaUoUmyM9Tv689EvLbRTQCK" }; const contentHashes = parseContentHashFile(data); diff --git a/packages/installer/test/unit/ethClient/syncedNotification.test.ts b/packages/installer/test/unit/ethClient/syncedNotification.test.ts index 42a2de4c1..deb4bdd28 100644 --- a/packages/installer/test/unit/ethClient/syncedNotification.test.ts +++ b/packages/installer/test/unit/ethClient/syncedNotification.test.ts @@ -12,17 +12,16 @@ describe.skip("modules / ethClient / emitSyncedNotification", () => { get: (): EthClientSyncedNotificationStatus => notificationStatus, set: (newValue: EthClientSyncedNotificationStatus): void => { notificationStatus = newValue; - }, + } }; const notificationEmit = sinon.stub(); const mockEventBus: EventBus = { ...eventBus, notification: { - // eslint-disable-next-line @typescript-eslint/no-empty-function on: (): void => {}, - emit: notificationEmit, - }, + emit: notificationEmit + } }; const { emitSyncedNotification } = await rewiremock.around( @@ -40,75 +39,60 @@ describe.skip("modules / ethClient / emitSyncedNotification", () => { emitSyncedNotification( { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }, { ok: false, code: "IS_SYNCING" } ); - expect(notificationEmit.callCount).to.equal( - 0, - "Should not emit when syncing" - ); + expect(notificationEmit.callCount).to.equal(0, "Should not emit when syncing"); emitSyncedNotification( { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }, { ok: true, url: "", dnpName: "" } ); - expect(notificationEmit.callCount).to.equal( - 1, - "Should emit when sync is complete" - ); + expect(notificationEmit.callCount).to.equal(1, "Should emit when sync is complete"); emitSyncedNotification( { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }, { ok: true, url: "", dnpName: "" } ); - expect(notificationEmit.callCount).to.equal( - 1, - "Should not emit again on complete" - ); + expect(notificationEmit.callCount).to.equal(1, "Should not emit again on complete"); emitSyncedNotification( { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }, { ok: false, code: "IS_SYNCING" } ); emitSyncedNotification( { execClient: "geth.dnp.dappnode.eth", - consClient: "lighthouse.dnp.dappnode.eth", + consClient: "lighthouse.dnp.dappnode.eth" }, { ok: true, url: "", dnpName: "" } ); - expect(notificationEmit.callCount).to.equal( - 1, - "Should not emit again after synced" - ); + expect(notificationEmit.callCount).to.equal(1, "Should not emit again after synced"); emitSyncedNotification( { execClient: "nethermind.public.dappnode.eth", - consClient: "nimbus.dnp.dappnode.eth", + consClient: "nimbus.dnp.dappnode.eth" }, { ok: false, code: "IS_SYNCING" } ); emitSyncedNotification( { execClient: "nethermind.public.dappnode.eth", - consClient: "nimbus.dnp.dappnode.eth", + consClient: "nimbus.dnp.dappnode.eth" }, { ok: true, url: "", dnpName: "" } ); - expect(notificationEmit.callCount).to.equal( - 2, - "Should emit when changing target" - ); + expect(notificationEmit.callCount).to.equal(2, "Should emit when changing target"); }); }); diff --git a/packages/installer/test/unit/installer/createVolumeDevicePaths.test.ts b/packages/installer/test/unit/installer/createVolumeDevicePaths.test.ts index cda52539a..42fd988ce 100644 --- a/packages/installer/test/unit/installer/createVolumeDevicePaths.test.ts +++ b/packages/installer/test/unit/installer/createVolumeDevicePaths.test.ts @@ -5,8 +5,7 @@ import { getVolumeDevicePaths } from "../../../src/installer/createVolumeDeviceP describe("Module > installer > createVolumeDevicePaths", () => { it("Should parse the list of volume paths to create from compose", () => { - const devicePath = - "/mnt/volume_ams3_01/dappnode-volumes/raiden.dnp.dappnode.eth/data"; + const devicePath = "/mnt/volume_ams3_01/dappnode-volumes/raiden.dnp.dappnode.eth/data"; const compose: Compose = { version: "3.5", @@ -14,23 +13,23 @@ describe("Module > installer > createVolumeDevicePaths", () => { "raiden.dnp.dappnode.eth": { volumes: ["data:/root/.raiden"], container_name: "DAppNodePackage-raiden.dnp.dappnode.eth", - image: "raiden.dnp.dappnode.eth:0.0.2", - }, + image: "raiden.dnp.dappnode.eth:0.0.2" + } }, volumes: { data: { driver_opts: { type: "none", device: devicePath, - o: "bind", - }, - }, + o: "bind" + } + } }, networks: { dncore_network: { - external: true, - }, - }, + external: true + } + } }; expect(getVolumeDevicePaths([{ compose }])).to.deep.equal([devicePath]); diff --git a/packages/installer/test/unit/installer/isIpfsHash.test.ts b/packages/installer/test/unit/installer/isIpfsHash.test.ts index 81a54f5a8..b69f3d7c1 100644 --- a/packages/installer/test/unit/installer/isIpfsHash.test.ts +++ b/packages/installer/test/unit/installer/isIpfsHash.test.ts @@ -9,7 +9,7 @@ describe("isIpfsHash", () => { "/ipfs/QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme", "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG/readme", "/ipfs/QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", - "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", + "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB" ]; for (const hash of validHashes) { diff --git a/packages/installer/test/unit/installer/orderInstallPackages.test.ts b/packages/installer/test/unit/installer/orderInstallPackages.test.ts index faca7a8a0..8774f690f 100644 --- a/packages/installer/test/unit/installer/orderInstallPackages.test.ts +++ b/packages/installer/test/unit/installer/orderInstallPackages.test.ts @@ -9,7 +9,7 @@ describe("Module > Installer", () => { function getPackagesData(names: string[]): InstallPackageData[] { return names.map((dnpName) => ({ ...mockPackageData, - dnpName, + dnpName })); } const coreName = "core.dnp.dappnode.eth"; @@ -25,7 +25,7 @@ describe("Module > Installer", () => { "wamp.dnp.dappnode.eth", "admin.dnp.dappnode.eth", dappmanagerName, - "wifi.dnp.dappnode.eth", + "wifi.dnp.dappnode.eth" ]); const expectedOrderedPackagesData = [ @@ -37,13 +37,10 @@ describe("Module > Installer", () => { "vpn.dnp.dappnode.eth", "wamp.dnp.dappnode.eth", "wifi.dnp.dappnode.eth", - dappmanagerName, + dappmanagerName ]; - const orderedPackagesData = orderInstallPackages( - packagesData, - coreName - ).map(({ dnpName }) => dnpName); + const orderedPackagesData = orderInstallPackages(packagesData, coreName).map(({ dnpName }) => dnpName); expect(orderedPackagesData).to.deep.equal(expectedOrderedPackagesData); }); @@ -59,15 +56,15 @@ describe("Module > Installer", () => { "wamp.dnp.dappnode.eth", "admin.dnp.dappnode.eth", dappmanagerName, - "wifi.dnp.dappnode.eth", + "wifi.dnp.dappnode.eth" ]).map((pkg) => { if (pkg.dnpName === coreName) return { ...pkg, manifest: { ...pkg.manifest, - runOrder, - }, + runOrder + } }; else return pkg; }); @@ -81,13 +78,10 @@ describe("Module > Installer", () => { "wamp.dnp.dappnode.eth", "wifi.dnp.dappnode.eth", coreName, - dappmanagerName, + dappmanagerName ]; - const orderedPackagesData = orderInstallPackages( - packagesData, - coreName - ).map(({ dnpName }) => dnpName); + const orderedPackagesData = orderInstallPackages(packagesData, coreName).map(({ dnpName }) => dnpName); expect(orderedPackagesData).to.deep.equal(expectedOrderedPackagesData); }); @@ -101,7 +95,7 @@ describe("Module > Installer", () => { "wamp.dnp.dappnode.eth", "wifi.dnp.dappnode.eth", "vpn.dnp.dappnode.eth", - dappmanagerName, + dappmanagerName ]; const packagesData = getPackagesData([ @@ -113,23 +107,20 @@ describe("Module > Installer", () => { "wamp.dnp.dappnode.eth", "admin.dnp.dappnode.eth", dappmanagerName, - "wifi.dnp.dappnode.eth", + "wifi.dnp.dappnode.eth" ]).map((pkg) => { if (pkg.dnpName === coreName) return { ...pkg, manifest: { ...pkg.manifest, - runOrder, - }, + runOrder + } }; else return pkg; }); - const orderedPackagesData = orderInstallPackages( - packagesData, - coreName - ).map(({ dnpName }) => dnpName); + const orderedPackagesData = orderInstallPackages(packagesData, coreName).map(({ dnpName }) => dnpName); expect(orderedPackagesData).to.deep.equal(runOrder); }); }); diff --git a/packages/installer/test/unit/release/findEntries.test.ts b/packages/installer/test/unit/release/findEntries.test.ts index 71d376a01..c8a27f3b1 100644 --- a/packages/installer/test/unit/release/findEntries.test.ts +++ b/packages/installer/test/unit/release/findEntries.test.ts @@ -2,12 +2,7 @@ import "mocha"; import { expect } from "chai"; import { mapValues } from "lodash-es"; import { IPFSEntry } from "@dappnode/toolkit"; -import { - releaseFilesToDownload, - DirectoryFiles, - FileConfig, - releaseFiles, -} from "@dappnode/types"; +import { releaseFilesToDownload, DirectoryFiles, FileConfig, releaseFiles } from "@dappnode/types"; interface IpfsFileResult { name: string; // 'avatar.png', @@ -21,18 +16,11 @@ type IPFSEntryName = Pick<IPFSEntry, "name">; type ReleaseFiles = typeof releaseFiles; // Overload to strictly type the return according to the fildId -export function findEntries< - T extends IPFSEntryName, - K extends keyof ReleaseFiles ->( +export function findEntries<T extends IPFSEntryName, K extends keyof ReleaseFiles>( files: T[], config: Omit<FileConfig, "format">, fileId: K -): ReleaseFiles[K] extends { multiple: true } - ? T[] - : ReleaseFiles[K] extends { required: true } - ? T - : T | undefined; +): ReleaseFiles[K] extends { multiple: true } ? T[] : ReleaseFiles[K] extends { required: true } ? T : T | undefined; export function findEntries<T extends IPFSEntryName>( files: T[], @@ -41,14 +29,12 @@ export function findEntries<T extends IPFSEntryName>( ): T[] | T | undefined { const matches = files.filter((file) => config.regex.test(file.name)); - if (matches.length === 0 && config.required) - throw Error(`No ${fileId} found`); + if (matches.length === 0 && config.required) throw Error(`No ${fileId} found`); if (config.multiple) { return matches; } else { - if (matches.length > 1) - throw Error(`Multiple possible entries found for ${fileId}`); + if (matches.length > 1) throw Error(`Multiple possible entries found for ${fileId}`); return matches[0]; } } @@ -68,12 +54,12 @@ describe("validateTarImage", () => { "host-grafana-dashboard.json", "prometheus-targets.json", "setup-wizard.json", - "signature.json", + "signature.json" ].map((name) => ({ name, path: `Qm-root/${name}`, size: name.length, - hash: `Qm-${name}`, + hash: `Qm-${name}` })); const expectedResultWithNameOnly = { @@ -84,10 +70,7 @@ describe("validateTarImage", () => { disclaimer: "disclaimer.md", gettingStarted: "getting-started.md", prometheusTargets: "prometheus-targets.json", - grafanaDashboards: [ - "docker-grafana-dashboard.json", - "host-grafana-dashboard.json", - ], + grafanaDashboards: ["docker-grafana-dashboard.json", "host-grafana-dashboard.json"] }; const result = mapValues(releaseFilesToDownload, (fileConfig, _fileId) => { diff --git a/packages/installer/test/unit/release/validateImage.test.ts b/packages/installer/test/unit/release/validateImage.test.ts index a00caf29a..f6cae3522 100644 --- a/packages/installer/test/unit/release/validateImage.test.ts +++ b/packages/installer/test/unit/release/validateImage.test.ts @@ -2,11 +2,7 @@ import "mocha"; import { expect } from "chai"; import path from "path"; import fs from "fs"; -import { - testDir, - createTestDir, - cleanTestDir, -} from "../../../../dappmanager/test/testUtils.js"; +import { testDir, createTestDir, cleanTestDir } from "../../../../dappmanager/test/testUtils.js"; import { validateTarImage } from "../../../src/installer/downloadImages.js"; describe("validateTarImage", () => { diff --git a/packages/logger/.eslintignore b/packages/logger/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/logger/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/logger/.eslintrc.cjs b/packages/logger/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/logger/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/logger/package.json b/packages/logger/package.json index fc3bd4c14..554ed502c 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/eventbus": "workspace:^0.1.0", diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts index 42779cead..0a2ffac99 100644 --- a/packages/logger/src/index.ts +++ b/packages/logger/src/index.ts @@ -1,6 +1,6 @@ export { logs } from "./logs.js"; -export { logUiClear, getLogUi } from "./logUi.js"; +export { logUiClear, getLogUi } from "./logUi.js"; export { routesLogger, subscriptionsLogger } from "./logger.js"; export * as logUserAction from "./logUserAction.js"; export type { Logs } from "./logs.js"; -export type { Log } from "./logUi.js"; \ No newline at end of file +export type { Log } from "./logUi.js"; diff --git a/packages/logger/src/logUi.ts b/packages/logger/src/logUi.ts index 57de5cf6c..300f4cd9d 100644 --- a/packages/logger/src/logUi.ts +++ b/packages/logger/src/logUi.ts @@ -21,8 +21,7 @@ export type Log = (dnpName: string, message: string) => void; function logUi(progressLog: ProgressLog): void { const { dnpName, message } = progressLog; // Log them internally. But skip download progress logs, too spam-y - if (message && !message.includes("%")) - logs.info("Progress log", dnpName, message); + if (message && !message.includes("%")) logs.info("Progress log", dnpName, message); eventBus.logUi.emit(progressLog); } diff --git a/packages/logger/src/logUserAction.ts b/packages/logger/src/logUserAction.ts index 61c6c4013..d4d835916 100644 --- a/packages/logger/src/logUserAction.ts +++ b/packages/logger/src/logUserAction.ts @@ -13,8 +13,7 @@ import { eventBus } from "@dappnode/eventbus"; let db: JsonFileDb<UserActionLog[]> | null = null; function getDb(): JsonFileDb<UserActionLog[]> { - if (!db) - db = new JsonFileDb<UserActionLog[]>(params.USER_ACTION_LOGS_DB_PATH, []); + if (!db) db = new JsonFileDb<UserActionLog[]>(params.USER_ACTION_LOGS_DB_PATH, []); return db; } @@ -33,14 +32,12 @@ function push(log: UserActionLogPartial, level: UserActionLog["level"]): void { timestamp: Date.now(), ...log, ...(log.args ? { args: logSafeObjects(log.args) } : {}), - ...(log.result ? { result: logSafeObjects(log.result) } : {}), + ...(log.result ? { result: logSafeObjects(log.result) } : {}) }; // Skip for logs greater than 3 KB if (isLogTooBig(userActionLog)) { - logs.warn( - `The log ${userActionLog.event} is too big. It will not be stored in ${params.USER_ACTION_LOGS_DB_PATH}` - ); + logs.warn(`The log ${userActionLog.event} is too big. It will not be stored in ${params.USER_ACTION_LOGS_DB_PATH}`); return; } diff --git a/packages/logger/src/logger.ts b/packages/logger/src/logger.ts index 9f44225d5..00558586c 100644 --- a/packages/logger/src/logger.ts +++ b/packages/logger/src/logger.ts @@ -1,12 +1,7 @@ import * as logUserAction from "./logUserAction.js"; import { logs } from "./logs.js"; import { routesData, Routes } from "@dappnode/types"; -import { - LoggerMiddleware, - Args, - Result, - EthProviderError, -} from "@dappnode/types"; +import { LoggerMiddleware, Args, Result, EthProviderError } from "@dappnode/types"; export const routesLogger: LoggerMiddleware = { onCall: (route: string, args: Args = []): void => { @@ -19,7 +14,7 @@ export const routesLogger: LoggerMiddleware = { event: route, message: `${route} success`, result, - args, + args }); logs.info("RPC success", route); } else { @@ -34,17 +29,16 @@ export const routesLogger: LoggerMiddleware = { } else if (isSyncingError(msg)) { logs.warn(`Chain is still syncing, on ${route}: ${msg}`); } else { - if (isNodeConnectionError(msg)) - logs.warn(`Error connecting to ethchain node, on ${route}: ${msg}`); + if (isNodeConnectionError(msg)) logs.warn(`Error connecting to ethchain node, on ${route}: ${msg}`); else logs.error("RPC error", route, error); logUserAction.error({ event: route, message: error.message, stack: error.stack, - args, + args }); } - }, + } }; export const subscriptionsLogger: LoggerMiddleware = { @@ -55,7 +49,7 @@ export const subscriptionsLogger: LoggerMiddleware = { onError: (route: string, error: Error, args: Args = []): void => { logs.error("Subscription error", route, error); logs.debug("Subscription error", route, args); - }, + } }; /** @@ -69,8 +63,5 @@ function isNodeConnectionError(msg: string): boolean { * When attempting to call a contract while the chain is syncing */ function isSyncingError(msg: string): boolean { - return ( - msg.includes("decode 0x from ABI") || - msg.includes("decode address from ABI") - ); + return msg.includes("decode 0x from ABI") || msg.includes("decode address from ABI"); } diff --git a/packages/logger/src/logs.ts b/packages/logger/src/logs.ts index 427d70713..d745e4433 100644 --- a/packages/logger/src/logs.ts +++ b/packages/logger/src/logs.ts @@ -25,11 +25,9 @@ const tags = { debug: "DEBUG", info: "INFO ", warn: "WARN ", - error: "ERROR", + error: "ERROR" }; -/* eslint-disable @typescript-eslint/no-empty-function */ -/* eslint-disable no-console */ export const logs: Logs = { /** * Allows to log any type of data. Strings will be shown first. @@ -60,10 +58,8 @@ export const logs: Logs = { * logs.error("error fetching", new Error("DAMNN")); * ``` */ - error: formatLogger(tags.error, console.error), + error: formatLogger(tags.error, console.error) }; -/* eslint-enable @typescript-eslint/no-empty-function */ -/* eslint-enable no-console */ export class ErrorNoStack extends Error {} @@ -97,7 +93,6 @@ function formatLogger(tag: string, logger: (...args: LogArguments[]) => void) { }); logger(tag, `${process.env.TEST ? "[" + caller + "]" : ""}`, ...data); } catch (e) { - /* eslint-disable-next-line no-console */ console.error("ERROR LOGGING ITEMS", e); logger(items); } diff --git a/packages/logger/test/unit/logUserAction.test.ts b/packages/logger/test/unit/logUserAction.test.ts index d9bc4522e..fd3550927 100644 --- a/packages/logger/test/unit/logUserAction.test.ts +++ b/packages/logger/test/unit/logUserAction.test.ts @@ -6,18 +6,14 @@ import { expect } from "chai"; describe("Util: logUserAction", () => { it("Should return true due to a big log", () => { const bigBuffer = Buffer.alloc(3073, "a"); - const bigString: UserActionLog = bigBuffer.toString( - "utf8" - ) as unknown as UserActionLog; + const bigString: UserActionLog = bigBuffer.toString("utf8") as unknown as UserActionLog; expect(logUserAction.isLogTooBig(bigString)).to.be.true; }); it("Should return false due to a small log", () => { const bigBuffer = Buffer.alloc(3069, "a"); - const bigString: UserActionLog = bigBuffer.toString( - "utf8" - ) as unknown as UserActionLog; + const bigString: UserActionLog = bigBuffer.toString("utf8") as unknown as UserActionLog; expect(logUserAction.isLogTooBig(bigString)).to.be.false; }); diff --git a/packages/logger/test/unit/logs.test.ts b/packages/logger/test/unit/logs.test.ts index ac26dddd5..bbd51f78c 100644 --- a/packages/logger/test/unit/logs.test.ts +++ b/packages/logger/test/unit/logs.test.ts @@ -8,11 +8,11 @@ describe("Util: logs", () => { expect( logSafeObjects({ normal: "normal", - dataurl: "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D", + dataurl: "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" }) ).to.deep.equal({ normal: "normal", - dataurl: "data:text/plain", + dataurl: "data:text/plain" }); }); @@ -23,18 +23,18 @@ describe("Util: logs", () => { person: { name: "Mike", relative: { - avatar: "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D", - }, - }, + avatar: "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D" + } + } }) ).to.deep.equal({ normal: "normal", person: { name: "Mike", relative: { - avatar: "data:text/plain", - }, - }, + avatar: "data:text/plain" + } + } }); }); @@ -44,13 +44,13 @@ describe("Util: logs", () => { RTL_PASSWORD: "super-password", SECRET_PHRASE: "black cheese robin door", PRIVATE_KEY: "8986182398162471627461892763891726398124123123213", - NORMAL: "value", + NORMAL: "value" }) ).to.deep.equal({ RTL_PASSWORD: "**********", SECRET_PHRASE: "**********", PRIVATE_KEY: "**********", - NORMAL: "value", + NORMAL: "value" }); }); @@ -65,10 +65,10 @@ describe("Util: logs", () => { color: "blue", passwords: { FIRST_PASSWORD: "first", - SECOND_PASSWORD: "second", - }, - }, - }, + SECOND_PASSWORD: "second" + } + } + } }) ).to.deep.equal({ PRIVATE_WORD: "**********", @@ -79,34 +79,34 @@ describe("Util: logs", () => { color: "blue", passwords: { FIRST_PASSWORD: "**********", - SECOND_PASSWORD: "**********", - }, - }, - }, + SECOND_PASSWORD: "**********" + } + } + } }); }); it("should should limit the size of the string object properties", () => { const obj = { longProp: "1".repeat(2 * maxLength), - shortProp: "1", + shortProp: "1" }; expect(logSafeObjects(obj)).to.deep.equal({ longProp: "1".repeat(maxLength), - shortProp: "1", + shortProp: "1" }); }); it("should keep an array of objects as an array", () => { const obj = { a: 1, - PRIVATE_WORD: "normal", + PRIVATE_WORD: "normal" }; expect(logSafeObjects([obj])).to.deep.equal([ { a: 1, - PRIVATE_WORD: "**********", - }, + PRIVATE_WORD: "**********" + } ]); }); }); diff --git a/packages/migrations/.eslintignore b/packages/migrations/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/migrations/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/migrations/.eslintrc.cjs b/packages/migrations/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/migrations/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/migrations/package.json b/packages/migrations/package.json index ca1888279..727b6eba9 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -16,8 +16,7 @@ "build": "tsc -p tsconfig.json", "test:int": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/int --timeout 180000", "test": "mocha --config ./.mocharc.yaml --recursive ./test/unit --timeout 180000", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/migrations/src/addAliasToRunningContainers.ts b/packages/migrations/src/addAliasToRunningContainers.ts index 692002ad3..d4671925d 100644 --- a/packages/migrations/src/addAliasToRunningContainers.ts +++ b/packages/migrations/src/addAliasToRunningContainers.ts @@ -1,29 +1,17 @@ import Dockerode from "dockerode"; import { uniq } from "lodash-es"; -import { - ComposeNetwork, - ComposeServiceNetwork, - PackageContainer, -} from "@dappnode/types"; +import { ComposeNetwork, ComposeServiceNetwork, PackageContainer } from "@dappnode/types"; import { logs } from "@dappnode/logger"; import { params } from "@dappnode/params"; -import { - ComposeFileEditor, - parseServiceNetworks, -} from "@dappnode/dockercompose"; +import { ComposeFileEditor, parseServiceNetworks } from "@dappnode/dockercompose"; import { dockerComposeUp, dockerNetworkReconnect, listPackageContainers, - getNetworkContainerConfig, + getNetworkContainerConfig } from "@dappnode/dockerapi"; import { gte, lt, clean } from "semver"; -import { - getDockerComposePath, - getIsMonoService, - getPrivateNetworkAliases, - shell, -} from "@dappnode/utils"; +import { getDockerComposePath, getIsMonoService, getPrivateNetworkAliases, shell } from "@dappnode/utils"; /** Alias for code succinctness */ const dncoreNetworkName = params.DOCKER_PRIVATE_NETWORK_NAME; @@ -43,18 +31,15 @@ export async function addAliasToRunningContainers(): Promise<void> { await addAliasToGivenContainers(containers); } -export async function addAliasToGivenContainers( - containers: PackageContainer[] -): Promise<void> { +export async function addAliasToGivenContainers(containers: PackageContainer[]): Promise<void> { for (const container of containers) { try { const service = { serviceName: container.serviceName, dnpName: container.dnpName, isMainOrMonoservice: - getIsMonoService( - new ComposeFileEditor(container.dnpName, container.isCore).compose - ) || Boolean(container.isMain), + getIsMonoService(new ComposeFileEditor(container.dnpName, container.isCore).compose) || + Boolean(container.isMain) }; const aliases = getPrivateNetworkAliases(service); @@ -68,15 +53,8 @@ export async function addAliasToGivenContainers( params.DOCKER_PRIVATE_NETWORK_NAME ); if (!hasAliases(currentEndpointConfig, aliases)) { - const updatedConfig = updateEndpointConfig( - currentEndpointConfig, - aliases - ); - await updateContainerNetwork( - dncoreNetworkName, - container, - updatedConfig - ); + const updatedConfig = updateEndpointConfig(currentEndpointConfig, aliases); + await updateContainerNetwork(dncoreNetworkName, container, updatedConfig); logs.info(`aliases ${aliases} added to ${container.containerName}`); } } catch (e) { @@ -92,16 +70,10 @@ export async function addAliasToGivenContainers( * @param aliases string[] * @returns void */ -export function migrateCoreNetworkAndAliasInCompose( - container: PackageContainer, - aliases: string[] -): void { +export function migrateCoreNetworkAndAliasInCompose(container: PackageContainer, aliases: string[]): void { const compose = new ComposeFileEditor(container.dnpName, container.isCore); - const rawServiceNetworks = compose.services()[ - // eslint-disable-next-line no-unexpected-multiline - container.serviceName - ].get().networks; + const rawServiceNetworks = compose.services()[container.serviceName].get().networks; if (!rawServiceNetworks) { throw Error(`No networks found in ${container.serviceName} service`); @@ -109,13 +81,10 @@ export function migrateCoreNetworkAndAliasInCompose( const serviceNetworks = parseServiceNetworks(rawServiceNetworks); - const dncoreServiceNetwork = - serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME]; + const dncoreServiceNetwork = serviceNetworks[params.DOCKER_PRIVATE_NETWORK_NAME]; if (!dncoreServiceNetwork) { - throw Error( - `No "dncore_network" found in ${container.serviceName} service` - ); + throw Error(`No "dncore_network" found in ${container.serviceName} service`); } const currentDncoreNetworkAliases = dncoreServiceNetwork.aliases || []; @@ -124,36 +93,24 @@ export function migrateCoreNetworkAndAliasInCompose( const newAliases = uniq([...currentDncoreNetworkAliases, ...aliases]); // Gets the network "dncore_network" from the general compose file - const dncoreComposeNetwork = compose.getComposeNetwork( - params.DOCKER_PRIVATE_NETWORK_NAME - ); + const dncoreComposeNetwork = compose.getComposeNetwork(params.DOCKER_PRIVATE_NETWORK_NAME); // Return if migration was done, compose is already updated - if ( - isComposeNetworkAndAliasMigrated( - dncoreComposeNetwork, - dncoreServiceNetwork, - compose.compose.version, - newAliases - ) - ) + if (isComposeNetworkAndAliasMigrated(dncoreComposeNetwork, dncoreServiceNetwork, compose.compose.version, newAliases)) return; // Ensure/update compose file version 3.5 // check if its lower than 3.5. Docker aliases was introduced in docker compose version 3.5 - if ( - lt(parseComposeSemver(compose.compose.version), parseComposeSemver("3.5")) - ) + if (lt(parseComposeSemver(compose.compose.version), parseComposeSemver("3.5"))) compose.compose = { ...compose.compose, - version: params.MINIMUM_COMPOSE_VERSION, + version: params.MINIMUM_COMPOSE_VERSION }; // Add aliases to service - compose.services()[ - // eslint-disable-next-line no-unexpected-multiline - container.serviceName - ].addNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, newAliases, dncoreServiceNetwork); + compose + .services() + [container.serviceName].addNetworkAliases(params.DOCKER_PRIVATE_NETWORK_NAME, newAliases, dncoreServiceNetwork); compose.write(); } @@ -164,15 +121,12 @@ export function migrateCoreNetworkAndAliasInCompose( // return false; // } -function updateEndpointConfig( - currentEndpointConfig: Dockerode.NetworkInfo | null, - aliases: string[] -) { +function updateEndpointConfig(currentEndpointConfig: Dockerode.NetworkInfo | null, aliases: string[]) { const currentAliases = currentEndpointConfig?.Aliases || []; const newAliases = uniq([...currentAliases, ...aliases]); return { ...currentEndpointConfig, - Aliases: newAliases, + Aliases: newAliases }; } @@ -184,14 +138,9 @@ async function updateContainerNetwork( const containerName = container.containerName; // Wifi and VPN containers need a refresh connect due to their own network configuration - if ( - containerName === params.vpnContainerName || - containerName === params.wifiContainerName - ) { + if (containerName === params.vpnContainerName || containerName === params.wifiContainerName) { await shell(`docker rm ${containerName} --force`); - await dockerComposeUp( - getDockerComposePath(container.dnpName, container.isCore) - ); + await dockerComposeUp(getDockerComposePath(container.dnpName, container.isCore)); } else { await dockerNetworkReconnect(networkName, containerName, endpointConfig); logs.info(`Added new alias to ${containerName} in ${networkName} network`); @@ -202,10 +151,7 @@ async function updateContainerNetwork( * @param aliases * @returns boolean */ -function hasAliases( - endpointConfig: Dockerode.NetworkInfo | null, - aliases: string[] -): boolean { +function hasAliases(endpointConfig: Dockerode.NetworkInfo | null, aliases: string[]): boolean { return Boolean( endpointConfig && endpointConfig.Aliases && @@ -235,10 +181,7 @@ function isComposeNetworkAndAliasMigrated( if ( dncoreComposeNetwork?.name === params.DOCKER_PRIVATE_NETWORK_NAME && // Check expected name dncoreComposeNetwork?.external && // Check is external network - gte( - parseComposeSemver(composeVersion), - parseComposeSemver(params.MINIMUM_COMPOSE_VERSION) - ) && // Check version is at least 3.5 + gte(parseComposeSemver(composeVersion), parseComposeSemver(params.MINIMUM_COMPOSE_VERSION)) && // Check version is at least 3.5 aliases.every((alias) => dncoreServiceNetwork.aliases?.includes(alias)) // Check every alias is already present ) return true; @@ -254,10 +197,9 @@ function isComposeNetworkAndAliasMigrated( */ function sanitizeVersion(version: string): string { const sanitizedVersion = clean(version, { - loose: true, + loose: true }); - if (!sanitizedVersion) - throw Error(`Error: ${version} cannot be used by semver`); + if (!sanitizedVersion) throw Error(`Error: ${version} cannot be used by semver`); return sanitizedVersion; } diff --git a/packages/migrations/src/addDappnodePeerToLocalIpfsNode.ts b/packages/migrations/src/addDappnodePeerToLocalIpfsNode.ts index 3de14419a..ef7a35cb4 100644 --- a/packages/migrations/src/addDappnodePeerToLocalIpfsNode.ts +++ b/packages/migrations/src/addDappnodePeerToLocalIpfsNode.ts @@ -2,15 +2,11 @@ import { logs } from "@dappnode/logger"; //Adds Dappnode IPFS peer to the local IPFS node for more stability when fetching IPFS content export async function addDappnodePeerToLocalIpfsNode() { - const dappnodeIpfsPeer = - "/ip4/167.86.114.131/tcp/4001/p2p/QmfB6dT5zxUq1BXiXisgcZKYkvjywdDYBK5keRaqDKH633"; + const dappnodeIpfsPeer = "/ip4/167.86.114.131/tcp/4001/p2p/QmfB6dT5zxUq1BXiXisgcZKYkvjywdDYBK5keRaqDKH633"; const ipfsAlias = "ipfs.dappnode"; logs.info("adding dappnode peer to local ipfs node"); - await fetch( - `http://${ipfsAlias}:5001/api/v0/swarm/peering/add?arg=${dappnodeIpfsPeer}`, - { - method: "POST", - } - ); + await fetch(`http://${ipfsAlias}:5001/api/v0/swarm/peering/add?arg=${dappnodeIpfsPeer}`, { + method: "POST" + }); } diff --git a/packages/migrations/src/createStakerNetworkAndConnectStakerPkgs.ts b/packages/migrations/src/createStakerNetworkAndConnectStakerPkgs.ts index 0b3722fb2..355cabb85 100644 --- a/packages/migrations/src/createStakerNetworkAndConnectStakerPkgs.ts +++ b/packages/migrations/src/createStakerNetworkAndConnectStakerPkgs.ts @@ -19,7 +19,7 @@ export async function createStakerNetworkAndConnectStakerPkgs( await execution.persistSelectedExecutionIfInstalled(network), await consensus.persistSelectedConsensusIfInstalled(network), await signer.persistSignerIfInstalledAndRunning(network), - await mevBoost.persistMevBoostIfInstalledAndRunning(network), + await mevBoost.persistMevBoostIfInstalledAndRunning(network) ]); } } @@ -39,8 +39,8 @@ async function createDockerStakerNetwork(network: string): Promise<void> { Name: network, Driver: "bridge", IPAM: { - Driver: "default", - }, + Driver: "default" + } }); } else { logs.error(`Failed to create docker network ${network}`); diff --git a/packages/migrations/src/determineIsDappnodeAws.ts b/packages/migrations/src/determineIsDappnodeAws.ts index 1155125ae..99fc2e494 100644 --- a/packages/migrations/src/determineIsDappnodeAws.ts +++ b/packages/migrations/src/determineIsDappnodeAws.ts @@ -44,7 +44,7 @@ export async function determineIsDappnodeAws(): Promise<void> { // emit event to trigger telegram bot daemon eventBus.telegramStatusChanged.emit(); } catch (error) { - logs.info("Not a Dappnode AWS cloud"); + logs.info(`Not a Dappnode AWS cloud: ${error.message}`); db.isDappnodeAws.set(false); } } diff --git a/packages/migrations/src/ensureCoreComposesHardcodedIpsRange.ts b/packages/migrations/src/ensureCoreComposesHardcodedIpsRange.ts index a68c7a304..633460203 100644 --- a/packages/migrations/src/ensureCoreComposesHardcodedIpsRange.ts +++ b/packages/migrations/src/ensureCoreComposesHardcodedIpsRange.ts @@ -1,8 +1,5 @@ import { listPackages } from "@dappnode/dockerapi"; -import { - ComposeFileEditor, - parseServiceNetworks, -} from "@dappnode/dockercompose"; +import { ComposeFileEditor, parseServiceNetworks } from "@dappnode/dockercompose"; import { logs } from "@dappnode/logger"; import { params } from "@dappnode/params"; @@ -26,39 +23,30 @@ export async function ensureCoreComposesHardcodedIpsRange(): Promise<void> { for (const service of Object.values(bindCompose.compose.services)) { if (service.networks) { const serviceCoreNetwork = parseServiceNetworks(service.networks); - const coreNetwork = - serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; + const coreNetwork = serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; if (coreNetwork.ipv4_address !== params.BIND_IP) { - logs.info( - `editing service ${params.bindDnpName} ip from ${coreNetwork.ipv4_address} to ${params.BIND_IP}` - ); + logs.info(`editing service ${params.bindDnpName} ip from ${coreNetwork.ipv4_address} to ${params.BIND_IP}`); coreNetwork.ipv4_address = params.BIND_IP; bindCompose.write(); } } } - const pkgsToRemoveHardcodedIps = [ - params.dappmanagerDnpName, - params.wifiDnpName, - params.ipfsDnpName, - ]; + const pkgsToRemoveHardcodedIps = [params.dappmanagerDnpName, params.wifiDnpName, params.ipfsDnpName]; const pkgs = await listPackages(); // Optional pkgs if (pkgs.find((pkg) => pkg.dnpName === params.HTTPS_PORTAL_DNPNAME)) pkgsToRemoveHardcodedIps.push(params.HTTPS_PORTAL_DNPNAME); if (pkgs.find((pkg) => pkg.dnpName === params.WIREGUARD_DNP_NAME)) pkgsToRemoveHardcodedIps.push(params.WIREGUARD_DNP_NAME); - if (pkgs.find((pkg) => pkg.dnpName === params.vpnDnpName)) - pkgsToRemoveHardcodedIps.push(params.vpnDnpName); + if (pkgs.find((pkg) => pkg.dnpName === params.vpnDnpName)) pkgsToRemoveHardcodedIps.push(params.vpnDnpName); for (const core of pkgsToRemoveHardcodedIps) { const compose = new ComposeFileEditor(core, true); for (const service of Object.values(compose.compose.services)) { if (service.networks) { const serviceCoreNetwork = parseServiceNetworks(service.networks); - const coreNetwork = - serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; + const coreNetwork = serviceCoreNetwork[params.DOCKER_PRIVATE_NETWORK_NAME]; if (coreNetwork.ipv4_address) { logs.info(`removing ip ${coreNetwork.ipv4_address} from ${core}`); delete coreNetwork.ipv4_address; diff --git a/packages/migrations/src/index.ts b/packages/migrations/src/index.ts index 514e4146f..78c50cf6e 100644 --- a/packages/migrations/src/index.ts +++ b/packages/migrations/src/index.ts @@ -20,9 +20,7 @@ export class MigrationError extends Error { super(); this.migration = migration; this.coreVersion = coreVersion; - super.message = `Migration ${migration} ${coreVersion} failed: ${ - super.message - }`; + super.message = `Migration ${migration} ${coreVersion} failed: ${super.message}`; } } @@ -42,7 +40,7 @@ export async function executeMigrations( migration: "bundle legacy ops to prevent spamming the docker API", coreVersion: "0.2.30", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -51,7 +49,7 @@ export async function executeMigrations( migration: "migrate winston .log JSON file to a lowdb", coreVersion: "0.2.30", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -60,7 +58,7 @@ export async function executeMigrations( migration: "prune user action logs if the size is greater than 4 MB", coreVersion: "0.2.59", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -69,17 +67,16 @@ export async function executeMigrations( migration: "remove bind DNS from docker compose files", coreVersion: "0.2.82", name: "MIGRATION_ERROR", - message: e, + message: e }) ); await ensureCoreComposesHardcodedIpsRange().catch((e) => migrationErrors.push({ - migration: - "ensure core composes files has correct hardcoded IPs in range", + migration: "ensure core composes files has correct hardcoded IPs in range", coreVersion: "0.2.85", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -88,7 +85,7 @@ export async function executeMigrations( migration: "remove legacy dns from running containers", coreVersion: "0.2.85", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -97,15 +94,15 @@ export async function executeMigrations( dockerNetworkSubnet: params.DOCKER_NETWORK_SUBNET, dappmanagerContainer: { name: params.dappmanagerContainerName, - ip: params.DAPPMANAGER_IP, + ip: params.DAPPMANAGER_IP }, - bindContainer: { name: params.bindContainerName, ip: params.BIND_IP }, + bindContainer: { name: params.bindContainerName, ip: params.BIND_IP } }).catch((e) => migrationErrors.push({ migration: "ensure docker network configuration", coreVersion: "0.2.85", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -114,7 +111,7 @@ export async function executeMigrations( migration: "add docker alias to running containers", coreVersion: "0.2.80", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -123,7 +120,7 @@ export async function executeMigrations( migration: "add Dappnode peer to local IPFS node", coreVersion: "0.2.88", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -132,7 +129,7 @@ export async function executeMigrations( migration: "change ethical metrics db format", coreVersion: "0.2.92", name: "MIGRATION_ERROR", - message: e, + message: e }) ); @@ -141,22 +138,16 @@ export async function executeMigrations( migration: "determine if the dappnode is running in Dappnode AWS", coreVersion: "0.2.94", name: "MIGRATION_ERROR", - message: e, + message: e }) ); - await createStakerNetworkAndConnectStakerPkgs( - execution, - consensus, - signer, - mevBoost - ).catch((e) => + await createStakerNetworkAndConnectStakerPkgs(execution, consensus, signer, mevBoost).catch((e) => migrationErrors.push({ - migration: - "create docker staker network and persist selected staker pkgs per network", + migration: "create docker staker network and persist selected staker pkgs per network", coreVersion: "0.2.95", name: "MIGRATION_ERROR", - message: e, + message: e }) ); diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainerWithIp.ts b/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainerWithIp.ts index 2c1ad28ed..fe954b6d2 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainerWithIp.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainerWithIp.ts @@ -1,9 +1,4 @@ -import { - disconnectConflictingContainerIfAny, - docker, - dockerComposeUp, - findContainerByIP, -} from "@dappnode/dockerapi"; +import { disconnectConflictingContainerIfAny, docker, dockerComposeUp, findContainerByIP } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { params } from "@dappnode/params"; import { getDockerComposePath, removeCidrSuffix } from "@dappnode/utils"; @@ -34,7 +29,7 @@ export async function connectContainerWithIp({ network, containerName, containerIp, - aliasesIpsMap, + aliasesIpsMap }: { network: Dockerode.Network; containerName: string; @@ -48,9 +43,7 @@ export async function connectContainerWithIp({ >; }) { // check if there are any docker containers connected to the network with that IP different than the container requested - const conflictingContainerName = ( - await findContainerByIP(network, containerIp) - )?.Name; + const conflictingContainerName = (await findContainerByIP(network, containerIp))?.Name; if (conflictingContainerName && conflictingContainerName !== containerName) await disconnectConflictingContainerIfAny(network, containerIp); @@ -60,47 +53,35 @@ export async function connectContainerWithIp({ // There has been edge cases where docker containers are in an intermedium state with a different docker container name // i.e b7903a289091_DAppNodeCore-bind.dnp.dappnode.eth instead of DAppNodeCore-bind.dnp.dappnode.eth const containerInfo = await targetContainer.inspect(); - if ( - !containerInfo.State.Running && - containerName !== params.dappmanagerContainerName - ) { + if (!containerInfo.State.Running && containerName !== params.dappmanagerContainerName) { logs.warn(`container ${containerName} is not running, restarting it`); await targetContainer.restart(); } - const hasContainerRightIp = - removeCidrSuffix(aliasesIpsMap.get(containerName)?.ip || "") === - containerIp; + const hasContainerRightIp = removeCidrSuffix(aliasesIpsMap.get(containerName)?.ip || "") === containerIp; - if (hasContainerRightIp) - logs.info( - `container ${containerName} has right IP and is connected to docker network` - ); + if (hasContainerRightIp) logs.info(`container ${containerName} has right IP and is connected to docker network`); else { - logs.info( - `container ${containerName} does not have right IP and/or is not connected to docker network` - ); + logs.info(`container ${containerName} does not have right IP and/or is not connected to docker network`); await connectContainerRetryOnIpUsed({ network, containerName, maxAttempts: 20, ip: containerIp, - aliasesIpsMap, + aliasesIpsMap }); } } catch (e) { // check if container does not exist 404 if (containerName === params.bindContainerName && e.statusCode === 404) { - logs.warn( - `container ${params.bindContainerName} not found and it might be in an intermedium state` - ); + logs.warn(`container ${params.bindContainerName} not found and it might be in an intermedium state`); // the container might be in intermedium state with different name // TODO: what if there is a docker container already using this IP. // This would be extremley dangerous once the migration to the private ip range is done // and less ips are available. logs.info(`recreating container ${containerName} with compose up`); await dockerComposeUp(getDockerComposePath(params.bindDnpName, true), { - forceRecreate: true, + forceRecreate: true }); } else throw e; } @@ -119,7 +100,7 @@ async function connectContainerRetryOnIpUsed({ containerName, maxAttempts, ip, - aliasesIpsMap, + aliasesIpsMap }: { network: Dockerode.Network; containerName: string; @@ -142,25 +123,20 @@ async function connectContainerRetryOnIpUsed({ Container: containerName, EndpointConfig: { IPAMConfig: { - IPv4Address: ip, + IPv4Address: ip }, - Aliases: aliases, - }, + Aliases: aliases + } }; while (attemptCount < maxAttempts) { try { await network.connect(networkOptions); - logs.info( - `Successfully connected ${containerName} with ip ${ip} and aliases ${aliases}` - ); + logs.info(`Successfully connected ${containerName} with ip ${ip} and aliases ${aliases}`); // The disconnected containers will be reconnected later (in the IP range migration) return; } catch (error) { - if ( - error.statusCode === 403 && - error.message.includes("Address already in use") - ) + if (error.statusCode === 403 && error.message.includes("Address already in use")) await disconnectConflictingContainerIfAny(network, ip); else if ( error.statusCode === 403 && @@ -168,13 +144,11 @@ async function connectContainerRetryOnIpUsed({ error.message.includes("already exists") ) { // IP is not right, reconnect container with proper IP - logs.warn( - `container ${containerName} already connected to network ${network.id} with wrong IP` - ); + logs.warn(`container ${containerName} already connected to network ${network.id} with wrong IP`); // TODO: What if this fails? await network.disconnect({ - Container: containerName, + Container: containerName }); // The container will be reconnected in the next iteration @@ -186,7 +160,5 @@ async function connectContainerRetryOnIpUsed({ } attemptCount++; } - logs.error( - `Failed to connect after ${maxAttempts} attempts due to repeated IP conflicts.` - ); + logs.error(`Failed to connect after ${maxAttempts} attempts due to repeated IP conflicts.`); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainersToNetworkWithPrio.ts b/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainersToNetworkWithPrio.ts index 7229a9d5e..380b56df5 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainersToNetworkWithPrio.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/connectContainersToNetworkWithPrio.ts @@ -20,7 +20,7 @@ export async function connectContainersToNetworkWithPrio({ bindContainer, aliasesIpsMap, containersToRestart, - containersToRecreate, + containersToRecreate }: { network: Dockerode.Network; dappmanagerContainer: { @@ -48,11 +48,9 @@ export async function connectContainersToNetworkWithPrio({ network, containerName: dappmanagerContainer.name, containerIp: dappmanagerContainer.ip, - aliasesIpsMap, + aliasesIpsMap }).catch((e) => - logs.error( - `Failed to connect container ${dappmanagerContainer.name} to network ${network.id}: ${e}` - ) + logs.error(`Failed to connect container ${dappmanagerContainer.name} to network ${network.id}: ${e}`) ); // 2. Connect bind container @@ -60,19 +58,13 @@ export async function connectContainersToNetworkWithPrio({ network, containerName: bindContainer.name, containerIp: bindContainer.ip, - aliasesIpsMap, - }).catch((e) => - logs.error( - `Failed to connect container ${bindContainer.name} to network ${network.id}: ${e}` - ) - ); + aliasesIpsMap + }).catch((e) => logs.error(`Failed to connect container ${bindContainer.name} to network ${network.id}: ${e}`)); await restoreContainersToNetworkNotThrow({ containersToRestart, network, aliasesIpsMap, - containersToRecreate, - }).catch((e) => - logs.error(`Failed to restore containers to network ${network.id}: ${e}`) - ); + containersToRecreate + }).catch((e) => logs.error(`Failed to restore containers to network ${network.id}: ${e}`)); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/ensureDockerNetworkConfig.ts b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/ensureDockerNetworkConfig.ts index 7b6afa11c..9918ae316 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/ensureDockerNetworkConfig.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/ensureDockerNetworkConfig.ts @@ -22,7 +22,7 @@ import { removeNetworksOverlappingSubnetIfNeeded } from "./removeNetworksOverlap export async function ensureDockerNetworkConfig({ networkName, networkSubnet, - aliasesIpsMap, + aliasesIpsMap }: { networkName: string; networkSubnet: string; @@ -46,35 +46,31 @@ export async function ensureDockerNetworkConfig({ Driver: "default", Config: [ { - Subnet: networkSubnet, - }, - ], - }, + Subnet: networkSubnet + } + ] + } }; try { const dncoreNetwork = docker.getNetwork(networkName); // docker network inspect // https://docs.docker.com/engine/api/v1.43/#tag/Network/operation/NetworkInspect - const networkInspect: Dockerode.NetworkInspectInfo = - await dncoreNetwork.inspect(); // throws 404 if network not found + const networkInspect: Dockerode.NetworkInspectInfo = await dncoreNetwork.inspect(); // throws 404 if network not found logs.info(`docker network ${networkName} exists`); - const networkSubnets = - networkInspect.IPAM?.Config?.map((config) => config.Subnet) ?? []; + const networkSubnets = networkInspect.IPAM?.Config?.map((config) => config.Subnet) ?? []; // Check subnet is as expected if (networkSubnets.some((subnet) => subnet === networkSubnet)) { // network subnet is as expected - logs.info( - `docker network ${networkName} has correct subnet ${networkSubnet}` - ); + logs.info(`docker network ${networkName} has correct subnet ${networkSubnet}`); return { network: dncoreNetwork, containersToRestart: [], containersToRecreate: [], - isNetworkRecreated: false, + isNetworkRecreated: false }; } else { logs.warn( @@ -84,17 +80,16 @@ export async function ensureDockerNetworkConfig({ logs.error(`error removing overlapping networks: ${e}`) ); // CRITICAL: if this step fails migration failure - const { network, containersToRestart, containersToRecreate } = - await recreateDockerNetwork( - dncoreNetwork, - networkOptions, - aliasesIpsMap - ); + const { network, containersToRestart, containersToRecreate } = await recreateDockerNetwork( + dncoreNetwork, + networkOptions, + aliasesIpsMap + ); return { network, containersToRestart, containersToRecreate, - isNetworkRecreated: true, + isNetworkRecreated: true }; } } catch (e) { @@ -110,7 +105,7 @@ export async function ensureDockerNetworkConfig({ network: await docker.createNetwork(networkOptions), containersToRestart: [], containersToRecreate: [], - isNetworkRecreated: true, + isNetworkRecreated: true }; } else { // TODO: What do we do here? diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/isNetworkOverlappingSubnet.ts b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/isNetworkOverlappingSubnet.ts index faf99b7b1..8dfb042d3 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/isNetworkOverlappingSubnet.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/isNetworkOverlappingSubnet.ts @@ -7,14 +7,8 @@ import { subnetsOverlap } from "./subnetsOverlap.js"; * @param subnet - A string representing the subnet in CIDR notation to check for overlap. * @returns True if there is an overlap with any of the network's subnets, false otherwise. */ -export function isNetworkOverlappingSubnet( - network: Dockerode.NetworkInspectInfo, - subnet: string -): boolean { - const networkSubnets = - network.IPAM?.Config?.map((config) => config.Subnet) ?? []; +export function isNetworkOverlappingSubnet(network: Dockerode.NetworkInspectInfo, subnet: string): boolean { + const networkSubnets = network.IPAM?.Config?.map((config) => config.Subnet) ?? []; - return networkSubnets.some( - (networkSubnet) => networkSubnet && subnetsOverlap(networkSubnet, subnet) - ); + return networkSubnets.some((networkSubnet) => networkSubnet && subnetsOverlap(networkSubnet, subnet)); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/recreateDockerNetwork.ts b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/recreateDockerNetwork.ts index e5c172cca..3708d8bcb 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/recreateDockerNetwork.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/recreateDockerNetwork.ts @@ -1,7 +1,4 @@ -import { - disconnectAllContainersFromNetwork, - docker, -} from "@dappnode/dockerapi"; +import { disconnectAllContainersFromNetwork, docker } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import Dockerode from "dockerode"; import { isEmpty } from "lodash-es"; @@ -33,27 +30,25 @@ export async function recreateDockerNetwork( containersToRestart: string[]; containersToRecreate: string[]; }> { - const containers = ( - (await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo - ).Containers; + const containers = ((await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo).Containers; - const { containersToRestart, containersToRecreate } = - await cleanDockerNetworkBeforeRemoval(networkToRemove, containers); + const { containersToRestart, containersToRecreate } = await cleanDockerNetworkBeforeRemoval( + networkToRemove, + containers + ); logs.info(`removing docker network ${networkToRemove.id}`); // CRITICAL: if this step fails migration failure await networkToRemove.remove().catch(async (e) => { // reconnect all docker containers before throwing error if (containers) { - logs.error( - `error removing docker network, reconnecting all docker containers` - ); + logs.error(`error removing docker network, reconnecting all docker containers`); await restoreContainersToNetworkNotThrow({ containersToRestart, network: networkToRemove, aliasesIpsMap, - containersToRecreate, + containersToRecreate }); } @@ -61,14 +56,12 @@ export async function recreateDockerNetwork( }); // create network with valid range - logs.info( - `creating docker network ${newNetworkOptions.Name} with valid IP range` - ); + logs.info(`creating docker network ${newNetworkOptions.Name} with valid IP range`); // CRITICAL: if this step fails migration failure return { network: await docker.createNetwork(newNetworkOptions), containersToRestart, - containersToRecreate, + containersToRecreate }; } @@ -81,39 +74,29 @@ async function cleanDockerNetworkBeforeRemoval( | undefined ): Promise<{ containersToRestart: string[]; containersToRecreate: string[] }> { if (containers && !isEmpty(containers)) { - logs.info( - `disconnecting containers from docker network before removing it` - ); + logs.info(`disconnecting containers from docker network before removing it`); await disconnectAllContainersFromNetwork(networkToRemove).catch((e) => - logs.error( - `error while disconnecting all containers from the network: ${e.message}` - ) + logs.error(`error while disconnecting all containers from the network: ${e.message}`) ); - const containersToRestart = await stopConnectedContainersIfAny( - networkToRemove - ).catch((e) => { + const containersToRestart = await stopConnectedContainersIfAny(networkToRemove).catch((e) => { logs.error(`error stopping pending connected containers: ${e.message}`); return []; }); - const containersToRecreate = await removeConnectedContainersIfAny( - networkToRemove - ).catch((e) => { - logs.error( - `error removing pending containers, the docker network removal might fail!: ${e}` - ); + const containersToRecreate = await removeConnectedContainersIfAny(networkToRemove).catch((e) => { + logs.error(`error removing pending containers, the docker network removal might fail!: ${e}`); return []; }); return { containersToRestart, - containersToRecreate, + containersToRecreate }; } return { containersToRecreate: [], - containersToRestart: [], + containersToRestart: [] }; } @@ -122,18 +105,12 @@ async function cleanDockerNetworkBeforeRemoval( * * @param networkToRemove dockerode network to remove */ -async function stopConnectedContainersIfAny( - networkToRemove: Dockerode.Network -): Promise<string[]> { - const containers = ( - (await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo - ).Containers; +async function stopConnectedContainersIfAny(networkToRemove: Dockerode.Network): Promise<string[]> { + const containers = ((await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo).Containers; if (!isEmpty(containers)) { const containersNames = Object.values(containers).map((c) => c.Name); - await Promise.all( - containersNames.map(async (cn) => await docker.getContainer(cn).stop()) - ); + await Promise.all(containersNames.map(async (cn) => await docker.getContainer(cn).stop())); return containersNames; } return []; @@ -145,20 +122,12 @@ async function stopConnectedContainersIfAny( * * @param networkToRemove dockerode network to remove */ -async function removeConnectedContainersIfAny( - networkToRemove: Dockerode.Network -): Promise<string[]> { - const containers = ( - (await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo - ).Containers; +async function removeConnectedContainersIfAny(networkToRemove: Dockerode.Network): Promise<string[]> { + const containers = ((await networkToRemove.inspect()) as Dockerode.NetworkInspectInfo).Containers; if (!isEmpty(containers)) { const containersNames = Object.values(containers).map((c) => c.Name); - await Promise.all( - containersNames.map( - async (cn) => await docker.getContainer(cn).remove({ force: true }) - ) - ); + await Promise.all(containersNames.map(async (cn) => await docker.getContainer(cn).remove({ force: true }))); return containersNames; } return []; diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/removeNetworksOverlappingSubnetIfNeeded.ts b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/removeNetworksOverlappingSubnetIfNeeded.ts index 58e202d96..5c459def7 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/removeNetworksOverlappingSubnetIfNeeded.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/removeNetworksOverlappingSubnetIfNeeded.ts @@ -1,7 +1,4 @@ -import { - docker, - disconnectAllContainersFromNetwork, -} from "@dappnode/dockerapi"; +import { docker, disconnectAllContainersFromNetwork } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { isNetworkOverlappingSubnet } from "./isNetworkOverlappingSubnet.js"; @@ -10,19 +7,13 @@ import { isNetworkOverlappingSubnet } from "./isNetworkOverlappingSubnet.js"; * The error thrown when trying to create a network with an overlapping subnet is: * Error: (HTTP code 403) unexpected - Pool overlaps with other one on this address space */ -export async function removeNetworksOverlappingSubnetIfNeeded( - networkSubnet: string -): Promise<void> { +export async function removeNetworksOverlappingSubnetIfNeeded(networkSubnet: string): Promise<void> { const networks = await docker.listNetworks(); - const overlappingNetworks = networks.filter((network) => - isNetworkOverlappingSubnet(network, networkSubnet) - ); + const overlappingNetworks = networks.filter((network) => isNetworkOverlappingSubnet(network, networkSubnet)); if (overlappingNetworks.length > 0) { - logs.info( - `Found ${overlappingNetworks.length} networks to remove (overlapping subnet)` - ); + logs.info(`Found ${overlappingNetworks.length} networks to remove (overlapping subnet)`); await Promise.all( overlappingNetworks.map(async (networkInfo) => { diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/subnetsOverlap.ts b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/subnetsOverlap.ts index ebe196c87..428b2ac1e 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/subnetsOverlap.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/subnetsOverlap.ts @@ -6,7 +6,7 @@ * ipToInteger("192.168.1.1"); // returns 3232235777 */ function ipToInteger(ip: string): number { - return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0); + return ip.split(".").reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0); } /** @@ -17,7 +17,7 @@ function ipToInteger(ip: string): number { * calculateSubnetMask(24); // returns 4294967040 (255.255.255.0) */ function calculateSubnetMask(bits: number): number { - return -1 << (32 - bits); + return -1 << (32 - bits); } /** @@ -29,8 +29,8 @@ function calculateSubnetMask(bits: number): number { * isValidIp("999.999.999.999"); // returns false */ function isValidIp(ip: string): boolean { - const octets = ip.split('.').map(Number); - return octets.length === 4 && octets.every(octet => !isNaN(octet) && octet >= 0 && octet <= 255); + const octets = ip.split(".").map(Number); + return octets.length === 4 && octets.every((octet) => !isNaN(octet) && octet >= 0 && octet <= 255); } /** @@ -42,8 +42,8 @@ function isValidIp(ip: string): boolean { * isValidCidr("33"); // returns false */ function isValidCidr(cidr: string): boolean { - const mask = parseInt(cidr, 10); - return !isNaN(mask) && mask >= 0 && mask <= 32; + const mask = parseInt(cidr, 10); + return !isNaN(mask) && mask >= 0 && mask <= 32; } /** @@ -55,7 +55,7 @@ function isValidCidr(cidr: string): boolean { * getNetworkAddress(3232235777, 24); // returns 3232235776 (192.168.1.0) */ function getNetworkAddress(ip: number, bits: number): number { - return ip & calculateSubnetMask(bits); + return ip & calculateSubnetMask(bits); } /** @@ -69,21 +69,21 @@ function getNetworkAddress(ip: number, bits: number): number { * subnetsOverlap("192.168.1.0/24", "192.168.2.0/24"); // returns false */ export function subnetsOverlap(subnetA: string, subnetB: string): boolean { - const [ipA, maskBitsA] = subnetA.split('/'); - const [ipB, maskBitsB] = subnetB.split('/'); + const [ipA, maskBitsA] = subnetA.split("/"); + const [ipB, maskBitsB] = subnetB.split("/"); - if (!isValidIp(ipA) || !isValidIp(ipB) || !isValidCidr(maskBitsA) || !isValidCidr(maskBitsB)) { - throw new Error("Invalid IP address or CIDR notation"); - } + if (!isValidIp(ipA) || !isValidIp(ipB) || !isValidCidr(maskBitsA) || !isValidCidr(maskBitsB)) { + throw new Error("Invalid IP address or CIDR notation"); + } - const ipIntA = ipToInteger(ipA); - const ipIntB = ipToInteger(ipB); + const ipIntA = ipToInteger(ipA); + const ipIntB = ipToInteger(ipB); - const netA = getNetworkAddress(ipIntA, parseInt(maskBitsA, 10)); - const netB = getNetworkAddress(ipIntB, parseInt(maskBitsB, 10)); + const netA = getNetworkAddress(ipIntA, parseInt(maskBitsA, 10)); + const netB = getNetworkAddress(ipIntB, parseInt(maskBitsB, 10)); - const maskA = calculateSubnetMask(parseInt(maskBitsA, 10)); - const maskB = calculateSubnetMask(parseInt(maskBitsB, 10)); + const maskA = calculateSubnetMask(parseInt(maskBitsA, 10)); + const maskB = calculateSubnetMask(parseInt(maskBitsB, 10)); - return (netA & maskB) === (netB & maskB) || (netB & maskA) === (netA & maskA); + return (netA & maskB) === (netB & maskB) || (netB & maskA) === (netA & maskA); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/migrateDockerNetworkIpRange.ts b/packages/migrations/src/migrateDockerNetworkIpRange/migrateDockerNetworkIpRange.ts index 18979d4ee..826ec1961 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/migrateDockerNetworkIpRange.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/migrateDockerNetworkIpRange.ts @@ -17,7 +17,7 @@ export async function migrateDockerNetworkIpRange({ dockerNetworkName, dockerNetworkSubnet, dappmanagerContainer, - bindContainer, + bindContainer }: { dockerNetworkName: string; dockerNetworkSubnet: string; @@ -30,18 +30,11 @@ export async function migrateDockerNetworkIpRange({ ip: string; }; }): Promise<void> { - const aliasesIpsMap = await getNetworkAliasesIpsMapNotThrow( - dockerNetworkName - ); - const { - network, - containersToRestart, - containersToRecreate, - isNetworkRecreated, - } = await ensureDockerNetworkConfig({ + const aliasesIpsMap = await getNetworkAliasesIpsMapNotThrow(dockerNetworkName); + const { network, containersToRestart, containersToRecreate, isNetworkRecreated } = await ensureDockerNetworkConfig({ networkName: dockerNetworkName, networkSubnet: dockerNetworkSubnet, - aliasesIpsMap, + aliasesIpsMap }); try { @@ -51,7 +44,7 @@ export async function migrateDockerNetworkIpRange({ bindContainer, aliasesIpsMap, containersToRestart, - containersToRecreate, + containersToRecreate }); } catch (e) { logs.error(`Failed to connect containers to network ${dockerNetworkName}`); diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restartAccessContainersNotThrow.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restartAccessContainersNotThrow.ts index a9bb75ee6..36d340b88 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restartAccessContainersNotThrow.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restartAccessContainersNotThrow.ts @@ -6,13 +6,11 @@ export async function restartAccessContainersNotThrow(): Promise<void> { for (const accessContainerName of [ params.wireguardContainerName, params.vpnContainerName, - params.wifiContainerName, + params.wifiContainerName ]) { try { await docker.getContainer(accessContainerName).restart(); - logs.info( - `restarted ${accessContainerName} container to reroute requests` - ); + logs.info(`restarted ${accessContainerName} container to reroute requests`); } catch (e) { if (e.statusCode === 404) { // vpn container does not exist diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/excludeDappmanagerAndBind.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/excludeDappmanagerAndBind.ts index ad25806c6..ac776c721 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/excludeDappmanagerAndBind.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/excludeDappmanagerAndBind.ts @@ -1,8 +1,5 @@ import { params } from "@dappnode/params"; export function excludeDappmanagerAndBind(containers: string[]): string[] { - return containers.filter( - (c) => - c !== params.bindContainerName && c !== params.dappmanagerContainerName - ); + return containers.filter((c) => c !== params.bindContainerName && c !== params.dappmanagerContainerName); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/reconnectDisconnectedContainers.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/reconnectDisconnectedContainers.ts index 65d920f71..58cdd2383 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/reconnectDisconnectedContainers.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/reconnectDisconnectedContainers.ts @@ -1,7 +1,4 @@ -import { - dockerNetworkConnectNotThrow, - listPackages, -} from "@dappnode/dockerapi"; +import { dockerNetworkConnectNotThrow, listPackages } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import Dockerode from "dockerode"; import { excludeDappmanagerAndBind } from "./excludeDappmanagerAndBind.js"; @@ -17,19 +14,14 @@ export async function reconnectDisconnectedContainers( } > ): Promise<void> { - const containersNotConnected = await getContainersNamesNotConnected( - Array.from(Object.keys(aliasesIpsMap)), - network - ); + const containersNotConnected = await getContainersNamesNotConnected(Array.from(Object.keys(aliasesIpsMap)), network); if (containersNotConnected.length > 0) { - logs.info( - `Reconnecting disconnected containers: ${containersNotConnected}` - ); + logs.info(`Reconnecting disconnected containers: ${containersNotConnected}`); await Promise.all( excludeDappmanagerAndBind(containersNotConnected).map(async (c) => { const networkConfig: Partial<Dockerode.NetworkInfo> = { - Aliases: aliasesIpsMap.get(c)?.aliases ?? [], + Aliases: aliasesIpsMap.get(c)?.aliases ?? [] }; await dockerNetworkConnectNotThrow(network.id, c, networkConfig); @@ -38,16 +30,9 @@ export async function reconnectDisconnectedContainers( } } -async function getContainersNamesNotConnected( - containerNames: string[], - network: Dockerode.Network -): Promise<string[]> { - const connectedContainers = ( - (await network.inspect()) as Dockerode.NetworkInspectInfo - ).Containers; - const containerNamesList = (await listPackages()) - .map((pkg) => pkg.containers.map((c) => c.containerName)) - .flat(); +async function getContainersNamesNotConnected(containerNames: string[], network: Dockerode.Network): Promise<string[]> { + const connectedContainers = ((await network.inspect()) as Dockerode.NetworkInspectInfo).Containers; + const containerNamesList = (await listPackages()).map((pkg) => pkg.containers.map((c) => c.containerName)).flat(); // push to containerNames the containers from containerNamesList that are not in containerNames containerNamesList.forEach((c) => { @@ -55,10 +40,7 @@ async function getContainersNamesNotConnected( }); // return all the containers from containerNames that are not connected to the network - if (!connectedContainers || isEmpty(connectedContainers)) - return containerNamesList; + if (!connectedContainers || isEmpty(connectedContainers)) return containerNamesList; - return containerNames.filter( - (c) => !Object.values(connectedContainers).find((cc) => cc.Name === c) - ); + return containerNames.filter((c) => !Object.values(connectedContainers).find((cc) => cc.Name === c)); } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/recreateForceRemovedContainers.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/recreateForceRemovedContainers.ts index 2b4e55ece..4c96ab998 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/recreateForceRemovedContainers.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/recreateForceRemovedContainers.ts @@ -2,20 +2,14 @@ import { docker, dockerComposeUp } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { excludeDappmanagerAndBind } from "./excludeDappmanagerAndBind.js"; -export async function recreateForceRemovedContainers( - containersToRecreate: string[] -): Promise<void> { +export async function recreateForceRemovedContainers(containersToRecreate: string[]): Promise<void> { if (containersToRecreate.length > 0) { - logs.info( - `Recreating docker containers that require to be recreated: ${containersToRecreate}` - ); + logs.info(`Recreating docker containers that require to be recreated: ${containersToRecreate}`); const composeFilesPathsToRecreate = ( await Promise.all( excludeDappmanagerAndBind(containersToRecreate).map(async (cn) => { // get the compose file path - return (await docker.getContainer(cn).inspect()).Config.Labels[ - "com.docker.compose.project.config_files" - ]; + return (await docker.getContainer(cn).inspect()).Config.Labels["com.docker.compose.project.config_files"]; }) ) ).filter((path, index, self) => { @@ -23,10 +17,6 @@ export async function recreateForceRemovedContainers( return self.indexOf(path) === index; }); - await Promise.all( - composeFilesPathsToRecreate.map( - async (dcPath) => await dockerComposeUp(dcPath) - ) - ); + await Promise.all(composeFilesPathsToRecreate.map(async (dcPath) => await dockerComposeUp(dcPath))); } } diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restartForceStoppedContainers.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restartForceStoppedContainers.ts index 9decb4d02..0dc36c501 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restartForceStoppedContainers.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restartForceStoppedContainers.ts @@ -2,13 +2,9 @@ import { docker } from "@dappnode/dockerapi"; import { logs } from "@dappnode/logger"; import { excludeDappmanagerAndBind } from "./excludeDappmanagerAndBind.js"; -export async function restartForceStoppedContainers( - containersToRestart: string[] -): Promise<void> { +export async function restartForceStoppedContainers(containersToRestart: string[]): Promise<void> { if (containersToRestart.length > 0) { - logs.info( - `Restarting docker containers that require to be restarted: ${containersToRestart}` - ); + logs.info(`Restarting docker containers that require to be restarted: ${containersToRestart}`); await Promise.all( excludeDappmanagerAndBind(containersToRestart).map(async (cn) => { diff --git a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restoreContainersToNetworkNotThrow.ts b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restoreContainersToNetworkNotThrow.ts index c58713323..42d5cddba 100644 --- a/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restoreContainersToNetworkNotThrow.ts +++ b/packages/migrations/src/migrateDockerNetworkIpRange/restoreContainersToNetwork/restoreContainersToNetworkNotThrow.ts @@ -7,7 +7,7 @@ export async function restoreContainersToNetworkNotThrow({ containersToRestart, network, containersToRecreate, - aliasesIpsMap, + aliasesIpsMap }: { containersToRestart: string[]; network: Dockerode.Network; diff --git a/packages/migrations/src/migrateUserActionLogs.ts b/packages/migrations/src/migrateUserActionLogs.ts index ed8622300..73f82375e 100644 --- a/packages/migrations/src/migrateUserActionLogs.ts +++ b/packages/migrations/src/migrateUserActionLogs.ts @@ -22,20 +22,14 @@ export async function migrateUserActionLogs(): Promise<void> { userActionLogs.push({ ...winstonLog, args: winstonLog.args || [winstonLog.kwargs], - timestamp: new Date(winstonLog.timestamp).getTime(), + timestamp: new Date(winstonLog.timestamp).getTime() }); } catch (e) { logs.debug(`Error parsing user action log row: ${e.message}\n${row}`); } } - logUserAction.set( - orderBy( - [...logUserAction.get(), ...userActionLogs], - (log) => log.timestamp, - "desc" - ) - ); + logUserAction.set(orderBy([...logUserAction.get(), ...userActionLogs], (log) => log.timestamp, "desc")); fs.unlinkSync(userActionLogLegacyFile); logs.info(`Migrated ${userActionLogs.length} userActionLogs`); diff --git a/packages/migrations/src/pruneUserActionLogs.ts b/packages/migrations/src/pruneUserActionLogs.ts index cc8009244..567051afe 100644 --- a/packages/migrations/src/pruneUserActionLogs.ts +++ b/packages/migrations/src/pruneUserActionLogs.ts @@ -9,9 +9,7 @@ export async function pruneUserActionLogs(): Promise<void> { // return if no file exists if (!fs.existsSync(params.USER_ACTION_LOGS_DB_PATH)) return; const maxFileSizeBytes = 4194304; // Bytes = 4MB - const currentFileSizeBytes = fs.statSync( - params.USER_ACTION_LOGS_DB_PATH - ).size; + const currentFileSizeBytes = fs.statSync(params.USER_ACTION_LOGS_DB_PATH).size; if (currentFileSizeBytes > maxFileSizeBytes) fs.truncate(params.USER_ACTION_LOGS_DB_PATH, 0, () => console.log(`truncated file ${params.userActionLogsFilename} to 0`) diff --git a/packages/migrations/src/recreateContainersIfLegacyDns.ts b/packages/migrations/src/recreateContainersIfLegacyDns.ts index 7055d049f..b4234f67c 100644 --- a/packages/migrations/src/recreateContainersIfLegacyDns.ts +++ b/packages/migrations/src/recreateContainersIfLegacyDns.ts @@ -24,13 +24,10 @@ export async function recreateContainersIfLegacyDns(): Promise<void> { ); } -async function pkgHasLegacyDns( - containers: PackageContainer[] -): Promise<boolean> { +async function pkgHasLegacyDns(containers: PackageContainer[]): Promise<boolean> { for (const c of containers) { try { - const dns = (await docker.getContainer(c.containerName).inspect()) - .HostConfig.Dns; + const dns = (await docker.getContainer(c.containerName).inspect()).HostConfig.Dns; if (dns && dns.includes(params.DOCKER_LEGACY_DNS)) return true; return false; diff --git a/packages/migrations/src/removeDnsFromComposeFiles.ts b/packages/migrations/src/removeDnsFromComposeFiles.ts index 2d4d21410..a5110473e 100644 --- a/packages/migrations/src/removeDnsFromComposeFiles.ts +++ b/packages/migrations/src/removeDnsFromComposeFiles.ts @@ -4,30 +4,30 @@ import { logs } from "@dappnode/logger"; /** * Migration to allow removal of current Bind functionality - * + * * DNS resolution should be handled by the Docker DNS, not by Bind package - * + * * For every service in every compose file, we must make sure it does not include * the dns configuration */ export async function removeDnsFromComposeFiles(): Promise<void> { - const packages = await listPackages(); + const packages = await listPackages(); - for (const pkg of packages) { - removeDnsFromPackageComposeFile(pkg.dnpName, pkg.isCore); - } + for (const pkg of packages) { + removeDnsFromPackageComposeFile(pkg.dnpName, pkg.isCore); + } } export function removeDnsFromPackageComposeFile(dnpName: string, isCore: boolean): void { - const compose = new ComposeFileEditor(dnpName, isCore); - const services = compose.services(); + const compose = new ComposeFileEditor(dnpName, isCore); + const services = compose.services(); - for (const serviceName of Object.keys(services)) { - const composeService = services[serviceName].get(); - if (composeService.dns) { - logs.info(`Removing DNS from ${serviceName} in ${dnpName} compose file`); - composeService.dns = undefined; - compose.write(); - } + for (const serviceName of Object.keys(services)) { + const composeService = services[serviceName].get(); + if (composeService.dns) { + logs.info(`Removing DNS from ${serviceName} in ${dnpName} compose file`); + composeService.dns = undefined; + compose.write(); } + } } diff --git a/packages/migrations/src/removeLegacyDockerAssets.ts b/packages/migrations/src/removeLegacyDockerAssets.ts index 8f8aabc29..39e428b05 100644 --- a/packages/migrations/src/removeLegacyDockerAssets.ts +++ b/packages/migrations/src/removeLegacyDockerAssets.ts @@ -1,10 +1,5 @@ import { logs } from "@dappnode/logger"; -import { - dockerVolumesList, - dockerVolumeRemove, - dockerContainerRemove, - listPackages, -} from "@dappnode/dockerapi"; +import { dockerVolumesList, dockerVolumeRemove, dockerContainerRemove, listPackages } from "@dappnode/dockerapi"; import fs from "fs"; import { InstalledPackageData } from "@dappnode/types"; import { @@ -13,7 +8,7 @@ import { parseEnvironment, shell, getManifestPath, - getEnvFilePath, + getEnvFilePath } from "@dappnode/utils"; import { ComposeFileEditor } from "@dappnode/dockercompose"; @@ -25,7 +20,7 @@ const volumesToRemove = [ // must be removed for the bind state to be reset "dncore_binddnpdappnodeeth_bind", // Volume shared between ADMIN and VPN to share credentials - "vpndnpdappnodeeth_shared", + "vpndnpdappnodeeth_shared" ]; const dnpsToRemove = [ @@ -35,7 +30,7 @@ const dnpsToRemove = [ "admin.dnp.dappnode.eth", // DNP_ETHFORWARD functionality has been moved to the DAPPMANAGER // The migration is just deleting the container and clearing it's assets - "ethforward.dnp.dappnode.eth", + "ethforward.dnp.dappnode.eth" ]; /** @@ -45,9 +40,7 @@ export async function removeLegacyDockerAssets(): Promise<void> { const dnpList = await listPackages(); const volumes = await dockerVolumesList(); - migrateLegacyEnvFiles(dnpList).catch((e) => - logs.error("Error migrate env_files", e) - ); + migrateLegacyEnvFiles(dnpList).catch((e) => logs.error("Error migrate env_files", e)); // Remove legacy volumes for (const volName of volumesToRemove) @@ -68,19 +61,15 @@ export async function removeLegacyDockerAssets(): Promise<void> { if (dnp) try { // Remove / uninstall DNP - for (const container of dnp.containers) - await dockerContainerRemove(container.containerName); + for (const container of dnp.containers) await dockerContainerRemove(container.containerName); // Clean manifest and docker-compose - for (const filepath of [ - getDockerComposePath(dnpName, true), - getManifestPath(dnpName, true), - ]) + for (const filepath of [getDockerComposePath(dnpName, true), getManifestPath(dnpName, true)]) if (fs.existsSync(filepath)) fs.unlinkSync(filepath); logs.info(`Removed legacy DNP ${dnpName}`); } catch (e) { - logs.error(`Error removing legacy DNP ${dnpName}`); + logs.error(`Error removing legacy DNP ${dnpName}: ${e}`); } } } @@ -92,9 +81,7 @@ export async function removeLegacyDockerAssets(): Promise<void> { * This function will read the contents of .env files and add them in the * compose itself in the `environment` field in array format */ -export async function migrateLegacyEnvFiles( - dnpList: InstalledPackageData[] -): Promise<void> { +export async function migrateLegacyEnvFiles(dnpList: InstalledPackageData[]): Promise<void> { try { for (const dnp of dnpList) migrateLegacyEnvFile(dnp.dnpName, dnp.isCore); logs.info("Finished migrating legacy DNP .env files if any"); @@ -103,10 +90,7 @@ export async function migrateLegacyEnvFiles( } } -export function migrateLegacyEnvFile( - dnpName: string, - isCore: boolean -): boolean { +export function migrateLegacyEnvFile(dnpName: string, isCore: boolean): boolean { const envFilePath = getEnvFilePath(dnpName, isCore); try { const envFileData = fs.readFileSync(envFilePath, "utf8"); @@ -123,13 +107,10 @@ export function migrateLegacyEnvFile( logs.info(`Converted ${dnpName} .env file to compose environment`); return true; } else { - throw Error( - `Can not migrate ENVs for multi-service packages: ${dnpName}` - ); + throw Error(`Can not migrate ENVs for multi-service packages: ${dnpName}`); } } catch (e) { - if (!isNotFoundError(e)) - logs.error(`Error migrating ${dnpName} .env file`, e); + if (!isNotFoundError(e)) logs.error(`Error migrating ${dnpName} .env file`, e); return false; } } diff --git a/packages/migrations/test/int/aliasMigration.test.int.ts b/packages/migrations/test/int/aliasMigration.test.int.ts index a34463494..ddde2826a 100644 --- a/packages/migrations/test/int/aliasMigration.test.int.ts +++ b/packages/migrations/test/int/aliasMigration.test.int.ts @@ -24,7 +24,7 @@ const monoContainer: PackageContainer = { dnpName: `${DNP_NAME_MONO}`, serviceName: `${DNP_NAME_MONO}`, isCore: false, - isMain: true, + isMain: true }; const monoContainerPublic: PackageContainer = { @@ -33,7 +33,7 @@ const monoContainerPublic: PackageContainer = { dnpName: `${DNP_NAME_MONO_PUBLIC}`, serviceName: `service`, isCore: false, - isMain: true, + isMain: true }; const containerMain: PackageContainer = { @@ -42,7 +42,7 @@ const containerMain: PackageContainer = { dnpName: `${DNP_NAME}`, serviceName: "mainService", isMain: true, - isCore: false, + isCore: false }; const containerNotMain: PackageContainer = { @@ -51,7 +51,7 @@ const containerNotMain: PackageContainer = { dnpName: `${DNP_NAME}`, serviceName: "notmainService", isMain: false, - isCore: false, + isCore: false }; const containerMainPublic: PackageContainer = { @@ -60,7 +60,7 @@ const containerMainPublic: PackageContainer = { dnpName: `${DNP_NAME_PUBLIC}`, serviceName: "mainService", isMain: true, - isCore: false, + isCore: false }; const containerNotMainPublic: PackageContainer = { @@ -69,7 +69,7 @@ const containerNotMainPublic: PackageContainer = { dnpName: `${DNP_NAME_PUBLIC}`, serviceName: "notmainService", isMain: false, - isCore: false, + isCore: false }; //We check 6 possible containers: @@ -85,7 +85,7 @@ const containers = [ monoContainer, containerMainPublic, containerNotMainPublic, - monoContainerPublic, + monoContainerPublic ]; const CONTAINER_COMPOSE = ` @@ -155,20 +155,13 @@ async function ensureNetworkExists(networkName: string) { } // Inspect each container and fetch the aliases on the dncore network -async function getContainerAliasesOnNetwork( - containerName: string, - networkName: string -) { - const inspectData = await shellSafe( - `docker container inspect ${containerName}` - ); - if (!inspectData) - throw new Error(`Error inspecting container ${containerName}`); +async function getContainerAliasesOnNetwork(containerName: string, networkName: string) { + const inspectData = await shellSafe(`docker container inspect ${containerName}`); + if (!inspectData) throw new Error(`Error inspecting container ${containerName}`); const parsedData = JSON.parse(inspectData); // Extract the aliases from the specified network - const aliases = - parsedData[0]?.NetworkSettings?.Networks?.[networkName]?.Aliases || []; + const aliases = parsedData[0]?.NetworkSettings?.Networks?.[networkName]?.Aliases || []; return aliases; } @@ -196,7 +189,7 @@ describe("Add alias to running containers", function () { { path: TEST_ALIAS_PATH, content: CONTAINER_COMPOSE }, { path: TEST_ALIAS_PATH_PUBLIC, content: CONTAINER_COMPOSE_PUBLIC }, { path: TEST_ALIAS_PATH_MONO, content: MONO_COMPOSE }, - { path: TEST_ALIAS_PATH_MONO_PUBLIC, content: MONO_COMPOSE_PUBLIC }, + { path: TEST_ALIAS_PATH_MONO_PUBLIC, content: MONO_COMPOSE_PUBLIC } ]; for (const config of composeConfigs) { @@ -217,7 +210,7 @@ describe("Add alias to running containers", function () { containerMainPublic.containerName, containerNotMainPublic.containerName, monoContainer.containerName, - monoContainerPublic.containerName, + monoContainerPublic.containerName ]; // Check if all containers exist @@ -239,63 +232,41 @@ describe("Add alias to running containers", function () { const containersToTest = [ { container: containerMain, - expectedAliases: ["mainService.logger.dappnode", "logger.dappnode"], + expectedAliases: ["mainService.logger.dappnode", "logger.dappnode"] }, { container: containerNotMain, - expectedAliases: ["notmainService.logger.dappnode"], + expectedAliases: ["notmainService.logger.dappnode"] }, { container: monoContainer, - expectedAliases: [ - "logger-mono.dnp.dappnode.eth.logger-mono.dappnode", - "logger-mono.dappnode", - ], + expectedAliases: ["logger-mono.dnp.dappnode.eth.logger-mono.dappnode", "logger-mono.dappnode"] }, { container: monoContainerPublic, - expectedAliases: [ - "service.logger-mono.public.dappnode", - "logger-mono.public.dappnode", - ], + expectedAliases: ["service.logger-mono.public.dappnode", "logger-mono.public.dappnode"] }, { container: containerMainPublic, - expectedAliases: [ - "mainService.logger.public.dappnode", - "logger.public.dappnode", - ], + expectedAliases: ["mainService.logger.public.dappnode", "logger.public.dappnode"] }, { container: containerNotMainPublic, - expectedAliases: ["notmainService.logger.public.dappnode"], - }, + expectedAliases: ["notmainService.logger.public.dappnode"] + } ]; for (const { container, expectedAliases } of containersToTest) { - const actualAliases = await getContainerAliasesOnNetwork( - container.containerName, - DNCORE_NETWORK - ); + const actualAliases = await getContainerAliasesOnNetwork(container.containerName, DNCORE_NETWORK); expect(actualAliases).to.include.members(expectedAliases); } }); after("Cleanup", async () => { - const containerNames = containers.map( - (container) => container.containerName - ); - const directoryPaths = [ - TEST_ALIAS_PATH, - TEST_ALIAS_PATH_MONO, - TEST_ALIAS_PATH_PUBLIC, - TEST_ALIAS_PATH_MONO_PUBLIC, - ]; + const containerNames = containers.map((container) => container.containerName); + const directoryPaths = [TEST_ALIAS_PATH, TEST_ALIAS_PATH_MONO, TEST_ALIAS_PATH_PUBLIC, TEST_ALIAS_PATH_MONO_PUBLIC]; - await Promise.all([ - stopAndRemoveContainers(containerNames), - removeDirectories(directoryPaths), - ]); + await Promise.all([stopAndRemoveContainers(containerNames), removeDirectories(directoryPaths)]); // Remove the DNCORE_NETWORK if it exists await shellSafe(`docker network rm ${DNCORE_NETWORK}`); diff --git a/packages/migrations/test/int/composeMigration.test.int.ts b/packages/migrations/test/int/composeMigration.test.int.ts index 9d0a52328..96189959b 100644 --- a/packages/migrations/test/int/composeMigration.test.int.ts +++ b/packages/migrations/test/int/composeMigration.test.int.ts @@ -21,8 +21,8 @@ describe("Migration", () => { serviceName, networks: [ { name: "random", ip: "10.0.1.1" }, - { name: "dncore_network", ip: "172.33.1.7" }, - ], + { name: "dncore_network", ip: "172.33.1.7" } + ] }; const composeNoDns = ` @@ -80,53 +80,35 @@ services: // Create compose await shellSafe(`mkdir -p ${testPackagePath}`); // Compose to be migrated - fs.writeFileSync( - `${testPackagePath}/docker-compose.yml`, - composeToBeMigratedBefore - ); + fs.writeFileSync(`${testPackagePath}/docker-compose.yml`, composeToBeMigratedBefore); // Startup container - await shellSafe( - `docker compose -f ${testPackagePath}/docker-compose.yml -p DNCORE up -d` - ); - const containerExists = await shellSafe( - `docker container ls --filter name=${containerName}` - ); + await shellSafe(`docker compose -f ${testPackagePath}/docker-compose.yml -p DNCORE up -d`); + const containerExists = await shellSafe(`docker container ls --filter name=${containerName}`); - const networkExists = await shellSafe( - `docker network ls --filter name=${dncoreNetwork}` - ); + const networkExists = await shellSafe(`docker network ls --filter name=${dncoreNetwork}`); - if (!containerExists || !networkExists) - throw Error("Error creating container or/and dncore_network"); + if (!containerExists || !networkExists) throw Error("Error creating container or/and dncore_network"); }); it("Should do alias migration in compose", async () => { const aliases = ["test.test-migration.dappnode", "test.dappnode"]; migrateCoreNetworkAndAliasInCompose(container, aliases); - const composeAfter = fs.readFileSync( - `${testPackagePath}/docker-compose.yml`, - { encoding: "utf8" } - ); + const composeAfter = fs.readFileSync(`${testPackagePath}/docker-compose.yml`, { encoding: "utf8" }); expect(composeAfter.trim()).to.equal(composeAlreadyMigrated.trim()); }); it("Should remove DNS from compose file", async () => { removeDnsFromPackageComposeFile(container.dnpName, false); - const composeAfter = fs.readFileSync( - `${testPackagePath}/docker-compose.yml`, - { encoding: "utf8" } - ); + const composeAfter = fs.readFileSync(`${testPackagePath}/docker-compose.yml`, { encoding: "utf8" }); expect(composeAfter.trim()).to.equal(composeNoDns.trim()); }); after("Remove test setup", async () => { // Disconnect from network - await shellSafe( - `docker network disconnect ${dncoreNetwork} ${containerName} --force` - ); + await shellSafe(`docker network disconnect ${dncoreNetwork} ${containerName} --force`); // Remove network await shellSafe(`docker network rm dncore_network`); // Remove container diff --git a/packages/migrations/test/int/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio.test.int.ts b/packages/migrations/test/int/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio.test.int.ts index e05b6a21c..8fb4a34e5 100644 --- a/packages/migrations/test/int/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio.test.int.ts +++ b/packages/migrations/test/int/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio.test.int.ts @@ -1,10 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - docker, - dockerNetworkConnect, - getNetworkAliasesIpsMapNotThrow, -} from "@dappnode/dockerapi"; +import { docker, dockerNetworkConnect, getNetworkAliasesIpsMapNotThrow } from "@dappnode/dockerapi"; import { connectContainersToNetworkWithPrio } from "../../../src/migrateDockerNetworkIpRange/connectContainersToNetworkWithPrio/index.js"; import Dockerode from "dockerode"; @@ -16,15 +12,14 @@ describe("Ensure docker network config migration => connectContainersToNetworkW const dappmanagerIp = "172.30.0.7"; const bindContainerName = "DAppNodeCore-bind.dnp.dappnode.eth"; const bindIp = "172.30.0.2"; - const containerUsingDappmanagerIp = - "DAppNodePackage-validator.web3signer.dnp.dappnode.eth"; + const containerUsingDappmanagerIp = "DAppNodePackage-validator.web3signer.dnp.dappnode.eth"; const containerUsingBindIp = "DAppNodePackage-rotki.dnp.dappnode.eth"; const containerNames = [ dappmanagerContainerName, bindContainerName, containerUsingDappmanagerIp, - containerUsingBindIp, + containerUsingBindIp ]; let network: Dockerode.Network; @@ -38,7 +33,7 @@ describe("Ensure docker network config migration => connectContainersToNetworkW const container = await docker.createContainer({ Image: dockerImageTest, Cmd: ["tail", "-f", "/dev/null"], // Keep the container running - name: cn, + name: cn }); await container.start(); }) @@ -51,22 +46,22 @@ describe("Ensure docker network config migration => connectContainersToNetworkW Driver: "default", Config: [ { - Subnet: dockerNetworkSubnet, - }, - ], - }, + Subnet: dockerNetworkSubnet + } + ] + } })) as Dockerode.Network; // connect duplicate of dappmanager await dockerNetworkConnect(networkName, containerUsingDappmanagerIp, { IPAMConfig: { - IPv4Address: dappmanagerIp, - }, + IPv4Address: dappmanagerIp + } }); // connect duplicate of bind await dockerNetworkConnect(networkName, containerUsingBindIp, { IPAMConfig: { - IPv4Address: bindIp, - }, + IPv4Address: bindIp + } }); }); @@ -77,25 +72,21 @@ describe("Ensure docker network config migration => connectContainersToNetworkW network, dappmanagerContainer: { name: dappmanagerContainerName, - ip: dappmanagerIp, + ip: dappmanagerIp }, bindContainer: { name: bindContainerName, - ip: bindIp, + ip: bindIp }, aliasesIpsMap, containersToRestart: [], - containersToRecreate: [], + containersToRecreate: [] }); - const ipResult = (await docker.getContainer(bindContainerName).inspect()) - .NetworkSettings.Networks[networkName].IPAddress; + const ipResult = (await docker.getContainer(bindContainerName).inspect()).NetworkSettings.Networks[networkName] + .IPAddress; // verify bind container with expected ip expect(ipResult).to.deep.equal(bindIp); - const containers = ( - (await docker - .getNetwork(networkName) - .inspect()) as Dockerode.NetworkInspectInfo - ).Containers; + const containers = ((await docker.getNetwork(networkName).inspect()) as Dockerode.NetworkInspectInfo).Containers; if (!containers) throw Error("containers not exist"); const containerNames = Object.values(containers).map((c) => c.Name); expect(containerNames).to.include(containerUsingBindIp); @@ -105,8 +96,7 @@ describe("Ensure docker network config migration => connectContainersToNetworkW }); after(async () => { - for (const cn of containerNames) - await docker.getContainer(cn).remove({ force: true }); + for (const cn of containerNames) await docker.getContainer(cn).remove({ force: true }); // remove docker network await docker.getNetwork(networkName).remove(); diff --git a/packages/migrations/test/int/migrateDockerNetworkIpRange/ensureDockerNetworkConfig.test.int.ts b/packages/migrations/test/int/migrateDockerNetworkIpRange/ensureDockerNetworkConfig.test.int.ts index 784d074dc..84d115fcb 100644 --- a/packages/migrations/test/int/migrateDockerNetworkIpRange/ensureDockerNetworkConfig.test.int.ts +++ b/packages/migrations/test/int/migrateDockerNetworkIpRange/ensureDockerNetworkConfig.test.int.ts @@ -1,22 +1,14 @@ import "mocha"; import { expect } from "chai"; import { ensureDockerNetworkConfig } from "../../../src/migrateDockerNetworkIpRange/ensureDockerNetworkConfig/index.js"; -import { - docker, - dockerNetworkConnect, - getNetworkAliasesIpsMapNotThrow, -} from "@dappnode/dockerapi"; +import { docker, dockerNetworkConnect, getNetworkAliasesIpsMapNotThrow } from "@dappnode/dockerapi"; import Dockerode from "dockerode"; describe("Ensure docker network config migration => ensureDockerNetworkConfig", () => { const dockerNetworkName = "dncore_test"; const dockerNetworkSubnet = "172.30.0.0/16"; const dockerImageTest = "alpine"; - const containerNames = [ - "test_container_1", - "test_container_2", - "test_container_3", - ]; // Define container names + const containerNames = ["test_container_1", "test_container_2", "test_container_3"]; // Define container names before(async () => { // get alpine docker images @@ -27,7 +19,7 @@ describe("Ensure docker network config migration => ensureDockerNetworkConfig", const container = await docker.createContainer({ Image: dockerImageTest, Cmd: ["tail", "-f", "/dev/null"], // Keep the container running - name: cn, + name: cn }); await container.start(); }) @@ -41,18 +33,14 @@ describe("Ensure docker network config migration => ensureDockerNetworkConfig", Driver: "default", Config: [ { - Subnet: dockerNetworkSubnet, - }, - ], - }, + Subnet: dockerNetworkSubnet + } + ] + } }); // connect al containers to network - await Promise.all( - containerNames.map( - async (cn) => await dockerNetworkConnect(dockerNetworkName, cn) - ) - ); + await Promise.all(containerNames.map(async (cn) => await dockerNetworkConnect(dockerNetworkName, cn))); }); it("should ensure the docker network config", async () => { @@ -60,35 +48,25 @@ describe("Ensure docker network config migration => ensureDockerNetworkConfig", await ensureDockerNetworkConfig({ networkName: dockerNetworkName, networkSubnet: newDockerNetworkSubnet, - aliasesIpsMap: await getNetworkAliasesIpsMapNotThrow(dockerNetworkName), + aliasesIpsMap: await getNetworkAliasesIpsMapNotThrow(dockerNetworkName) }); - const recreatedNetwork: Dockerode.NetworkInspectInfo = await docker - .getNetwork(dockerNetworkName) - .inspect(); + const recreatedNetwork: Dockerode.NetworkInspectInfo = await docker.getNetwork(dockerNetworkName).inspect(); const recreatedNetworkConfig = recreatedNetwork.IPAM?.Config; if (!recreatedNetworkConfig) throw Error("docker network config not found"); // validate new ip range - expect(recreatedNetworkConfig[0].Subnet).to.deep.equal( - newDockerNetworkSubnet - ); + expect(recreatedNetworkConfig[0].Subnet).to.deep.equal(newDockerNetworkSubnet); // validate all containers are connected - const containers = ( - (await docker - .getNetwork(dockerNetworkName) - .inspect()) as Dockerode.NetworkInspectInfo - ).Containers; + const containers = ((await docker.getNetwork(dockerNetworkName).inspect()) as Dockerode.NetworkInspectInfo) + .Containers; if (!containers) throw Error("containers not exist"); - const containerNamesConnected = Object.values(containers).map( - (c) => c.Name - ); + const containerNamesConnected = Object.values(containers).map((c) => c.Name); for (const cn of containerNamesConnected) { expect(containerNames).to.include(cn); } }); after(async () => { - for (const cn of containerNames) - await docker.getContainer(cn).remove({ force: true }); + for (const cn of containerNames) await docker.getContainer(cn).remove({ force: true }); // remove docker network await docker.getNetwork(dockerNetworkName).remove(); diff --git a/packages/migrations/test/testUtils.ts b/packages/migrations/test/testUtils.ts index 44a180c30..8dcfaa223 100644 --- a/packages/migrations/test/testUtils.ts +++ b/packages/migrations/test/testUtils.ts @@ -28,7 +28,7 @@ export const mockContainer: PackageContainer = { defaultVolumes: [], dependencies: {}, origin: "", - avatarUrl: "", + avatarUrl: "" }; function ignoreErrors<A, R>(fn: (arg: A) => R) { @@ -37,6 +37,7 @@ function ignoreErrors<A, R>(fn: (arg: A) => R) { return await fn(arg); } catch (e) { // Ignore + console.error(e); } }; } diff --git a/packages/migrations/test/unit/subnetsOverlap.unit.test.ts b/packages/migrations/test/unit/subnetsOverlap.unit.test.ts index 9bb2433fa..e987fbcaa 100644 --- a/packages/migrations/test/unit/subnetsOverlap.unit.test.ts +++ b/packages/migrations/test/unit/subnetsOverlap.unit.test.ts @@ -16,9 +16,7 @@ describe("Subnet Overlap Tests", () => { }); it("should throw an error for invalid inputs", () => { - expect(() => - subnetsOverlap("192.168.1.300/24", "192.168.2.0/24") - ).to.throw(); + expect(() => subnetsOverlap("192.168.1.300/24", "192.168.2.0/24")).to.throw(); expect(() => subnetsOverlap("192.168.1.0/24", "invalid")).to.throw(); expect(() => subnetsOverlap("172.33.0.0/40", "172.33.0.0/16")).to.throw(); }); diff --git a/packages/optimism/.eslintignore b/packages/optimism/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/optimism/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/optimism/.eslintrc.cjs b/packages/optimism/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/optimism/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/optimism/package.json b/packages/optimism/package.json index 5fc03915c..4ddd04f42 100644 --- a/packages/optimism/package.json +++ b/packages/optimism/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/optimism/src/getOptimismConfig.ts b/packages/optimism/src/getOptimismConfig.ts index 0387b87f5..7dda2feff 100644 --- a/packages/optimism/src/getOptimismConfig.ts +++ b/packages/optimism/src/getOptimismConfig.ts @@ -3,22 +3,15 @@ import { OptimismItem, executionClientsOptimism, optimismL2Geth, - optimismNode, + optimismNode } from "@dappnode/types"; import * as db from "@dappnode/db"; import { listPackages } from "@dappnode/dockerapi"; import { DappnodeInstaller, packageGetData } from "@dappnode/installer"; -import { - getIsInstalled, - getIsRunning, - getIsUpdated, - fileToGatewayUrl, -} from "@dappnode/utils"; +import { getIsInstalled, getIsRunning, getIsUpdated, fileToGatewayUrl } from "@dappnode/utils"; import { getOptimismNodeRpcUrlIfExists } from "./getOptimismNodeRpcUrlIfExists.js"; -export async function getOptimismConfig( - dappnodeInstaller: DappnodeInstaller -): Promise<OptimismConfigGet> { +export async function getOptimismConfig(dappnodeInstaller: DappnodeInstaller): Promise<OptimismConfigGet> { try { const currentOptimismExecutionClient = db.opExecutionClient.get(); const enableHistorical = db.opEnableHistoricalRpc.get(); @@ -42,14 +35,14 @@ export async function getOptimismConfig( isRunning: getIsRunning(pkgData, dnpList), data: pkgData, isSelected: execClient === currentOptimismExecutionClient, - enableHistorical, + enableHistorical }; } catch (error) { return { status: "error", dnpName: execClient, error, - enableHistorical, + enableHistorical }; } }) @@ -60,10 +53,7 @@ export async function getOptimismConfig( // make sure the repo exists await dappnodeInstaller.getRepoContract(optimismNode); - const pkgData = await packageGetData( - dappnodeInstaller, - optimismNode - ); + const pkgData = await packageGetData(dappnodeInstaller, optimismNode); const mainnetRpcUrl = getOptimismNodeRpcUrlIfExists(); const isRunning = getIsRunning(pkgData, dnpList); resolve({ @@ -75,14 +65,14 @@ export async function getOptimismConfig( isRunning, data: pkgData, isSelected: isRunning, - mainnetRpcUrl, + mainnetRpcUrl }); } catch (error) { resolve({ status: "error", dnpName: optimismNode, error, - mainnetRpcUrl: "", + mainnetRpcUrl: "" }); } })(); @@ -94,10 +84,7 @@ export async function getOptimismConfig( // make sure the repo exists await dappnodeInstaller.getRepoContract(optimismL2Geth); - const pkgData = await packageGetData( - dappnodeInstaller, - optimismL2Geth - ); + const pkgData = await packageGetData(dappnodeInstaller, optimismL2Geth); const isRunning = getIsRunning(pkgData, dnpList); resolve({ status: "ok", @@ -107,17 +94,17 @@ export async function getOptimismConfig( isUpdated: getIsUpdated(pkgData, dnpList), isRunning, data: pkgData, - isSelected: isRunning && enableHistorical, + isSelected: isRunning && enableHistorical }); } catch (error) { resolve({ status: "error", dnpName: optimismL2Geth, - error, + error }); } })(); - }), + }) }; } catch (e) { throw Error(`Error getting Optimism config: ${e}`); diff --git a/packages/optimism/src/getOptimismNodeRpcUrlIfExists.ts b/packages/optimism/src/getOptimismNodeRpcUrlIfExists.ts index 7bd45d17d..34fe6d638 100644 --- a/packages/optimism/src/getOptimismNodeRpcUrlIfExists.ts +++ b/packages/optimism/src/getOptimismNodeRpcUrlIfExists.ts @@ -3,11 +3,6 @@ import { ComposeFileEditor } from "@dappnode/dockercompose"; import { opNodeRpcUrlEnvName, opNodeServiceName } from "./params.js"; export function getOptimismNodeRpcUrlIfExists(): string { - const userSettings = ComposeFileEditor.getUserSettingsIfExist( - optimismNode, - false - ); - return userSettings.environment - ? userSettings.environment[opNodeServiceName][opNodeRpcUrlEnvName] - : ""; + const userSettings = ComposeFileEditor.getUserSettingsIfExist(optimismNode, false); + return userSettings.environment ? userSettings.environment[opNodeServiceName][opNodeRpcUrlEnvName] : ""; } diff --git a/packages/optimism/src/params.ts b/packages/optimism/src/params.ts index 57996ef69..6b28e6353 100644 --- a/packages/optimism/src/params.ts +++ b/packages/optimism/src/params.ts @@ -8,5 +8,5 @@ export const historicalRpcUrl = "http://op-l2geth.dappnode:8545"; export const opClientToServiceMap: Record<ExecutionClientOptimism, string> = { "op-geth.dnp.dappnode.eth": "geth", - "op-erigon.dnp.dappnode.eth": "erigon", + "op-erigon.dnp.dappnode.eth": "erigon" }; diff --git a/packages/optimism/src/setOptimismConfig.ts b/packages/optimism/src/setOptimismConfig.ts index 4af08a66b..09fb056f5 100644 --- a/packages/optimism/src/setOptimismConfig.ts +++ b/packages/optimism/src/setOptimismConfig.ts @@ -5,26 +5,18 @@ import { optimismNode, optimismL2Geth, executionClientsOptimism, - ExecutionClientOptimism, + ExecutionClientOptimism } from "@dappnode/types"; import * as db from "@dappnode/db"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - dockerContainerStart, - dockerContainerStop, - listPackageNoThrow, -} from "@dappnode/dockerapi"; -import { - packageSetEnvironment, - packageInstall, - DappnodeInstaller, -} from "@dappnode/installer"; +import { dockerContainerStart, dockerContainerStop, listPackageNoThrow } from "@dappnode/dockerapi"; +import { packageSetEnvironment, packageInstall, DappnodeInstaller } from "@dappnode/installer"; import { opNodeServiceName, opNodeRpcUrlEnvName, historicalRpcUrl, opExecutionClientHistoricalRpcUrlEnvName, - opClientToServiceMap, + opClientToServiceMap } from "./params.js"; export async function setOptimismConfig( @@ -33,7 +25,7 @@ export async function setOptimismConfig( ): Promise<void> { // l2geth; const l2gethPackage = await listPackageNoThrow({ - dnpName: optimismL2Geth, + dnpName: optimismL2Geth }); if (archive) { @@ -43,41 +35,37 @@ export async function setOptimismConfig( } else { await startAllContainers(l2gethPackage); } - if (db.opEnableHistoricalRpc.get() !== true) - await db.opEnableHistoricalRpc.set(true); + if (db.opEnableHistoricalRpc.get() !== true) await db.opEnableHistoricalRpc.set(true); } else { if (l2gethPackage) await stopAllContainers([l2gethPackage]); - if (db.opEnableHistoricalRpc.get() !== false) - await db.opEnableHistoricalRpc.set(false); + if (db.opEnableHistoricalRpc.get() !== false) await db.opEnableHistoricalRpc.set(false); } // op Execution clients: op-geth || op-erigon if (executionClient) { const targetOpExecutionClientPackage = await listPackageNoThrow({ - dnpName: executionClient.dnpName, + dnpName: executionClient.dnpName }); const userSettings: UserSettings = { environment: { [opClientToServiceMap[executionClient.dnpName]]: { - [opExecutionClientHistoricalRpcUrlEnvName]: historicalRpcUrl, // TODO: Empty if not archive? - }, - }, + [opExecutionClientHistoricalRpcUrlEnvName]: historicalRpcUrl // TODO: Empty if not archive? + } + } }; if (!targetOpExecutionClientPackage) { // make sure target package is installed await packageInstall(dappnodeInstaller, { name: executionClient.dnpName, - userSettings: { [executionClient.dnpName]: userSettings }, + userSettings: { [executionClient.dnpName]: userSettings } }); } else { await packageSetEnvironment({ dnpName: executionClient.dnpName, - environmentByService: userSettings.environment - ? userSettings.environment - : {}, + environmentByService: userSettings.environment ? userSettings.environment : {} }); await startAllContainers(targetOpExecutionClientPackage); @@ -99,36 +87,29 @@ export async function setOptimismConfig( const userSettings: UserSettings = { environment: { [opNodeServiceName]: { - [opNodeRpcUrlEnvName]: rollup.mainnetRpcUrl, - }, - }, + [opNodeRpcUrlEnvName]: rollup.mainnetRpcUrl + } + } }; // make sure op-node is installed await packageInstall(dappnodeInstaller, { name: optimismNode, - userSettings: { [optimismNode]: userSettings }, + userSettings: { [optimismNode]: userSettings } }); } else { await startAllContainers(opNodePackage); // check if the current env is the same as the new one - const opNodeUserSettings = new ComposeFileEditor( - optimismNode, - false - ).getUserSettings(); - - if ( - opNodeUserSettings.environment?.[opNodeServiceName]?.[ - opNodeRpcUrlEnvName - ] !== rollup.mainnetRpcUrl - ) { + const opNodeUserSettings = new ComposeFileEditor(optimismNode, false).getUserSettings(); + + if (opNodeUserSettings.environment?.[opNodeServiceName]?.[opNodeRpcUrlEnvName] !== rollup.mainnetRpcUrl) { await packageSetEnvironment({ dnpName: optimismNode, environmentByService: { [opNodeServiceName]: { - [opNodeRpcUrlEnvName]: rollup.mainnetRpcUrl, - }, - }, + [opNodeRpcUrlEnvName]: rollup.mainnetRpcUrl + } + } }); } } @@ -137,12 +118,8 @@ export async function setOptimismConfig( } } -async function stopOtherOpExecutionClients( - executionClient: ExecutionClientOptimism -): Promise<void> { - const otherOpExecutionClientDnps = executionClientsOptimism.filter( - (client) => client !== executionClient - ); +async function stopOtherOpExecutionClients(executionClient: ExecutionClientOptimism): Promise<void> { + const otherOpExecutionClientDnps = executionClientsOptimism.filter((client) => client !== executionClient); await stopPkgsByDnpNames(otherOpExecutionClientDnps); } @@ -160,11 +137,9 @@ async function stopPkgsByDnpNames(dnpNames: ExecutionClientOptimism[]) { async function stopAllContainers(pkgs: InstalledPackageData[]): Promise<void> { for (const pkg of pkgs) - for (const container of pkg.containers) - if (container.running) await dockerContainerStop(container.containerName); + for (const container of pkg.containers) if (container.running) await dockerContainerStop(container.containerName); } async function startAllContainers(pkg: InstalledPackageData): Promise<void> { - for (const container of pkg.containers) - if (!container.running) await dockerContainerStart(container.containerName); + for (const container of pkg.containers) if (!container.running) await dockerContainerStart(container.containerName); } diff --git a/packages/params/.eslintignore b/packages/params/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/params/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/params/.eslintrc.cjs b/packages/params/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/params/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/params/package.json b/packages/params/package.json index 5bab3a94e..06c5e4c7e 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/types": "workspace:^0.1.0" diff --git a/packages/params/src/params.ts b/packages/params/src/params.ts index 647f6f826..ec66f0a95 100644 --- a/packages/params/src/params.ts +++ b/packages/params/src/params.ts @@ -57,22 +57,16 @@ export const params = { // Host script paths HOST_SCRIPTS_DIR_FROM_HOST: path.join(HOST_HOME, "DNCORE/scripts/host"), HOST_SCRIPTS_DIR: "DNCORE/scripts/host", - HOST_SCRIPTS_SOURCE_DIR: process.env.TEST - ? "/app/packages/hostScriptsServices/hostScripts" - : "hostScripts", + HOST_SCRIPTS_SOURCE_DIR: process.env.TEST ? "/app/packages/hostScriptsServices/hostScripts" : "hostScripts", // Host services paths HOST_SERVICES_DIR_FROM_HOST: path.join(HOST_HOME, "DNCORE/services/host"), HOST_SYSTEMD_DIR_FROM_HOST: "/etc/systemd/system", HOST_SERVICES_DIR: "DNCORE/services/host", - HOST_SERVICES_SOURCE_DIR: process.env.TEST - ? "/app/packages/hostScriptsServices/hostServices" - : "hostServices", + HOST_SERVICES_SOURCE_DIR: process.env.TEST ? "/app/packages/hostScriptsServices/hostServices" : "hostServices", // Host timer paths HOST_TIMERS_DIR_FROM_HOST: path.join(HOST_HOME, "DNCORE/timers/host"), HOST_TIMERS_DIR: "DNCORE/timers/host", - HOST_TIMERS_SOURCE_DIR: process.env.TEST - ? "/app/packages/hostScriptsServices/hostTimers" - : "hostTimers", + HOST_TIMERS_SOURCE_DIR: process.env.TEST ? "/app/packages/hostScriptsServices/hostTimers" : "hostTimers", // Local fallback versions, to be able to install and eth client without connecting to remote FALLBACK_VERSIONS_PATH: path.join(DNCORE_DIR, "packages-content-hash.csv"), // Version data file, created in the docker image build process @@ -92,7 +86,7 @@ export const params = { "http://localhost:3000", "http://localhost:3001", "http://my.dappnode", - "http://dappnode.local", + "http://dappnode.local" ], // API auth sessions @@ -127,7 +121,7 @@ export const params = { [Network.Holesky]: "holesky_network", [Network.Prater]: "prater_network", [Network.Gnosis]: "gnosis_network", - [Network.Lukso]: "lukso_network", + [Network.Lukso]: "lukso_network" }, DOCKER_LEGACY_DNS: "172.33.1.2", BIND_IP: "172.33.1.2", // "10.20.0.2" @@ -164,8 +158,7 @@ export const params = { // Web3 parameters ETH_MAINNET_RPC_URL_OVERRIDE: process.env.ETH_MAINNET_RPC_OVERRIDE, - ETH_MAINNET_RPC_URL_REMOTE: - process.env.ETH_MAINNET_RPC_URL_REMOTE || "https://web3.dappnode.net", + ETH_MAINNET_RPC_URL_REMOTE: process.env.ETH_MAINNET_RPC_URL_REMOTE || "https://web3.dappnode.net", ETH_MAINNET_CHECKPOINTSYNC_URL_REMOTE: "https://checkpoint-sync.dappnode.io", // Prysm legacy specs for: prater, gnosis and mainnet @@ -179,8 +172,8 @@ export const params = { "teku-prater.dnp.dappnode.eth", "lighthouse-prater.dnp.dappnode.eth", "nimbus-prater.dnp.dappnode.eth", - "lodestar-prater.dnp.dappnode.eth", - ], + "lodestar-prater.dnp.dappnode.eth" + ] }, // v0.2.51 { @@ -191,8 +184,8 @@ export const params = { "teku-gnosis.dnp.dappnode.eth", "lighthouse-gnosis.dnp.dappnode.eth", "nimbus-gnosis.dnp.dappnode.eth", - "lodestar-gnosis.dnp.dappnode.eth", - ], + "lodestar-gnosis.dnp.dappnode.eth" + ] }, // v0.2.52 { @@ -203,17 +196,13 @@ export const params = { "teku.dnp.dappnode.eth", "lighthouse.dnp.dappnode.eth", "nimbus.dnp.dappnode.eth", - "lodestar.dnp.dappnode.eth", - ], - }, + "lodestar.dnp.dappnode.eth" + ] + } ], // DAPPMANAGER alias - DAPPMANAGER_ALIASES: [ - "dappmanager.dappnode", - "my.dappnode", - "dappnode.local", - ], + DAPPMANAGER_ALIASES: ["dappmanager.dappnode", "my.dappnode", "dappnode.local"], // DAppNode specific names bindDnpName: "bind.dnp.dappnode.eth", @@ -231,26 +220,20 @@ export const params = { vpnDataVolume: "dncore_vpndnpdappnodeeth_data", wireguardContainerName: "DAppNodeCore-wireguard.wireguard.dnp.dappnode.eth", restartContainerName: "DAppNodeTool-restart.dnp.dappnode.eth", - restartDnpVolumes: [ - "/usr/src/dappnode/DNCORE/:/usr/src/app/DNCORE/", - "/var/run/docker.sock:/var/run/docker.sock", - ], - corePackagesThatMustBeRunning: [ - "bind.dnp.dappnode.eth", - "dappmanager.dnp.dappnode.eth", - ], + restartDnpVolumes: ["/usr/src/dappnode/DNCORE/:/usr/src/app/DNCORE/", "/var/run/docker.sock:/var/run/docker.sock"], + corePackagesThatMustBeRunning: ["bind.dnp.dappnode.eth", "dappmanager.dnp.dappnode.eth"], corePackagesNotAutoupdatable: [ "core.dnp.dappnode.eth", "bind.dnp.dappnode.eth", "dappmanager.dnp.dappnode.eth", "ipfs.dnp.dappnode.eth", - "wifi.dnp.dappnode.eth", + "wifi.dnp.dappnode.eth" ], corePackagesNotRemovable: [ "bind.dnp.dappnode.eth", "dappmanager.dnp.dappnode.eth", "ipfs.dnp.dappnode.eth", - "wifi.dnp.dappnode.eth", + "wifi.dnp.dappnode.eth" ], // DYNDNS parameters @@ -274,18 +257,14 @@ export const params = { GLOBAL_ENVS_PREFIX: "_DAPPNODE_GLOBAL_", // nsenter line to run commands on host - NSENTER_COMMAND: - "docker run --rm --privileged --pid=host -t alpine:3.8 nsenter -t 1 -m -u -n -i", + NSENTER_COMMAND: "docker run --rm --privileged --pid=host -t alpine:3.8 nsenter -t 1 -m -u -n -i", // Use a deterministic predefined key for the ADMIN side (DAPPMANAGER's is generated) ADMIN_NACL_SECRET_KEY: "DAppNodeDAppNodeDAppNodeDAppNodeDAppNodeDao=", ADMIN_NACL_PUBLIC_KEY: "cYo1NA7/+PQ22PeqrRNGhs1B84SY/fuomNtURj5SUmQ=", // Fullnode names - ALLOWED_FULLNODE_DNP_NAMES: [ - "geth.dnp.dappnode.eth", - "parity.dnp.dappnode.eth", - ], + ALLOWED_FULLNODE_DNP_NAMES: ["geth.dnp.dappnode.eth", "parity.dnp.dappnode.eth"], // Default fullnode alias FULLNODE_ALIAS: "fullnode.dappnode", @@ -307,81 +286,81 @@ export const params = { name: "DAppNode Association (dnp)", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xf35960302a07022aba880dffaec2fdd64d5bf1c1", + key: "0xf35960302a07022aba880dffaec2fdd64d5bf1c1" }, { name: "DAppNode Association (public)", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xf35960302a07022aba880dffaec2fdd64d5bf1c1", + key: "0xf35960302a07022aba880dffaec2fdd64d5bf1c1" }, { name: "Nethermind Ethereum client team (public)", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xA6264173430bd3FdFF7414c617CBa299d85661E6", + key: "0xA6264173430bd3FdFF7414c617CBa299d85661E6" }, { name: "Nethermind Ethereum client team (dnp)", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xA6264173430bd3FdFF7414c617CBa299d85661E6", + key: "0xA6264173430bd3FdFF7414c617CBa299d85661E6" }, { name: "Lodestar Ethereum consensus client team", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0x9D055dd23de15114EC95921208c741873eDE8558", + key: "0x9D055dd23de15114EC95921208c741873eDE8558" }, { name: "ETC Cooperative", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xfB737B2bb2067C3f9E1448AA2D70D32Db4fb51C4", + key: "0xfB737B2bb2067C3f9E1448AA2D70D32Db4fb51C4" }, { name: "Besu Ethereum client team (public)", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xD88457e1B6e304900190b4a74f3c7D9a89896dBA", + key: "0xD88457e1B6e304900190b4a74f3c7D9a89896dBA" }, { name: "Besu Ethereum client team (dnp)", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xD88457e1B6e304900190b4a74f3c7D9a89896dBA", + key: "0xD88457e1B6e304900190b4a74f3c7D9a89896dBA" }, { name: "Mgarciate", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0x86C4C5D83Ae936d32Ce46E8F256eC382A4F111d6", + key: "0x86C4C5D83Ae936d32Ce46E8F256eC382A4F111d6" }, { name: "Mgarciate", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0x86C4C5D83Ae936d32Ce46E8F256eC382A4F111d6", + key: "0x86C4C5D83Ae936d32Ce46E8F256eC382A4F111d6" }, { name: "HOPR Team", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0x7305356ad936A06c4ea5DF45AD5E5C3ff9Db818E", + key: "0x7305356ad936A06c4ea5DF45AD5E5C3ff9Db818E" }, { name: "Gnosis Team", dnpNameSuffix: ".dnp.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0x2BdB9b9b477268C1e7C04459F79DCc22401BBcd1", + key: "0x2BdB9b9b477268C1e7C04459F79DCc22401BBcd1" }, { name: "Blockswap Labs", dnpNameSuffix: ".public.dappnode.eth", signatureProtocol: "ECDSA_256" as const, - key: "0xF84eeDc34257018Ba77353b9F5b3e11AeAeecC2a", - }, - ], + key: "0xF84eeDc34257018Ba77353b9F5b3e11AeAeecC2a" + } + ] }; if (devMode) { diff --git a/packages/schemas/.eslintignore b/packages/schemas/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/schemas/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/schemas/.eslintrc.cjs b/packages/schemas/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/schemas/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/schemas/package.json b/packages/schemas/package.json index 376a3f8d9..a5a72c58c 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -8,8 +8,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "exports": { ".": { diff --git a/packages/schemas/src/ajv.ts b/packages/schemas/src/ajv.ts index 2c4ba9da4..7db9b5fbb 100644 --- a/packages/schemas/src/ajv.ts +++ b/packages/schemas/src/ajv.ts @@ -10,5 +10,5 @@ export const ajv = new Ajv({ logger: false, allErrors: true, coerceTypes: true, - verbose: true, + verbose: true }); diff --git a/packages/schemas/src/params.ts b/packages/schemas/src/params.ts index 829c055ab..70fc384ee 100644 --- a/packages/schemas/src/params.ts +++ b/packages/schemas/src/params.ts @@ -16,7 +16,7 @@ export const dockerParams = { "wireguard.dnp.dappnode.eth", "core.dnp.dappnode.eth", "dappnode-exporter.dnp.dappnode.eth", - "dms.dnp.dappnode.eth", + "dms.dnp.dappnode.eth" ], DOCKER_CORE_ALIASES: [ "dappmanager.dappnode", @@ -24,8 +24,8 @@ export const dockerParams = { "vpn.dappnode", "wireguard.dappnode", "ipfs.dappnode", - "bind.dappnode", + "bind.dappnode" ], DNS_SERVICE: "172.33.1.2", - MINIMUM_COMPOSE_FILE_VERSION: "3.4", + MINIMUM_COMPOSE_FILE_VERSION: "3.4" }; diff --git a/packages/schemas/src/schemas/manifest.schema.json b/packages/schemas/src/schemas/manifest.schema.json index eee6b3185..44511ff6a 100644 --- a/packages/schemas/src/schemas/manifest.schema.json +++ b/packages/schemas/src/schemas/manifest.schema.json @@ -109,26 +109,14 @@ "oneOf": [ { "type": "string", - "enum": [ - "ethereum", - "ethereum-beacon-chain", - "ethereum2-beacon-chain-prysm", - "bitcoin", - "monero" - ] + "enum": ["ethereum", "ethereum-beacon-chain", "ethereum2-beacon-chain-prysm", "bitcoin", "monero"] }, { "type": "object", "properties": { "driver": { "type": "string", - "enum": [ - "bitcoin", - "ethereum", - "ethereum-beacon-chain", - "ethereum2-beacon-chain-prysm", - "monero" - ], + "enum": ["bitcoin", "ethereum", "ethereum-beacon-chain", "ethereum2-beacon-chain-prysm", "monero"], "description": "The blockchain driver used by this DAppNode Package", "examples": ["ethereum", "bitcoin"] }, @@ -167,11 +155,7 @@ "description": "Specifies the order in which the services should be started.", "items": { "type": "string", - "examples": [ - "vpn.dnp.dappnode.eth", - "core.dnp.dappnode.eth", - "dappmanager.dnp.dappnode.eth" - ] + "examples": ["vpn.dnp.dappnode.eth", "core.dnp.dappnode.eth", "dappmanager.dnp.dappnode.eth"] } }, "restartCommand": { @@ -274,10 +258,7 @@ "description": "The list of envs to inject to the defined services", "items": { "type": "string", - "examples": [ - "_DAPPNODE_GLOBAL_NO_NAT_LOOPBACK", - "_DAPPNODE_GLOBAL_PUBLIC_IP" - ] + "examples": ["_DAPPNODE_GLOBAL_NO_NAT_LOOPBACK", "_DAPPNODE_GLOBAL_PUBLIC_IP"] }, "services": { "type": "array", @@ -322,10 +303,7 @@ "path": { "type": "string", "description": "Path to the file or directory to backup. It **MUST** be an absolute path (do not use the `~` character) for the backup tool to work correctly.", - "examples": [ - "/root/.raiden/secret/keystore", - "/usr/src/app/config.json" - ], + "examples": ["/root/.raiden/secret/keystore", "/usr/src/app/config.json"], "minLength": 1, "errorMessage": "should be an non-empty string" }, @@ -342,9 +320,7 @@ "changelog": { "type": "string", "description": "Description of relevant changes of this specific version. Supports markdown and links.", - "examples": [ - "Brief summary of the most relevant changes that the user must known before installing" - ] + "examples": ["Brief summary of the most relevant changes that the user must known before installing"] }, "warnings": { "type": "object", @@ -374,9 +350,7 @@ "onMajorUpdate": { "type": "string", "description": "Will be shown before performing a major update in the DAppNode Package, not in the first installation.", - "examples": [ - "This is a major update of Prysm, it will start validating using the web3signer." - ] + "examples": ["This is a major update of Prysm, it will start validating using the web3signer."] }, "onReset": { "type": "string", @@ -437,9 +411,7 @@ "message": { "type": "string", "description": "The message shown in the pop-up. Markdown and links are allowed.", - "examples": [ - "This software is experimental, presented “as is” and inherently carries risks." - ] + "examples": ["This software is experimental, presented “as is” and inherently carries risks."] } } }, @@ -507,9 +479,7 @@ "author": { "type": "string", "description": "Main author of this DAppNode Package. Must follow the structure `${name} <${email}> (${githubUserLink})`.", - "examples": [ - "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)" - ], + "examples": ["DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)"], "minLength": 1, "errorMessage": "should be an non-empty string" }, diff --git a/packages/schemas/src/schemas/setup-wizard.schema.json b/packages/schemas/src/schemas/setup-wizard.schema.json index efe2e7190..555258e6c 100644 --- a/packages/schemas/src/schemas/setup-wizard.schema.json +++ b/packages/schemas/src/schemas/setup-wizard.schema.json @@ -161,10 +161,7 @@ "patternErrorMessage": { "type": "string", "title": "Error to show if the regex pattern validation fails", - "examples": [ - "Must be a valid address (0x1fd16a...)", - "Must be at least 8 characters long" - ] + "examples": ["Must be a valid address (0x1fd16a...)", "Must be at least 8 characters long"] }, "enum": { "type": "array", diff --git a/packages/schemas/src/utils.ts b/packages/schemas/src/utils.ts index fbf617391..aee3dad9d 100644 --- a/packages/schemas/src/utils.ts +++ b/packages/schemas/src/utils.ts @@ -56,9 +56,6 @@ export function processError( releaseFileType: "compose" | "manifest" | "setupWizard" ): string { const { schemaPath, message } = errorObject; - const path = `${releaseFileType}${schemaPath}`.replace( - new RegExp("/", "g"), - "." - ); + const path = `${releaseFileType}${schemaPath}`.replace(new RegExp("/", "g"), "."); return `${path} ${message}`; } diff --git a/packages/schemas/src/validateComposeSchema.ts b/packages/schemas/src/validateComposeSchema.ts index ac1d6282a..8cb7f80b5 100644 --- a/packages/schemas/src/validateComposeSchema.ts +++ b/packages/schemas/src/validateComposeSchema.ts @@ -7,27 +7,21 @@ import { exec } from "child_process"; * @param compose */ export async function validateComposeSchema(composePaths: string[]): Promise<void> { - - if (composePaths.length < 1) - throw Error(`No compose files provided`); + if (composePaths.length < 1) throw Error(`No compose files provided`); composePaths.forEach((composePath) => { - if (!fs.existsSync(composePath)) - throw Error(`Compose file ${composePath} not found`); + if (!fs.existsSync(composePath)) throw Error(`Compose file ${composePath} not found`); }); return new Promise((resolve, reject) => { - exec( - `docker compose -f ${composePaths.join(" -f ")} config`, - (error, _stdout, stderr) => { - if (error) { - console.error(`Error: ${error.message}`); - reject(new CliError(`Invalid compose:\n${stderr}`)); - } else { - console.log("Compose file is valid."); - resolve(); - } + exec(`docker compose -f ${composePaths.join(" -f ")} config`, (error, _stdout, stderr) => { + if (error) { + console.error(`Error: ${error.message}`); + reject(new CliError(`Invalid compose:\n${stderr}`)); + } else { + console.log("Compose file is valid."); + resolve(); } - ); + }); }); } diff --git a/packages/schemas/src/validateDappnodeCompose.ts b/packages/schemas/src/validateDappnodeCompose.ts index 25a9b4163..0fe6b5561 100644 --- a/packages/schemas/src/validateDappnodeCompose.ts +++ b/packages/schemas/src/validateDappnodeCompose.ts @@ -1,10 +1,5 @@ import semver from "semver"; -import { - Compose, - ComposeService, - Manifest, - dockerComposeSafeKeys, -} from "@dappnode/types"; +import { Compose, ComposeService, Manifest, dockerComposeSafeKeys } from "@dappnode/types"; import { dockerParams } from "./params.js"; let aggregatedError: string[]; @@ -18,10 +13,7 @@ function err(msg: string): void { * This function must be executed after the official docker schema * @param param0 */ -export function validateDappnodeCompose( - compose: Compose, - manifest: Manifest -): void { +export function validateDappnodeCompose(compose: Compose, manifest: Manifest): void { // clean the errors aggregatedError = []; const isCore = manifest.type === "dncore"; @@ -40,23 +32,14 @@ export function validateDappnodeCompose( } if (aggregatedError.length > 0) - throw Error( - `Error validating compose file with dappnode requirements:\n\n${aggregatedError.join( - "\n" - )}` - ); + throw Error(`Error validating compose file with dappnode requirements:\n\n${aggregatedError.join("\n")}`); } /** * Ensures the docker compose version is supported */ function validateComposeVersion(compose: Compose): void { - if ( - semver.lt( - compose.version + ".0", - dockerParams.MINIMUM_COMPOSE_FILE_VERSION + ".0" - ) - ) + if (semver.lt(compose.version + ".0", dockerParams.MINIMUM_COMPOSE_FILE_VERSION + ".0")) err( `Compose version ${compose.version} is not supported. Minimum version is ${dockerParams.MINIMUM_COMPOSE_FILE_VERSION}` ); @@ -80,9 +63,7 @@ function validateComposeNetworks(compose: Compose): void { // Check all networks are external const network = networks[networkName]; if (network && network.external === false) - err( - `The docker network ${networkName} is not allowed. Docker internal networks are not allowed` - ); + err(`The docker network ${networkName} is not allowed. Docker internal networks are not allowed`); } } } @@ -90,12 +71,7 @@ function validateComposeNetworks(compose: Compose): void { /** * Ensures the compose keys values are valid for dappnode */ -function validateComposeService( - compose: Compose, - isCore: boolean, - serviceName: string, - dnpName: string -): void { +function validateComposeService(compose: Compose, isCore: boolean, serviceName: string, dnpName: string): void { for (const serviceKey of Object.keys(compose.services[serviceName])) { if (!dockerComposeSafeKeys.includes(serviceKey as keyof ComposeService)) err( @@ -105,48 +81,30 @@ function validateComposeService( ); } - const { dns, pid, privileged, network_mode, volumes } = - compose.services[serviceName]; + const { dns, pid, privileged, network_mode, volumes } = compose.services[serviceName]; // Check that if defined, the DNS must be the one provided from the bind package if (!isCore && dns && !dockerParams.DNS_SERVICE.includes(dns)) - err( - `service ${serviceName} has DNS different than ${dockerParams.DNS_SERVICE}` - ); + err(`service ${serviceName} has DNS different than ${dockerParams.DNS_SERVICE}`); // Check compose pid feature can only be used with the format service:*. The pid:host is dangerous - if (pid && !pid.startsWith("service:")) - err(`service ${serviceName} has PID feature differnet than service:*`); + if (pid && !pid.startsWith("service:")) err(`service ${serviceName} has PID feature differnet than service:*`); // Check only core packages or exporter cand be privileged - if ( - dnpName !== "dappnode-exporter.dnp.dappnode.eth" && - !isCore && - privileged && - privileged === true - ) - err( - `service ${serviceName} has privileged as true but is not a core package` - ); + if (dnpName !== "dappnode-exporter.dnp.dappnode.eth" && !isCore && privileged && privileged === true) + err(`service ${serviceName} has privileged as true but is not a core package`); // Check Only core packages can use network_mode: host if (!isCore && network_mode && network_mode === "host") - err( - `service ${serviceName} has network_mode: host but is not a core package` - ); + err(`service ${serviceName} has network_mode: host but is not a core package`); validateComposeServiceNetworks(compose, isCore, serviceName); - if ( - volumes && - !dockerParams.DOCKER_WHITELIST_BIND_VOLUMES.includes(dnpName) - ) { + if (volumes && !dockerParams.DOCKER_WHITELIST_BIND_VOLUMES.includes(dnpName)) { for (const [i, volume] of volumes.entries()) { if (typeof volume !== "string") { // https://docs.docker.com/compose/compose-file/compose-file-v3/#short-syntax-3 - err( - `service ${serviceName}.volumes[${i}] must use volume short-syntax` - ); + err(`service ${serviceName}.volumes[${i}] must use volume short-syntax`); } validateComposeServiceVolumes(compose, serviceName, volume); @@ -157,15 +115,9 @@ function validateComposeService( /** * Ensure the services networks are whitelisted */ -function validateComposeServiceNetworks( - compose: Compose, - isCore: boolean, - serviceName: string -): void { - const DOCKER_WHITELIST_NETWORKS_STR = - dockerParams.DOCKER_WHITELIST_NETWORKS.join(","); - const DOCKER_WHITELIST_ALIASES_STR = - dockerParams.DOCKER_CORE_ALIASES.join(","); +function validateComposeServiceNetworks(compose: Compose, isCore: boolean, serviceName: string): void { + const DOCKER_WHITELIST_NETWORKS_STR = dockerParams.DOCKER_WHITELIST_NETWORKS.join(","); + const DOCKER_WHITELIST_ALIASES_STR = dockerParams.DOCKER_CORE_ALIASES.join(","); const service = compose.services[serviceName]; const serviceNetworks = service.networks; if (!serviceNetworks) return; @@ -181,24 +133,14 @@ function validateComposeServiceNetworks( } else { for (const serviceNetworkObjectName of Object.keys(serviceNetworks)) { // Check docker network is whitelisted when defined in object format - if ( - !dockerParams.DOCKER_WHITELIST_NETWORKS.includes( - serviceNetworkObjectName - ) - ) + if (!dockerParams.DOCKER_WHITELIST_NETWORKS.includes(serviceNetworkObjectName)) err( `service ${serviceName} has a non-whitelisted docker network: ${serviceNetworkObjectName}. Only docker networks ${DOCKER_WHITELIST_NETWORKS_STR} are allowed` ); // Check core aliases are not used by non core packages const { aliases } = serviceNetworks[serviceNetworkObjectName]; - if ( - !isCore && - aliases && - dockerParams.DOCKER_CORE_ALIASES.some((coreAlias) => - aliases.includes(coreAlias) - ) - ) { + if (!isCore && aliases && dockerParams.DOCKER_CORE_ALIASES.some((coreAlias) => aliases.includes(coreAlias))) { err( `service ${serviceName} has the network ${serviceNetworkObjectName} with reserved docker alias. Aliases ${DOCKER_WHITELIST_ALIASES_STR} are reserved to core packages` ); @@ -210,11 +152,7 @@ function validateComposeServiceNetworks( /** * Ensure only core packages can use bind-mounted volumes */ -function validateComposeServiceVolumes( - compose: Compose, - serviceName: string, - volume: string -): void { +function validateComposeServiceVolumes(compose: Compose, serviceName: string, volume: string): void { // From https://docs.docker.com/compose/compose-file/compose-file-v3/#short-syntax-3 // docker supports multiple short-syntax. DAppNode only supports exclicit declaration of name // @@ -242,18 +180,14 @@ bind mounts are forbidden unless explicitly whitelisted. Reach out to DAppNode t // Extra check REDUNDANT but for better UX in case developers use bind-mounts if (volumeName.includes("/")) { - return err( - `service ${serviceName} volume ${volume} is a bind-mount, only named non-external volumes are allowed` - ); + return err(`service ${serviceName} volume ${volume} is a bind-mount, only named non-external volumes are allowed`); } // Check volume name contains only valid charaters. // Note: this validation is also done by Docker. // Note: this also protects against weird paths. if (!/^[a-zA-Z0-9_.-]+$/.test(volumeName)) { - return err( - `service ${serviceName} volume ${volume} must only include characters [a-zA-Z0-9_.-]` - ); + return err(`service ${serviceName} volume ${volume} must only include characters [a-zA-Z0-9_.-]`); } // Check that service volumes are defined also at top compose level @@ -265,14 +199,10 @@ bind mounts are forbidden unless explicitly whitelisted. Reach out to DAppNode t // Extra check REDUNDANT but for better UX if (volumeDefinition?.external) { - err( - `service ${serviceName} volume ${volumeName} is external. Only named non-external volumes are allowed` - ); + err(`service ${serviceName} volume ${volumeName} is external. Only named non-external volumes are allowed`); } if (Object.keys(volumeDefinition).length > 0) { - err( - `service ${serviceName} volume ${volumeName} definition must not set any property` - ); + err(`service ${serviceName} volume ${volumeName} definition must not set any property`); } } diff --git a/packages/schemas/src/validateManifestSchema.ts b/packages/schemas/src/validateManifestSchema.ts index 88d33f211..0e18a052b 100644 --- a/packages/schemas/src/validateManifestSchema.ts +++ b/packages/schemas/src/validateManifestSchema.ts @@ -12,11 +12,7 @@ export function validateManifestSchema(manifest: Manifest): void { const validateManifest = ajv.compile(manifestSchema); const valid = validateManifest(manifest); if (!valid) { - const errors = validateManifest.errors - ? validateManifest.errors.map((e) => processError(e, "manifest")) - : []; - throw new CliError( - `Invalid manifest: \n${errors.map((msg) => ` - ${msg}`).join("\n")}` - ); + const errors = validateManifest.errors ? validateManifest.errors.map((e) => processError(e, "manifest")) : []; + throw new CliError(`Invalid manifest: \n${errors.map((msg) => ` - ${msg}`).join("\n")}`); } } diff --git a/packages/schemas/src/validateSetupWizardSchema.ts b/packages/schemas/src/validateSetupWizardSchema.ts index 6ee0048a2..9e59a215e 100644 --- a/packages/schemas/src/validateSetupWizardSchema.ts +++ b/packages/schemas/src/validateSetupWizardSchema.ts @@ -15,8 +15,6 @@ export function validateSetupWizardSchema(setupWizard: SetupWizard): void { const errors = validateSetupWizard.errors ? validateSetupWizard.errors.map((e) => processError(e, "setupWizard")) : []; - throw new CliError( - `Invalid setupWizard: \n${errors.map((msg) => ` - ${msg}`).join("\n")}` - ); + throw new CliError(`Invalid setupWizard: \n${errors.map((msg) => ` - ${msg}`).join("\n")}`); } } diff --git a/packages/schemas/test/unit/validateDappnodeCompose.test.ts b/packages/schemas/test/unit/validateDappnodeCompose.test.ts index daa4df503..6d1a19df0 100644 --- a/packages/schemas/test/unit/validateDappnodeCompose.test.ts +++ b/packages/schemas/test/unit/validateDappnodeCompose.test.ts @@ -17,42 +17,41 @@ describe("files / compose / validateDappnodeCompose", () => { chain: { driver: "ethereum-beacon-chain", serviceName: "beacon-chain", - portNumber: 3500, + portNumber: 3500 }, mainService: "validator", - author: - "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", + author: "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", contributors: [ "dappLion <dapplion@dappnode.io> (https://github.com/dapplion)", "tropicar <tropicar@dappnode.io> (https://github.com/tropicar)", - "pablo <pablo@dappnode.io> (https://github.com/pablomendezroyo)", + "pablo <pablo@dappnode.io> (https://github.com/pablomendezroyo)" ], license: "GPL-3.0", repository: { type: "git", - url: "git+https://github.com/dappnode/DAppNodePackage-prysm-prater.git", + url: "git+https://github.com/dappnode/DAppNodePackage-prysm-prater.git" }, bugs: { - url: "https://github.com/dappnode/DAppNodePackage-prysm-prater/issues", + url: "https://github.com/dappnode/DAppNodePackage-prysm-prater/issues" }, requirements: { - minimumDappnodeVersion: "0.2.51", + minimumDappnodeVersion: "0.2.51" }, categories: ["Blockchain", "ETH2.0"], warnings: { onMajorUpdate: - "This is a major update of Prysm Prater, it will start validating with the web3signer. There will be a migration where your keystores will be replaced to another location, pay attention to the update", + "This is a major update of Prysm Prater, it will start validating with the web3signer. There will be a migration where your keystores will be replaced to another location, pay attention to the update" }, links: { ui: "http://ui.web3signer-prater.dappnode?signer_url=http://web3signer.web3signer-prater.dappnode:9000", homepage: "https://prysmaticlabs.com/", readme: "https://github.com/dappnode/DAppNodePackage-prysm-prater", - docs: "https://docs.prylabs.network/docs/getting-started", + docs: "https://docs.prylabs.network/docs/getting-started" }, dependencies: { "goerli-geth.dnp.dappnode.eth": "latest", - "web3signer-prater.dnp.dappnode.eth": "latest", - }, + "web3signer-prater.dnp.dappnode.eth": "latest" + } }; const compose: Compose = { @@ -63,8 +62,8 @@ describe("files / compose / validateDappnodeCompose", () => { build: { context: "beacon-chain", args: { - UPSTREAM_VERSION: "v2.1.2", - }, + UPSTREAM_VERSION: "v2.1.2" + } }, volumes: ["beacon-chain-data:/data"], ports: ["13000", "12000/udp"], @@ -74,8 +73,8 @@ describe("files / compose / validateDappnodeCompose", () => { CHECKPOINT_SYNC_URL: "", CORSDOMAIN: "http://prysm-prater.dappnode", WEB3_BACKUP: "", - EXTRA_OPTS: "", - }, + EXTRA_OPTS: "" + } }, validator: { image: "validator.prysm-prater.dnp.dappnode.eth:1.0.0", @@ -84,25 +83,24 @@ describe("files / compose / validateDappnodeCompose", () => { dockerfile: "Dockerfile", args: { UPSTREAM_VERSION: "v2.1.2", - BRANCH: "develop", - }, + BRANCH: "develop" + } }, volumes: ["validator-data:/root/"], restart: "unless-stopped", environment: { LOG_TYPE: "INFO", BEACON_RPC_PROVIDER: "beacon-chain.prysm-prater.dappnode:4000", - BEACON_RPC_GATEWAY_PROVIDER: - "beacon-chain.prysm-prater.dappnode:3500", + BEACON_RPC_GATEWAY_PROVIDER: "beacon-chain.prysm-prater.dappnode:3500", GRAFFITI: "validating_from_DAppNode", - EXTRA_OPTS: "", - }, - }, + EXTRA_OPTS: "" + } + } }, volumes: { "beacon-chain-data": {}, - "validator-data": {}, - }, + "validator-data": {} + } }; it("Should validate the compose file", () => { @@ -117,9 +115,9 @@ describe("files / compose / validateDappnodeCompose", () => { networks: { danger_network: { name: "danger_network", - external: true, - }, - }, + external: true + } + } }, manifest ) @@ -137,9 +135,9 @@ The docker network danger_network is not allowed. Only docker networks dncore_ne ...compose.services, validator: { ...compose.services.validator, - volumes: ["/var/run/docker.sock:/var/run/docker.sock"], - }, - }, + volumes: ["/var/run/docker.sock:/var/run/docker.sock"] + } + } }, manifest ) @@ -157,9 +155,9 @@ service validator volume /var/run/docker.sock:/var/run/docker.sock is a bind-mou ...compose.services, validator: { ...compose.services.validator, - credential_spec: "random", - }, - }, + credential_spec: "random" + } + } } as Compose, manifest ) @@ -173,7 +171,7 @@ service validator has key credential_spec that is not allowed. Allowed keys are: validateDappnodeCompose( { ...compose, - version: "3.3", + version: "3.3" }, manifest ) @@ -191,9 +189,9 @@ Compose version 3.3 is not supported. Minimum version is 3.4`); ...compose.services, validator: { ...compose.services.validator, - networks: ["danger_network"], - }, - }, + networks: ["danger_network"] + } + } }, manifest ) @@ -214,15 +212,15 @@ service validator has a non-whitelisted docker network: danger_network. Only doc networks: { danger_network: { ipv4_address: "172.33.4.5", - aliases: ["dappmanager.dappnode"], + aliases: ["dappmanager.dappnode"] }, other_network: { ipv4_address: "", - aliases: ["core.dappnode"], - }, - }, - }, - }, + aliases: ["core.dappnode"] + } + } + } + } }, manifest ) @@ -243,9 +241,9 @@ service validator has a non-whitelisted docker network: other_network. Only dock ...compose.services, validator: { ...compose.services.validator, - volumes: ["/var/run/docker.sock:/var/run/docker.sock"], - }, - }, + volumes: ["/var/run/docker.sock:/var/run/docker.sock"] + } + } }, manifest ) diff --git a/packages/schemas/test/unit/validateSchema.test.ts b/packages/schemas/test/unit/validateSchema.test.ts index 5d231d56c..b631fd2df 100644 --- a/packages/schemas/test/unit/validateSchema.test.ts +++ b/packages/schemas/test/unit/validateSchema.test.ts @@ -1,9 +1,5 @@ import { expect } from "chai"; -import { - validateComposeSchema, - validateManifestSchema, - validateSetupWizardSchema, -} from "../../src/index.js"; +import { validateComposeSchema, validateManifestSchema, validateSetupWizardSchema } from "../../src/index.js"; import fs from "fs"; import path from "path"; import { cleanTestDir, testDir } from "../testUtils.js"; @@ -25,19 +21,16 @@ describe("schemaValidation", () => { globalEnvs: [ { services: ["web3signer", "ui"], - envs: [ - "_DAPPNODE_GLOBAL_INTERNAL_IP", - "_DAPPNODE_GLOBAL_PUBLIC_IP", - ], + envs: ["_DAPPNODE_GLOBAL_INTERNAL_IP", "_DAPPNODE_GLOBAL_PUBLIC_IP"] }, { services: ["db"], - envs: ["_DAPPNODE_GLOBAL_PUBKEY"], - }, + envs: ["_DAPPNODE_GLOBAL_PUBKEY"] + } ], chain: { - driver: "ethereum", - }, + driver: "ethereum" + } }; expect(() => validateManifestSchema(manifest)).to.not.throw(); @@ -51,8 +44,8 @@ describe("schemaValidation", () => { type: "dncore", license: "1", chain: { - driver: "ethereum", - }, + driver: "ethereum" + } }; expect(() => validateManifestSchema(manifest)).to.not.throw(); @@ -65,7 +58,7 @@ describe("schemaValidation", () => { description: "", type: "dncore", license: "1", - chain: "ethereum", + chain: "ethereum" }; expect(() => validateManifestSchema(manifest)).to.not.throw(); @@ -79,7 +72,7 @@ describe("schemaValidation", () => { description: "", type: "dncore", license: "1", - chain: "notAllowed", + chain: "notAllowed" }; expect(() => validateManifestSchema(manifest as Manifest)).to.throw(); @@ -125,9 +118,7 @@ volumes: validator-data: {}`; const validComposePath = path.join(testDir, "valid-docker-compose.yml"); fs.writeFileSync(validComposePath, validCompose); - expect( - async () => await validateComposeSchema([validComposePath]) - ).to.not.throw(); + expect(async () => await validateComposeSchema([validComposePath])).to.not.throw(); }); it("should throw error with an invalid compose", async () => { @@ -173,15 +164,10 @@ volumes: web3signer_data: {} postgres_data: {} postgres_migrations: {}`; - const invalidComposePath = path.join( - testDir, - "invalid-docker-compose.yml" - ); + const invalidComposePath = path.join(testDir, "invalid-docker-compose.yml"); fs.writeFileSync(invalidComposePath, invalidCompose); - const error = await validateComposeSchema([invalidComposePath]).catch( - (e) => e - ); + const error = await validateComposeSchema([invalidComposePath]).catch((e) => e); console.log(error); const expectedErrorMessage = `Invalid compose`; expect(error.message).to.include(expectedErrorMessage); @@ -235,9 +221,7 @@ volumes: fs.writeFileSync(validComposePath1, validCompose1); fs.writeFileSync(validComposePath2, validCompose2); - expect( - async () => await validateComposeSchema([validComposePath1, validComposePath2]) - ).to.not.throw(); + expect(async () => await validateComposeSchema([validComposePath1, validComposePath2])).to.not.throw(); }); }); @@ -255,48 +239,47 @@ volumes: target: { type: "environment", name: "GRAFFITI", - service: "validator", + service: "validator" }, title: "Graffiti", maxLength: 32, - description: - "Add a string to your proposed blocks, which will be seen on the block explorer", + description: "Add a string to your proposed blocks, which will be seen on the block explorer" }, { id: "HTTP_WEB3PROVIDER", target: { type: "environment", name: "HTTP_WEB3PROVIDER", - service: ["validator", "beacon-chain"], + service: ["validator", "beacon-chain"] }, title: "Eth1.x node URL", - description: "URL to the Eth1.x node need for the Beacon chain.", + description: "URL to the Eth1.x node need for the Beacon chain." }, { id: "web3Backup", target: { type: "environment", name: "WEB3_BACKUP", - service: "beacon-chain", + service: "beacon-chain" }, title: "Add a backup web3 provider", description: "It's a good idea to add a backup web3 provider in case your main one goes down. For example, if your primary EL client is a local Geth, but you want to use Infura as a backup. Get your web3 backup from [infura](https://infura.io/) (i.e https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@eth2-beacon-prater.infura.io)", - required: false, + required: false }, { id: "checkpointSyncUrl", target: { type: "environment", name: "CHECKPOINT_SYNC_URL", - service: "beacon-chain", + service: "beacon-chain" }, title: "Checkpoint for fast sync", description: "To get Prysm up and running in only a few minutes, you can start Prysm from a recent finalized checkpoint state rather than syncing from genesis. This is substantially **faster** and consumes **less resources** than syncing from genesis, while still providing all the same features. Be sure you are using a trusted node for the fast sync. Check [Prysm docs](https://docs.prylabs.network/docs/prysm-usage/parameters/) Get your checkpoint sync from [infura](https://infura.io/) (i.e https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@eth2-beacon-prater.infura.io)", - required: false, - }, - ], + required: false + } + ] } as SetupWizard; expect(() => validateSetupWizardSchema(validSetupWizard)).to.not.throw(); @@ -311,56 +294,53 @@ volumes: target: { type: "environment", name: "GRAFFITI", - service: "validator", + service: "validator" }, title: "Graffiti", maxLength: 32, - description: - "Add a string to your proposed blocks, which will be seen on the block explorer", + description: "Add a string to your proposed blocks, which will be seen on the block explorer" }, { id: "HTTP_WEB3PROVIDER", target: { type: "environment", name: "HTTP_WEB3PROVIDER", - service: "beacon-chain", + service: "beacon-chain" }, title: "Eth1.x node URL", - description: "URL to the Eth1.x node need for the Beacon chain.", + description: "URL to the Eth1.x node need for the Beacon chain." }, { id: "web3Backup", target: { type: "environment", name: "WEB3_BACKUP", - service: "beacon-chain", + service: "beacon-chain" }, title: "Add a backup web3 provider", description: "It's a good idea to add a backup web3 provider in case your main one goes down. For example, if your primary EL client is a local Geth, but you want to use Infura as a backup. Get your web3 backup from [infura](https://infura.io/) (i.e https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@eth2-beacon-prater.infura.io)", - required: false, + required: false }, { id: "checkpointSyncUrl", target: { type: "environment", name: "CHECKPOINT_SYNC_URL", - service: "beacon-chain", + service: "beacon-chain" }, title: "Checkpoint for fast sync", description: "To get Prysm up and running in only a few minutes, you can start Prysm from a recent finalized checkpoint state rather than syncing from genesis. This is substantially **faster** and consumes **less resources** than syncing from genesis, while still providing all the same features. Be sure you are using a trusted node for the fast sync. Check [Prysm docs](https://docs.prylabs.network/docs/prysm-usage/parameters/) Get your checkpoint sync from [infura](https://infura.io/) (i.e https://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@eth2-beacon-prater.infura.io)", - required: false, + required: false }, { - notAllowed: "random", - }, - ], + notAllowed: "random" + } + ] } as SetupWizard; - expect(() => - validateSetupWizardSchema(invalidSetupWizardString) - ).to.throw(); + expect(() => validateSetupWizardSchema(invalidSetupWizardString)).to.throw(); }); it("should throw error with an empty service array in setupWizard", () => { @@ -372,14 +352,13 @@ volumes: target: { type: "environment", name: "GRAFFITI", - service: [], + service: [] }, title: "Graffiti", maxLength: 32, - description: - "Add a string to your proposed blocks, which will be seen on the block explorer", - }, - ], + description: "Add a string to your proposed blocks, which will be seen on the block explorer" + } + ] } as unknown as SetupWizard; expect(() => validateSetupWizardSchema(invalidSetupWizard)).to.throw(); @@ -420,7 +399,8 @@ volumes: }); it("should not allow a manifest with upstream settings defined in both possible ways", () => { - const manifest: Manifest = { // Using 'any' to bypass TypeScript checks for invalid schema + const manifest: Manifest = { + // Using 'any' to bypass TypeScript checks for invalid schema name: "example.dnp.dappnode.eth", version: "1.0.0", description: "A sample DAppNode package", @@ -452,6 +432,5 @@ volumes: expect(() => validateManifestSchema(manifest)).to.not.throw(); }); - }); }); diff --git a/packages/stakers/.eslintignore b/packages/stakers/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/stakers/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/stakers/.eslintrc.cjs b/packages/stakers/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/stakers/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/stakers/package.json b/packages/stakers/package.json index ea804ffce..93249df03 100644 --- a/packages/stakers/package.json +++ b/packages/stakers/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/db": "workspace:^0.1.0", diff --git a/packages/stakers/src/consensus.ts b/packages/stakers/src/consensus.ts index 52cc77f13..79c948d59 100644 --- a/packages/stakers/src/consensus.ts +++ b/packages/stakers/src/consensus.ts @@ -6,7 +6,7 @@ import { ConsensusClientPrater, Network, StakerItem, - UserSettings, + UserSettings } from "@dappnode/types"; import { StakerComponent } from "./stakerComponent.js"; import { DappnodeInstaller } from "@dappnode/installer"; @@ -28,50 +28,47 @@ export class Consensus extends StakerComponent { [Network.Gnosis]: db.consensusClientGnosis, [Network.Prater]: db.consensusClientPrater, [Network.Holesky]: db.consensusClientHolesky, - [Network.Lukso]: db.consensusClientLukso, + [Network.Lukso]: db.consensusClientLukso }; protected static readonly DefaultCheckpointSync: Record<Network, string> = { [Network.Mainnet]: "https://checkpoint-sync.dappnode.io", [Network.Prater]: "https://checkpoint-sync-prater.dappnode.io", [Network.Gnosis]: "https://checkpoint-sync-gnosis.dappnode.io", [Network.Holesky]: "https://checkpoint-sync-holesky.dappnode.io", - [Network.Lukso]: "https://checkpoints.mainnet.lukso.network", + [Network.Lukso]: "https://checkpoints.mainnet.lukso.network" }; - protected static readonly CompatibleConsensus: Record< - Network, - { dnpName: string; minVersion: string }[] - > = { + protected static readonly CompatibleConsensus: Record<Network, { dnpName: string; minVersion: string }[]> = { [Network.Mainnet]: [ { dnpName: ConsensusClientMainnet.Prysm, minVersion: "3.0.4" }, { dnpName: ConsensusClientMainnet.Lighthouse, minVersion: "1.0.3" }, { dnpName: ConsensusClientMainnet.Teku, minVersion: "2.0.4" }, { dnpName: ConsensusClientMainnet.Nimbus, minVersion: "1.0.5" }, - { dnpName: ConsensusClientMainnet.Lodestar, minVersion: "0.1.0" }, + { dnpName: ConsensusClientMainnet.Lodestar, minVersion: "0.1.0" } ], [Network.Gnosis]: [ { dnpName: ConsensusClientGnosis.Lighthouse, minVersion: "0.1.5" }, { dnpName: ConsensusClientGnosis.Teku, minVersion: "0.1.5" }, { dnpName: ConsensusClientGnosis.Lodestar, minVersion: "0.1.0" }, - { dnpName: ConsensusClientGnosis.Nimbus, minVersion: "0.1.0" }, + { dnpName: ConsensusClientGnosis.Nimbus, minVersion: "0.1.0" } ], [Network.Prater]: [ { dnpName: ConsensusClientPrater.Prysm, minVersion: "1.0.15" }, { dnpName: ConsensusClientPrater.Lighthouse, minVersion: "0.1.9" }, { dnpName: ConsensusClientPrater.Teku, minVersion: "0.1.10" }, { dnpName: ConsensusClientPrater.Nimbus, minVersion: "0.1.7" }, - { dnpName: ConsensusClientPrater.Lodestar, minVersion: "0.1.0" }, + { dnpName: ConsensusClientPrater.Lodestar, minVersion: "0.1.0" } ], [Network.Holesky]: [ { dnpName: ConsensusClientHolesky.Lighthouse, minVersion: "0.1.2" }, { dnpName: ConsensusClientHolesky.Prysm, minVersion: "0.1.3" }, { dnpName: ConsensusClientHolesky.Teku, minVersion: "0.1.2" }, { dnpName: ConsensusClientHolesky.Nimbus, minVersion: "0.1.2" }, - { dnpName: ConsensusClientHolesky.Lodestar, minVersion: "0.1.3" }, + { dnpName: ConsensusClientHolesky.Lodestar, minVersion: "0.1.3" } ], [Network.Lukso]: [ { dnpName: ConsensusClientLukso.Prysm, minVersion: "0.1.0" }, - { dnpName: ConsensusClientLukso.Teku, minVersion: "0.1.0" }, - ], + { dnpName: ConsensusClientLukso.Teku, minVersion: "0.1.0" } + ] }; constructor(dappnodeInstaller: DappnodeInstaller) { @@ -80,19 +77,15 @@ export class Consensus extends StakerComponent { async getAllConsensus(network: Network): Promise<StakerItem[]> { return await super.getAll({ - dnpNames: Consensus.CompatibleConsensus[network].map( - (client) => client.dnpName - ), - currentClient: this.DbHandlers[network].get(), + dnpNames: Consensus.CompatibleConsensus[network].map((client) => client.dnpName), + currentClient: this.DbHandlers[network].get() }); } async persistSelectedConsensusIfInstalled(network: Network): Promise<void> { const currentConsensusDnpName = this.DbHandlers[network].get(); if (currentConsensusDnpName) { - const isInstalled = Boolean( - await listPackageNoThrow({ dnpName: currentConsensusDnpName }) - ); + const isInstalled = Boolean(await listPackageNoThrow({ dnpName: currentConsensusDnpName })); if (!isInstalled) { // update status in db @@ -101,11 +94,7 @@ export class Consensus extends StakerComponent { } await this.persistSelectedIfInstalled({ dnpName: currentConsensusDnpName, - userSettings: this.getUserSettings( - currentConsensusDnpName, - isInstalled, - network - ), + userSettings: this.getUserSettings(currentConsensusDnpName, isInstalled, network) }); await this.DbHandlers[network].set(currentConsensusDnpName); } @@ -125,20 +114,14 @@ export class Consensus extends StakerComponent { network ) : {}, - prevClient: prevConsClientDnpName, + prevClient: prevConsClientDnpName }); // persist on db - if (newConsensusDnpName !== prevConsClientDnpName) - await this.DbHandlers[network].set(newConsensusDnpName); + if (newConsensusDnpName !== prevConsClientDnpName) await this.DbHandlers[network].set(newConsensusDnpName); } - private getUserSettings( - newConsensusDnpName: string, - shouldSetEnvironment: boolean, - network: Network - ): UserSettings { - const validatorServiceName = - this.getValidatorServiceName(newConsensusDnpName); + private getUserSettings(newConsensusDnpName: string, shouldSetEnvironment: boolean, network: Network): UserSettings { + const validatorServiceName = this.getValidatorServiceName(newConsensusDnpName); const beaconServiceName = this.getBeaconServiceName(newConsensusDnpName); const defaultDappnodeGraffiti = "validating_from_DAppNode"; const defaultFeeRecipient = "0x0000000000000000000000000000000000000000"; @@ -152,73 +135,65 @@ export class Consensus extends StakerComponent { // Graffiti is a mandatory value ["GRAFFITI"]: defaultDappnodeGraffiti, // Checkpoint sync is an optional value - ["CHECKPOINT_SYNC_URL"]: - Consensus.DefaultCheckpointSync[network], - }, + ["CHECKPOINT_SYNC_URL"]: Consensus.DefaultCheckpointSync[network] + } } : { [validatorServiceName]: { // Fee recipient is set as global env, keep this for backwards compatibility ["FEE_RECIPIENT_ADDRESS"]: defaultFeeRecipient, // Graffiti is a mandatory value - ["GRAFFITI"]: defaultDappnodeGraffiti, + ["GRAFFITI"]: defaultDappnodeGraffiti }, [beaconServiceName]: { // Fee recipient is set as global env, keep this for backwards compatibility ["FEE_RECIPIENT_ADDRESS"]: defaultFeeRecipient, // Checkpoint sync is an optional value - ["CHECKPOINT_SYNC_URL"]: - Consensus.DefaultCheckpointSync[network], - }, + ["CHECKPOINT_SYNC_URL"]: Consensus.DefaultCheckpointSync[network] + } } : {}, networks: { rootNetworks: { [params.DOCKER_STAKER_NETWORKS[network]]: { - external: true, + external: true }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - external: true, - }, + external: true + } }, serviceNetworks: beaconServiceName === validatorServiceName ? { "beacon-validator": { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [ - `beacon-chain.${network}.staker.dappnode`, - `validator.${network}.staker.dappnode`, - ], + aliases: [`beacon-chain.${network}.staker.dappnode`, `validator.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [ - `beacon-chain.${network}.dncore.dappnode`, - `validator.${network}.dncore.dappnode`, - ], - }, - }, + aliases: [`beacon-chain.${network}.dncore.dappnode`, `validator.${network}.dncore.dappnode`] + } + } } : { "beacon-chain": { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [`beacon-chain.${network}.staker.dappnode`], + aliases: [`beacon-chain.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [`beacon-chain.${network}.dncore.dappnode`], - }, + aliases: [`beacon-chain.${network}.dncore.dappnode`] + } }, validator: { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [`validator.${network}.staker.dappnode`], + aliases: [`validator.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [`validator.${network}.dncore.dappnode`], - }, - }, - }, - }, + aliases: [`validator.${network}.dncore.dappnode`] + } + } + } + } }; } @@ -228,11 +203,7 @@ export class Consensus extends StakerComponent { * - Prysm, Teku, Lighthouse, and Lodestar are multiservice (beacon, validator) */ private getValidatorServiceName(newConsensusDnpName: string | null): string { - return newConsensusDnpName - ? newConsensusDnpName.includes("nimbus") - ? "beacon-validator" - : "validator" - : ""; + return newConsensusDnpName ? (newConsensusDnpName.includes("nimbus") ? "beacon-validator" : "validator") : ""; } /** @@ -241,10 +212,6 @@ export class Consensus extends StakerComponent { * - Prysm, Teku, Lighthouse, and Lodestar are multiservice (beacon, validator) */ private getBeaconServiceName(newConsensusDnpName: string | null): string { - return newConsensusDnpName - ? newConsensusDnpName.includes("nimbus") - ? "beacon-validator" - : "beacon-chain" - : ""; + return newConsensusDnpName ? (newConsensusDnpName.includes("nimbus") ? "beacon-validator" : "beacon-chain") : ""; } } diff --git a/packages/stakers/src/execution.ts b/packages/stakers/src/execution.ts index e9f9ab45a..0bc8a3d2d 100644 --- a/packages/stakers/src/execution.ts +++ b/packages/stakers/src/execution.ts @@ -6,7 +6,7 @@ import { ExecutionClientPrater, Network, StakerItem, - UserSettings, + UserSettings } from "@dappnode/types"; import { StakerComponent } from "./stakerComponent.js"; import { DappnodeInstaller, ethereumClient } from "@dappnode/installer"; @@ -28,39 +28,34 @@ export class Execution extends StakerComponent { [Network.Gnosis]: db.executionClientGnosis, [Network.Prater]: db.executionClientPrater, [Network.Holesky]: db.executionClientHolesky, - [Network.Lukso]: db.executionClientLukso, + [Network.Lukso]: db.executionClientLukso }; - protected static readonly CompatibleExecutions: Record< - Network, - { dnpName: string; minVersion: string }[] - > = { + protected static readonly CompatibleExecutions: Record<Network, { dnpName: string; minVersion: string }[]> = { [Network.Mainnet]: [ { dnpName: ExecutionClientMainnet.Geth, minVersion: "0.1.37" }, { dnpName: ExecutionClientMainnet.Nethermind, minVersion: "1.0.27" }, { dnpName: ExecutionClientMainnet.Erigon, minVersion: "0.1.34" }, - { dnpName: ExecutionClientMainnet.Besu, minVersion: "1.2.6" }, + { dnpName: ExecutionClientMainnet.Besu, minVersion: "1.2.6" } ], [Network.Gnosis]: [ { dnpName: ExecutionClientGnosis.Nethermind, minVersion: "1.0.18" }, - { dnpName: ExecutionClientGnosis.Erigon, minVersion: "0.1.0" }, + { dnpName: ExecutionClientGnosis.Erigon, minVersion: "0.1.0" } ], [Network.Prater]: [ { dnpName: ExecutionClientPrater.Geth, minVersion: "0.4.26" }, { dnpName: ExecutionClientPrater.Erigon, minVersion: "0.1.0" }, { dnpName: ExecutionClientPrater.Nethermind, minVersion: "1.0.1" }, - { dnpName: ExecutionClientPrater.Besu, minVersion: "0.1.0" }, + { dnpName: ExecutionClientPrater.Besu, minVersion: "0.1.0" } ], [Network.Holesky]: [ { dnpName: ExecutionClientHolesky.Reth, minVersion: "0.1.0" }, { dnpName: ExecutionClientHolesky.Geth, minVersion: "0.1.0" }, { dnpName: ExecutionClientHolesky.Erigon, minVersion: "0.1.0" }, { dnpName: ExecutionClientHolesky.Nethermind, minVersion: "0.1.0" }, - { dnpName: ExecutionClientHolesky.Besu, minVersion: "0.1.0" }, - ], - [Network.Lukso]: [ - { dnpName: ExecutionClientLukso.Geth, minVersion: "0.1.0" }, + { dnpName: ExecutionClientHolesky.Besu, minVersion: "0.1.0" } ], + [Network.Lukso]: [{ dnpName: ExecutionClientLukso.Geth, minVersion: "0.1.0" }] }; constructor(dappnodeInstaller: DappnodeInstaller) { @@ -69,10 +64,8 @@ export class Execution extends StakerComponent { async getAllExecutions(network: Network): Promise<StakerItem[]> { return await super.getAll({ - dnpNames: Execution.CompatibleExecutions[network].map( - (client) => client.dnpName - ), - currentClient: this.DbHandlers[network].get(), + dnpNames: Execution.CompatibleExecutions[network].map((client) => client.dnpName), + currentClient: this.DbHandlers[network].get() }); } @@ -80,7 +73,7 @@ export class Execution extends StakerComponent { const currentExecutionDnpName = this.DbHandlers[network].get(); if (currentExecutionDnpName) { const isInstalled = await listPackageNoThrow({ - dnpName: currentExecutionDnpName, + dnpName: currentExecutionDnpName }); if (!isInstalled) { @@ -90,7 +83,7 @@ export class Execution extends StakerComponent { } await this.persistSelectedIfInstalled({ dnpName: currentExecutionDnpName, - userSettings: this.getUserSettings(network, currentExecutionDnpName), + userSettings: this.getUserSettings(network, currentExecutionDnpName) }); await this.DbHandlers[network].set(currentExecutionDnpName); } @@ -103,10 +96,8 @@ export class Execution extends StakerComponent { newStakerDnpName: newExecutionDnpName, dockerNetworkName: params.DOCKER_STAKER_NETWORKS[network], compatibleClients: Execution.CompatibleExecutions[network], - userSettings: newExecutionDnpName - ? this.getUserSettings(network, newExecutionDnpName) - : {}, - prevClient: prevExecClientDnpName, + userSettings: newExecutionDnpName ? this.getUserSettings(network, newExecutionDnpName) : {}, + prevClient: prevExecClientDnpName }); if (newExecutionDnpName !== prevExecClientDnpName) { @@ -116,7 +107,7 @@ export class Execution extends StakerComponent { await ethereumClient.updateFullnodeAlias({ network, newExecClientDnpName: newExecutionDnpName, - prevExecClientDnpName: prevExecClientDnpName || "", + prevExecClientDnpName: prevExecClientDnpName || "" }); } } @@ -126,23 +117,23 @@ export class Execution extends StakerComponent { networks: { rootNetworks: { [params.DOCKER_STAKER_NETWORKS[network]]: { - external: true, + external: true }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - external: true, - }, + external: true + } }, serviceNetworks: { [this.getExecutionServiceName(dnpName)]: { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [`execution.${network}.staker.dappnode`], + aliases: [`execution.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [`execution.${network}.dncore.dappnode`], - }, - }, - }, - }, + aliases: [`execution.${network}.dncore.dappnode`] + } + } + } + } }; } @@ -153,8 +144,7 @@ export class Execution extends StakerComponent { */ private getExecutionServiceName(dnpName: string): string { // TODO: geth mainnet is the only execution with service name === dnpName. See https://github.com/dappnode/DAppNodePackage-geth/blob/7e8e5aa860a8861986f675170bfa92215760d32e/docker-compose.yml#L3 - if (dnpName === ExecutionClientMainnet.Geth) - return ExecutionClientMainnet.Geth; + if (dnpName === ExecutionClientMainnet.Geth) return ExecutionClientMainnet.Geth; if (dnpName.includes("geth")) return "geth"; if (dnpName.includes("nethermind")) return "nethermind"; if (dnpName.includes("erigon")) return "erigon"; diff --git a/packages/stakers/src/mevBoost.ts b/packages/stakers/src/mevBoost.ts index 27a6660ce..ae3a651c8 100644 --- a/packages/stakers/src/mevBoost.ts +++ b/packages/stakers/src/mevBoost.ts @@ -1,11 +1,4 @@ -import { - MevBoostHolesky, - MevBoostMainnet, - MevBoostPrater, - Network, - StakerItem, - UserSettings, -} from "@dappnode/types"; +import { MevBoostHolesky, MevBoostMainnet, MevBoostPrater, Network, StakerItem, UserSettings } from "@dappnode/types"; import { StakerComponent } from "./stakerComponent.js"; import { DappnodeInstaller } from "@dappnode/installer"; import * as db from "@dappnode/db"; @@ -14,35 +7,29 @@ import { params } from "@dappnode/params"; import { ComposeFileEditor } from "@dappnode/dockercompose"; export class MevBoost extends StakerComponent { - readonly DbHandlers: Record< - Network, - { get: () => boolean; set: (globEnvValue: boolean) => Promise<void> } - > = { + readonly DbHandlers: Record<Network, { get: () => boolean; set: (globEnvValue: boolean) => Promise<void> }> = { [Network.Mainnet]: db.mevBoostMainnet, [Network.Gnosis]: db.mevBoostGnosis, [Network.Prater]: db.mevBoostPrater, [Network.Holesky]: db.mevBoostHolesky, - [Network.Lukso]: db.mevBoostLukso, + [Network.Lukso]: db.mevBoostLukso }; - protected static readonly CompatibleMevBoost: Record< - Network, - { dnpName: string; minVersion: string } | null - > = { + protected static readonly CompatibleMevBoost: Record<Network, { dnpName: string; minVersion: string } | null> = { [Network.Mainnet]: { dnpName: MevBoostMainnet.Mevboost, - minVersion: "0.1.0", + minVersion: "0.1.0" }, [Network.Gnosis]: null, [Network.Prater]: { dnpName: MevBoostPrater.Mevboost, - minVersion: "0.1.0", + minVersion: "0.1.0" }, [Network.Holesky]: { dnpName: MevBoostHolesky.Mevboost, - minVersion: "0.1.0", + minVersion: "0.1.0" }, - [Network.Lukso]: null, + [Network.Lukso]: null }; constructor(dappnodeInstaller: DappnodeInstaller) { @@ -54,36 +41,26 @@ export class MevBoost extends StakerComponent { return await super.getAll({ dnpNames: mevBoostDnpName ? [mevBoostDnpName] : [], currentClient: this.DbHandlers[network].get(), - relays: await this.getMevBoostCurrentRelays(mevBoostDnpName), + relays: await this.getMevBoostCurrentRelays(mevBoostDnpName) }); } async getMevBoostCurrentRelays(mevBoostDnpName?: string): Promise<string[]> { const relays: string[] = []; - if ( - !mevBoostDnpName || - !(await listPackageNoThrow({ dnpName: mevBoostDnpName })) - ) - return relays; - const pkgEnv = new ComposeFileEditor( - mevBoostDnpName, - false - ).getUserSettings().environment; + if (!mevBoostDnpName || !(await listPackageNoThrow({ dnpName: mevBoostDnpName }))) return relays; + const pkgEnv = new ComposeFileEditor(mevBoostDnpName, false).getUserSettings().environment; if (pkgEnv) { - pkgEnv["mev-boost"]["RELAYS"] - .split(",") - .forEach((relay) => relays.push(relay)); + pkgEnv["mev-boost"]["RELAYS"].split(",").forEach((relay) => relays.push(relay)); } return relays; } async persistMevBoostIfInstalledAndRunning(network: Network): Promise<void> { - const currentMevBoostDnpName = - MevBoost.CompatibleMevBoost[network]?.dnpName; + const currentMevBoostDnpName = MevBoost.CompatibleMevBoost[network]?.dnpName; if (currentMevBoostDnpName) { const isInstalledAndRunning = ( await listPackageNoThrow({ - dnpName: currentMevBoostDnpName, + dnpName: currentMevBoostDnpName }) )?.containers.some((container) => container.running); @@ -93,37 +70,27 @@ export class MevBoost extends StakerComponent { } await this.persistSelectedIfInstalled({ dnpName: currentMevBoostDnpName, - userSettings: this.getUserSettings([], false, network), + userSettings: this.getUserSettings([], false, network) }); this.DbHandlers[network].set(true); } } - async setNewMevBoost( - network: Network, - newMevBoostDnpName: string | null, - newRelays: string[] - ) { + async setNewMevBoost(network: Network, newMevBoostDnpName: string | null, newRelays: string[]) { const compatibleMevBoost = MevBoost.CompatibleMevBoost[network]; await super.setNew({ newStakerDnpName: newMevBoostDnpName, dockerNetworkName: params.DOCKER_STAKER_NETWORKS[network], compatibleClients: compatibleMevBoost ? [compatibleMevBoost] : null, - userSettings: newMevBoostDnpName - ? this.getUserSettings(newRelays, true, network) - : {}, - prevClient: compatibleMevBoost ? compatibleMevBoost.dnpName : null, + userSettings: newMevBoostDnpName ? this.getUserSettings(newRelays, true, network) : {}, + prevClient: compatibleMevBoost ? compatibleMevBoost.dnpName : null }); // persist on db if (Boolean(newMevBoostDnpName) !== this.DbHandlers[network].get()) await this.DbHandlers[network].set(newMevBoostDnpName ? true : false); } - private getUserSettings( - newRelays: string[], - shouldSetEnvironment: boolean, - network: Network - ): UserSettings { + private getUserSettings(newRelays: string[], shouldSetEnvironment: boolean, network: Network): UserSettings { return { environment: shouldSetEnvironment ? { @@ -132,30 +99,30 @@ export class MevBoost extends StakerComponent { newRelays .join(",") .trim() - .replace(/(^,)|(,$)/g, "") || "", - }, + .replace(/(^,)|(,$)/g, "") || "" + } } : {}, networks: { rootNetworks: { [params.DOCKER_STAKER_NETWORKS[network]]: { - external: true, + external: true }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - external: true, - }, + external: true + } }, serviceNetworks: { ["mev-boost"]: { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [`mev-boost.${network}.staker.dappnode`], + aliases: [`mev-boost.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [`mev-boost.${network}.dncore.dappnode`], - }, - }, - }, - }, + aliases: [`mev-boost.${network}.dncore.dappnode`] + } + } + } + } }; } } diff --git a/packages/stakers/src/signer.ts b/packages/stakers/src/signer.ts index e4761cb9b..e18e0c373 100644 --- a/packages/stakers/src/signer.ts +++ b/packages/stakers/src/signer.ts @@ -6,7 +6,7 @@ import { SignerMainnet, SignerPrater, StakerItem, - UserSettings, + UserSettings } from "@dappnode/types"; import { StakerComponent } from "./stakerComponent.js"; import { DappnodeInstaller } from "@dappnode/installer"; @@ -16,30 +16,27 @@ import { listPackageNoThrow } from "@dappnode/dockerapi"; export class Signer extends StakerComponent { protected static readonly ServiceAliasesMap: Record<string, string[]> = {}; - protected static readonly CompatibleSigners: Record< - Network, - { dnpName: string; minVersion: string } - > = { + protected static readonly CompatibleSigners: Record<Network, { dnpName: string; minVersion: string }> = { [Network.Mainnet]: { dnpName: SignerMainnet.Web3signer, - minVersion: "0.1.4", + minVersion: "0.1.4" }, [Network.Gnosis]: { dnpName: SignerGnosis.Web3signer, - minVersion: "0.1.10", + minVersion: "0.1.10" }, [Network.Prater]: { dnpName: SignerPrater.Web3signer, - minVersion: "0.1.11", + minVersion: "0.1.11" }, [Network.Holesky]: { dnpName: SignerHolesky.Web3signer, - minVersion: "0.1.0", + minVersion: "0.1.0" }, [Network.Lukso]: { dnpName: SignerLukso.Web3signer, - minVersion: "0.1.0", - }, + minVersion: "0.1.0" + } }; constructor(dappnodeInstaller: DappnodeInstaller) { @@ -49,7 +46,7 @@ export class Signer extends StakerComponent { async getAllSigners(network: Network): Promise<StakerItem[]> { return await super.getAll({ dnpNames: [Signer.CompatibleSigners[network].dnpName], - currentClient: Signer.CompatibleSigners[network].dnpName, + currentClient: Signer.CompatibleSigners[network].dnpName }); } @@ -57,13 +54,13 @@ export class Signer extends StakerComponent { if ( ( await listPackageNoThrow({ - dnpName: Signer.CompatibleSigners[network].dnpName, + dnpName: Signer.CompatibleSigners[network].dnpName }) )?.containers.some((container) => container.running) ) await this.persistSelectedIfInstalled({ dnpName: Signer.CompatibleSigners[network].dnpName, - userSettings: this.getUserSettings(network), + userSettings: this.getUserSettings(network) }); } @@ -73,7 +70,7 @@ export class Signer extends StakerComponent { dockerNetworkName: params.DOCKER_STAKER_NETWORKS[network], compatibleClients: [Signer.CompatibleSigners[network]], userSettings: this.getUserSettings(network), - prevClient: Signer.CompatibleSigners[network].dnpName, + prevClient: Signer.CompatibleSigners[network].dnpName }); } @@ -82,23 +79,23 @@ export class Signer extends StakerComponent { networks: { rootNetworks: { [params.DOCKER_STAKER_NETWORKS[network]]: { - external: true, + external: true }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - external: true, - }, + external: true + } }, serviceNetworks: { web3signer: { [params.DOCKER_STAKER_NETWORKS[network]]: { - aliases: [`signer.${network}.staker.dappnode`], + aliases: [`signer.${network}.staker.dappnode`] }, [params.DOCKER_PRIVATE_NETWORK_NAME]: { - aliases: [`signer.${network}.dncore.dappnode`], - }, - }, - }, - }, + aliases: [`signer.${network}.dncore.dappnode`] + } + } + } + } }; } } diff --git a/packages/stakers/src/stakerComponent.ts b/packages/stakers/src/stakerComponent.ts index 73bc0b66c..e2d897036 100644 --- a/packages/stakers/src/stakerComponent.ts +++ b/packages/stakers/src/stakerComponent.ts @@ -3,14 +3,10 @@ import { dockerContainerStop, dockerNetworkDisconnect, listPackageNoThrow, - listPackages, + listPackages } from "@dappnode/dockerapi"; import { ComposeFileEditor } from "@dappnode/dockercompose"; -import { - DappnodeInstaller, - packageGetData, - packageInstall, -} from "@dappnode/installer"; +import { DappnodeInstaller, packageGetData, packageInstall } from "@dappnode/installer"; import { logs } from "@dappnode/logger"; import { InstalledPackageDataApiReturn, @@ -18,14 +14,9 @@ import { UserSettingsAllDnps, PackageContainer, StakerItem, - UserSettings, + UserSettings } from "@dappnode/types"; -import { - getIsInstalled, - getIsUpdated, - getIsRunning, - fileToGatewayUrl, -} from "@dappnode/utils"; +import { getIsInstalled, getIsUpdated, getIsRunning, fileToGatewayUrl } from "@dappnode/utils"; import { lt } from "semver"; import { isMatch } from "lodash-es"; @@ -39,7 +30,7 @@ export class StakerComponent { protected async getAll({ dnpNames, currentClient, - relays, + relays }: { dnpNames: string[]; currentClient?: boolean | string | null; @@ -61,13 +52,13 @@ export class StakerComponent { isRunning: getIsRunning(pkgData, dnpList), data: pkgData, relays, // only for mevBoost - isSelected: dnpName === currentClient || currentClient === true, + isSelected: dnpName === currentClient || currentClient === true }; } catch (error) { return { status: "error", dnpName, - error, + error }; } }) @@ -76,7 +67,7 @@ export class StakerComponent { protected async persistSelectedIfInstalled({ dnpName, - userSettings, + userSettings }: { dnpName: string; userSettings: UserSettings; @@ -90,7 +81,7 @@ export class StakerComponent { dockerNetworkName, compatibleClients, userSettings, - prevClient, + prevClient }: { newStakerDnpName: string | null | undefined; dockerNetworkName: string; @@ -109,28 +100,21 @@ export class StakerComponent { } const currentPkg = await listPackageNoThrow({ - dnpName: prevClient || "", + dnpName: prevClient || "" }); if (currentPkg) { if (prevClient && compatibleClients) - this.ensureCompatibilityRequirements( - prevClient, - compatibleClients, - currentPkg.version - ); - if (prevClient !== newStakerDnpName) - await this.unsetStakerPkgConfig(currentPkg, dockerNetworkName); + this.ensureCompatibilityRequirements(prevClient, compatibleClients, currentPkg.version); + if (prevClient !== newStakerDnpName) await this.unsetStakerPkgConfig(currentPkg, dockerNetworkName); } if (!newStakerDnpName) return; // set staker config await this.setStakerPkgConfig({ dnpName: newStakerDnpName, - isInstalled: Boolean( - await listPackageNoThrow({ dnpName: newStakerDnpName }) - ), - userSettings, + isInstalled: Boolean(await listPackageNoThrow({ dnpName: newStakerDnpName })), + userSettings }); } @@ -144,7 +128,7 @@ export class StakerComponent { private async setStakerPkgConfig({ dnpName, isInstalled, - userSettings, + userSettings }: { dnpName: string; isInstalled: boolean; @@ -154,7 +138,7 @@ export class StakerComponent { if (!isInstalled) await packageInstall(this.dappnodeInstaller, { name: dnpName, - userSettings: userSettings ? { [dnpName]: userSettings } : {}, + userSettings: userSettings ? { [dnpName]: userSettings } : {} }); else if (userSettings) { const composeEditor = new ComposeFileEditor(dnpName, false); @@ -176,15 +160,9 @@ export class StakerComponent { * - stops the staker pkg * - removes the staker network from the docker-compose file */ - private async unsetStakerPkgConfig( - pkg: InstalledPackageData, - dockerNetworkName: string - ): Promise<void> { + private async unsetStakerPkgConfig(pkg: InstalledPackageData, dockerNetworkName: string): Promise<void> { // disconnect pkg from staker network - await this.disconnectPkgFromStakerNetwork( - dockerNetworkName, - pkg.containers - ); + await this.disconnectPkgFromStakerNetwork(dockerNetworkName, pkg.containers); // stop all containers await this.stopAllPkgContainers(pkg); @@ -192,23 +170,14 @@ export class StakerComponent { this.removeStakerNetworkFromCompose(pkg.dnpName, dockerNetworkName); } - private async disconnectPkgFromStakerNetwork( - networkName: string, - pkgContainers: PackageContainer[] - ): Promise<void> { + private async disconnectPkgFromStakerNetwork(networkName: string, pkgContainers: PackageContainer[]): Promise<void> { const connectedContainers = pkgContainers - .filter((container) => - container.networks.some((network) => network.name === networkName) - ) + .filter((container) => container.networks.some((network) => network.name === networkName)) .map((container) => container.containerName); - for (const container of connectedContainers) - await dockerNetworkDisconnect(networkName, container); + for (const container of connectedContainers) await dockerNetworkDisconnect(networkName, container); } - private removeStakerNetworkFromCompose( - dnpName: string, - dockerNetworkName: string - ): void { + private removeStakerNetworkFromCompose(dnpName: string, dockerNetworkName: string): void { const composeEditor = new ComposeFileEditor(dnpName, false); const services = composeEditor.compose.services; @@ -222,9 +191,7 @@ export class StakerComponent { // Array case if (Array.isArray(serviceNetworks)) - service.networks = serviceNetworks.filter( - (network) => network !== dockerNetworkName - ); + service.networks = serviceNetworks.filter((network) => network !== dockerNetworkName); // ComposeServiceNetworksObj case else delete serviceNetworks[dockerNetworkName]; } @@ -242,21 +209,13 @@ export class StakerComponent { ): void { if (!dnpName) return; - const compatibleClient = compatibleClients.find( - (c) => c.dnpName === dnpName - ); + const compatibleClient = compatibleClients.find((c) => c.dnpName === dnpName); // ensure valid dnpName - if (!compatibleClient) - throw Error( - "The selected staker is not compatible with the current network" - ); + if (!compatibleClient) throw Error("The selected staker is not compatible with the current network"); // ensure valid version - if ( - compatibleClient?.minVersion && - lt(pkgVersion, compatibleClient.minVersion) - ) { + if (compatibleClient?.minVersion && lt(pkgVersion, compatibleClient.minVersion)) { throw Error( `The selected staker version from ${dnpName} is not compatible with the current network. Required version: ${compatibleClient.minVersion}. Got: ${pkgVersion}` ); @@ -267,15 +226,11 @@ export class StakerComponent { * Stop all the containers from a given package dnpName */ // TODO: Move this to where packages and containers are started/stopped - private async stopAllPkgContainers( - pkg: InstalledPackageDataApiReturn | InstalledPackageData - ): Promise<void> { + private async stopAllPkgContainers(pkg: InstalledPackageDataApiReturn | InstalledPackageData): Promise<void> { await Promise.all( pkg.containers .filter((c) => c.running) - .map(async (c) => - dockerContainerStop(c.containerName, { timeout: c.dockerTimeout }) - ) + .map(async (c) => dockerContainerStop(c.containerName, { timeout: c.dockerTimeout })) ).catch((e) => logs.error(e.message)); } } diff --git a/packages/toolkit/.eslintignore b/packages/toolkit/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/toolkit/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/toolkit/.eslintrc.cjs b/packages/toolkit/.eslintrc.cjs deleted file mode 100644 index a837cc0bc..000000000 --- a/packages/toolkit/.eslintrc.cjs +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - // ignore the directory theGraph - ignorePatterns: ["theGraph"], -}; diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index a57546af9..1e846bdde 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -9,7 +9,6 @@ "clean": "rimraf dist", "dev": "tsc -w", "build": "tsc -p tsconfig.json", - "lint": "eslint . --ext .ts", "format": "prettier --write \"src/**/*.ts\"", "test": "mocha --config .mocharc.yml test/**/*.test.ts", "truffle:compile:v0.4": "truffle compile --config ./truffle/truffle-config-v0.4.cjs", @@ -29,12 +28,7 @@ "@types/mocha": "^10", "@types/node": "^20.14.10", "@types/semver": "^7.3.13", - "@typescript-eslint/eslint-plugin": "^5.59.2", - "@typescript-eslint/parser": "^5.59.5", - "eslint": "^8.38.0", - "eslint-plugin-import": "^2.27.5", "mocha": "^10.7.0", - "prettier": "^2.8.7", "rimraf": "^5.0.0", "truffle": "^5.9.0", "ts-loader": "^9.4.2", diff --git a/packages/toolkit/src/directory/directory.ts b/packages/toolkit/src/directory/directory.ts index 1c8e12eb1..f89eb8262 100644 --- a/packages/toolkit/src/directory/directory.ts +++ b/packages/toolkit/src/directory/directory.ts @@ -15,11 +15,7 @@ export class DappNodeDirectory { * @param ethUrl - The URL of the Ethereum node to connect to. */ constructor(ethersProvider: ethers.AbstractProvider) { - this.directoryContract = new ethers.Contract( - directoryAddress, - directoryAbi, - ethersProvider - ); + this.directoryContract = new ethers.Contract(directoryAddress, directoryAbi, ethersProvider); } /** @@ -30,10 +26,7 @@ export class DappNodeDirectory { const numberOfDappnodePackages = await this.fetchNumberOfPackages(); const featuredIndexes = await this.fetchFeaturedPackagesIndexes(); - const directoryPkgs = await this.fetchPackageDetails( - numberOfDappnodePackages, - featuredIndexes - ); + const directoryPkgs = await this.fetchPackageDetails(numberOfDappnodePackages, featuredIndexes); return this.sortDirectoryPkgs(directoryPkgs); } @@ -43,9 +36,7 @@ export class DappNodeDirectory { * @returns - A promise that resolves to the number of Dappnode packages. */ private async fetchNumberOfPackages(): Promise<number> { - return parseInt( - (await this.directoryContract.numberOfDAppNodePackages()).toString() - ); + return parseInt((await this.directoryContract.numberOfDAppNodePackages()).toString()); } /** @@ -57,10 +48,7 @@ export class DappNodeDirectory { return (featuredBytes.replace("0x", "").match(/.{1,2}/g) ?? []) .filter((value: string) => value !== "00") - .filter( - (value: string, index: number, self: string[]) => - self.indexOf(value) === index - ) + .filter((value: string, index: number, self: string[]) => self.indexOf(value) === index) .map((base64: string) => parseInt(base64, 16)); } @@ -70,22 +58,12 @@ export class DappNodeDirectory { * @param featuredIndexes - The indexes of featured packages. * @returns - A promise that resolves to an array of package details. */ - private async fetchPackageDetails( - numberOfPackages: number, - featuredIndexes: number[] - ): Promise<DirectoryDnp[]> { - const packageIndices = Array.from( - { length: numberOfPackages }, - (_, i) => i - ); + private async fetchPackageDetails(numberOfPackages: number, featuredIndexes: number[]): Promise<DirectoryDnp[]> { + const packageIndices = Array.from({ length: numberOfPackages }, (_, i) => i); - const packages = await Promise.all( - packageIndices.map((i) => this.fetchPackageDetail(i, featuredIndexes)) - ); + const packages = await Promise.all(packageIndices.map((i) => this.fetchPackageDetail(i, featuredIndexes))); - return packages.filter( - (dnp): dnp is DirectoryDnp => typeof dnp !== "undefined" - ); + return packages.filter((dnp): dnp is DirectoryDnp => typeof dnp !== "undefined"); } /** @@ -94,16 +72,9 @@ export class DappNodeDirectory { * @param featuredIndexes - The indexes of featured packages. * @returns - A promise that resolves to the package details or undefined if there was an error. */ - private async fetchPackageDetail( - index: number, - featuredIndexes: number[] - ): Promise<DirectoryDnp | undefined> { + private async fetchPackageDetail(index: number, featuredIndexes: number[]): Promise<DirectoryDnp | undefined> { try { - const { - name, - status: statusBn, - position: positionBn, - } = await this.directoryContract.getPackage(index); + const { name, status: statusBn, position: positionBn } = await this.directoryContract.getPackage(index); const status = parseInt(statusBn.toString()); if (!isEnsDomain(name) || status === 0) return; @@ -114,11 +85,10 @@ export class DappNodeDirectory { statusName: directoryDnpStatus[status], position: parseInt(positionBn.toString()), isFeatured: featuredIndex > -1, - featuredIndex: featuredIndex, + featuredIndex: featuredIndex }; } catch (e) { - if (e instanceof Error) - e.message = `Error retrieving DNP #${index} from directory ${e}`; + if (e instanceof Error) e.message = `Error retrieving DNP #${index} from directory ${e}`; console.log(e); return; } @@ -136,7 +106,7 @@ export class DappNodeDirectory { const notFeatured = dnps.filter((dnp) => !dnp.isFeatured); return [ ...featured.sort((a, b) => a.featuredIndex - b.featuredIndex), - ...notFeatured.sort((a, b) => b.position - a.position), + ...notFeatured.sort((a, b) => b.position - a.position) ]; } } diff --git a/packages/toolkit/src/directory/params.ts b/packages/toolkit/src/directory/params.ts index 9ff0bb0c5..371c9e727 100644 --- a/packages/toolkit/src/directory/params.ts +++ b/packages/toolkit/src/directory/params.ts @@ -7,13 +7,13 @@ export const directoryAbi = [ inputs: [ { name: "name", type: "string" }, { name: "status", type: "uint128" }, - { name: "position", type: "uint128" }, + { name: "position", type: "uint128" } ], name: "addPackage", outputs: [{ name: "idPackage", type: "uint256" }], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -22,7 +22,7 @@ export const directoryAbi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, @@ -31,7 +31,7 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -40,19 +40,19 @@ export const directoryAbi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, inputs: [ { name: "idPackage", type: "uint256" }, - { name: "newStatus", type: "uint128" }, + { name: "newStatus", type: "uint128" } ], name: "changeStatus", outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, @@ -61,19 +61,19 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, inputs: [ { name: "idPackage1", type: "uint256" }, - { name: "idPackage2", type: "uint256" }, + { name: "idPackage2", type: "uint256" } ], name: "switchPosition", outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, @@ -82,19 +82,19 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, inputs: [ { name: "idPackage", type: "uint256" }, - { name: "newPosition", type: "uint128" }, + { name: "newPosition", type: "uint128" } ], name: "changePosition", outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, @@ -103,7 +103,7 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -112,7 +112,7 @@ export const directoryAbi = [ outputs: [{ name: "", type: "bool" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -121,7 +121,7 @@ export const directoryAbi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, @@ -130,7 +130,7 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -139,7 +139,7 @@ export const directoryAbi = [ outputs: [{ name: "", type: "uint256" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -148,11 +148,11 @@ export const directoryAbi = [ outputs: [ { name: "name", type: "string" }, { name: "status", type: "uint128" }, - { name: "position", type: "uint128" }, + { name: "position", type: "uint128" } ], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, @@ -160,13 +160,13 @@ export const directoryAbi = [ { name: "idPackage", type: "uint256" }, { name: "name", type: "string" }, { name: "status", type: "uint128" }, - { name: "position", type: "uint128" }, + { name: "position", type: "uint128" } ], name: "updatePackage", outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -175,7 +175,7 @@ export const directoryAbi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, @@ -184,7 +184,7 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, @@ -193,7 +193,7 @@ export const directoryAbi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -202,96 +202,96 @@ export const directoryAbi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { inputs: [ { name: "_escapeHatchCaller", type: "address" }, - { name: "_escapeHatchDestination", type: "address" }, + { name: "_escapeHatchDestination", type: "address" } ], payable: false, stateMutability: "nonpayable", - type: "constructor", + type: "constructor" }, { anonymous: false, inputs: [ { indexed: true, name: "idPackage", type: "uint256" }, - { indexed: false, name: "name", type: "string" }, + { indexed: false, name: "name", type: "string" } ], name: "PackageAdded", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: true, name: "idPackage", type: "uint256" }, - { indexed: false, name: "name", type: "string" }, + { indexed: false, name: "name", type: "string" } ], name: "PackageUpdated", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: false, name: "idPackage", type: "uint256" }, - { indexed: false, name: "newStatus", type: "uint128" }, + { indexed: false, name: "newStatus", type: "uint128" } ], name: "StatusChanged", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: false, name: "idPackage", type: "uint256" }, - { indexed: false, name: "newPosition", type: "uint128" }, + { indexed: false, name: "newPosition", type: "uint128" } ], name: "PositionChanged", - type: "event", + type: "event" }, { anonymous: false, inputs: [{ indexed: false, name: "newFeatured", type: "bytes32" }], name: "FeaturedChanged", - type: "event", + type: "event" }, { anonymous: false, inputs: [{ indexed: false, name: "token", type: "address" }], name: "EscapeHatchBlackistedToken", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: false, name: "token", type: "address" }, - { indexed: false, name: "amount", type: "uint256" }, + { indexed: false, name: "amount", type: "uint256" } ], name: "EscapeHatchCalled", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: true, name: "by", type: "address" }, - { indexed: true, name: "to", type: "address" }, + { indexed: true, name: "to", type: "address" } ], name: "OwnershipRequested", - type: "event", + type: "event" }, { anonymous: false, inputs: [ { indexed: true, name: "from", type: "address" }, - { indexed: true, name: "to", type: "address" }, + { indexed: true, name: "to", type: "address" } ], name: "OwnershipTransferred", - type: "event", + type: "event" }, { anonymous: false, inputs: [], name: "OwnershipRemoved", - type: "event", - }, + type: "event" + } ] as const; diff --git a/packages/toolkit/src/registry/params.ts b/packages/toolkit/src/registry/params.ts index c88b1f291..51b5c4561 100644 --- a/packages/toolkit/src/registry/params.ts +++ b/packages/toolkit/src/registry/params.ts @@ -1,9 +1,7 @@ import { Abi } from "../types.js"; -export const dnpRegistryGraphEndpoint = - "https://api.studio.thegraph.com/query/45661/dappnode-registry/v0.0.3"; -export const publicRegistryGraphEndpoint = - "https://api.studio.thegraph.com/query/45661/public-registry/v0.1.0"; +export const dnpRegistryGraphEndpoint = "https://api.studio.thegraph.com/query/45661/dappnode-registry/v0.0.3"; +export const publicRegistryGraphEndpoint = "https://api.studio.thegraph.com/query/45661/public-registry/v0.1.0"; // APM REGISTRY SMART CONTRACT: https://etherscan.io/address/0x1d9bdf492e59a306dda59e5aa13e7f1c7d89197a#code @@ -19,8 +17,7 @@ export const publicRegistryGraphEndpoint = export const registryContractName = "registry"; export const registryAddress = "0x1d9Bdf492e59A306DDa59E5aA13E7F1C7D89197A"; // public.dappnode.eth: 0x9f85ae5aefe4a3eff39d9a44212aae21dd15079aç -export const registryPublicAddress = - "0x9f85ae5aefe4a3eff39d9a44212aae21dd15079a"; +export const registryPublicAddress = "0x9f85ae5aefe4a3eff39d9a44212aae21dd15079a"; // dnp.dappnode.eth: 0x266bfdb2124a68beb6769dc887bd655f78778923 export const registryDnpAddress = "0x266bfdb2124a68beb6769dc887bd655f78778923"; export const registryAbi: Abi = [ @@ -31,7 +28,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "string" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -40,7 +37,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "string" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -49,7 +46,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "string" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -58,7 +55,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, @@ -67,13 +64,13 @@ export const registryAbi: Abi = [ { name: "_dev", type: "address" }, { name: "_initialSemanticVersion", type: "uint16[3]" }, { name: "_contractAddress", type: "address" }, - { name: "_contentURI", type: "bytes" }, + { name: "_contentURI", type: "bytes" } ], name: "newRepoWithVersion", outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -82,7 +79,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -91,7 +88,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -100,7 +97,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -109,7 +106,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "uint256" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -118,32 +115,32 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, inputs: [ { name: "_sender", type: "address" }, { name: "_role", type: "bytes32" }, - { name: "params", type: "uint256[]" }, + { name: "params", type: "uint256[]" } ], name: "canPerform", outputs: [{ name: "", type: "bool" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, inputs: [ { name: "_name", type: "string" }, - { name: "_dev", type: "address" }, + { name: "_dev", type: "address" } ], name: "newRepo", outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: false, @@ -152,7 +149,7 @@ export const registryAbi: Abi = [ outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -161,7 +158,7 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -170,22 +167,22 @@ export const registryAbi: Abi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { anonymous: false, inputs: [ { indexed: false, name: "id", type: "bytes32" }, { indexed: false, name: "name", type: "string" }, - { indexed: false, name: "repo", type: "address" }, + { indexed: false, name: "repo", type: "address" } ], name: "NewRepo", - type: "event", + type: "event" }, { anonymous: false, inputs: [{ indexed: false, name: "proxy", type: "address" }], name: "NewAppProxy", - type: "event", - }, + type: "event" + } ] as const; diff --git a/packages/toolkit/src/registry/registry.ts b/packages/toolkit/src/registry/registry.ts index 508140ad2..a63aa8214 100644 --- a/packages/toolkit/src/registry/registry.ts +++ b/packages/toolkit/src/registry/registry.ts @@ -1,9 +1,6 @@ import { DNPRegistryEntry, PublicRegistryEntry, Registry } from "./types.js"; import { request, gql } from "graphql-request"; -import { - dnpRegistryGraphEndpoint, - publicRegistryGraphEndpoint, -} from "./params.js"; +import { dnpRegistryGraphEndpoint, publicRegistryGraphEndpoint } from "./params.js"; // TODO: Consider adding scanning functions for events @@ -25,8 +22,7 @@ export class DappNodeRegistry { if (registry === "dnp") this.graphEndpoint = dnpRegistryGraphEndpoint; else this.graphEndpoint = publicRegistryGraphEndpoint; - this.nameSuffix = - this.registry === "dnp" ? ".dnp.dappnode.eth" : ".public.dappnode.eth"; + this.nameSuffix = this.registry === "dnp" ? ".dnp.dappnode.eth" : ".public.dappnode.eth"; } /** diff --git a/packages/toolkit/src/repository/apmRepository.ts b/packages/toolkit/src/repository/apmRepository.ts index c65c2b4e8..cc2e93b38 100644 --- a/packages/toolkit/src/repository/apmRepository.ts +++ b/packages/toolkit/src/repository/apmRepository.ts @@ -1,10 +1,6 @@ import { ethers } from "ethers"; import { valid, parse, validRange } from "semver"; -import { - ApmRepoVersionReturn, - ApmVersionRawAndOrigin, - ApmVersionState, -} from "./types.js"; +import { ApmRepoVersionReturn, ApmVersionRawAndOrigin, ApmVersionState } from "./types.js"; import * as isIPFS from "is-ipfs"; import { isEnsDomain } from "../isEnsDomain.js"; import { repositoryAbi } from "./params.js"; @@ -39,18 +35,11 @@ export class ApmRepository { * @returns - A promise that resolves to the Repo instance. */ public async getRepoContract(dnpName: string): Promise<ethers.Contract> { - const contractAddress = await this.ethProvider.resolveName( - this.ensureValidDnpName(dnpName) - ); + const contractAddress = await this.ethProvider.resolveName(this.ensureValidDnpName(dnpName)); // This error should include "NOREPO" in order to handle it properly in SDK publish code - if (!contractAddress) - throw new Error(`Could not resolve name ${dnpName}: NOREPO`); - return new ethers.Contract( - contractAddress, - repositoryAbi, - this.ethProvider - ); + if (!contractAddress) throw new Error(`Could not resolve name ${dnpName}: NOREPO`); + return new ethers.Contract(contractAddress, repositoryAbi, this.ethProvider); } /** @@ -62,7 +51,7 @@ export class ApmRepository { */ public async getVersionAndIpfsHash({ dnpNameOrHash, - version = "*", + version = "*" }: { dnpNameOrHash: string; version?: string; @@ -73,22 +62,18 @@ export class ApmRepository { // Normal cases: // - name = eth domain & ver = semverVersion // - name = eth domain & ver = semverRange, [DO-NOT-CACHE] as the version is dynamic - if ( - isEnsDomain(dnpNameOrHash) && - (this.isSemver(version) || this.isSemverRange(version)) - ) { + if (isEnsDomain(dnpNameOrHash) && (this.isSemver(version) || this.isSemverRange(version))) { const repoContract = await this.getRepoContract(dnpNameOrHash); const res = version && valid(version) - ? await repoContract.getBySemanticVersion( - this.toApmVersionArray(version) - ) + ? await repoContract.getBySemanticVersion(this.toApmVersionArray(version)) : await repoContract.getLatest(); return this.parseApmVersionReturn({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any semanticVersion: res[0].map((v: any) => parseInt(v.toString())), contractAddress: res[1], - contentURI: res[2], + contentURI: res[2] }); } @@ -97,7 +82,7 @@ export class ApmRepository { return { version, contentUri: version, - origin: version, + origin: version }; } @@ -107,14 +92,12 @@ export class ApmRepository { return { version, contentUri: dnpNameOrHash, - origin: dnpNameOrHash, + origin: dnpNameOrHash }; // All other cases are invalid - if (isEnsDomain(dnpNameOrHash)) - throw Error(`Invalid version, must be a semver or a hash: ${version}`); - else - throw Error(`Invalid DNP name, must be a ENS domain: ${dnpNameOrHash}`); + if (isEnsDomain(dnpNameOrHash)) throw Error(`Invalid version, must be a semver or a hash: ${version}`); + else throw Error(`Invalid DNP name, must be a ENS domain: ${dnpNameOrHash}`); } /** @@ -133,10 +116,7 @@ export class ApmRepository { * If provided version request range, only returns satisfying versions * @param dnpName "bitcoin.dnp.dappnode.eth" */ - public async fetchApmVersionsState( - dnpName: string, - lastVersionId = 0 - ): Promise<ApmVersionState[]> { + public async fetchApmVersionsState(dnpName: string, lastVersionId = 0): Promise<ApmVersionState[]> { const repo = new ethers.Contract(dnpName, repositoryAbi, this.ethProvider); const versionCount: number = await repo.getVersionsCount().then(parseFloat); @@ -159,12 +139,10 @@ export class ApmRepository { const versionIndexes = this.linspace(lastVersionId + 1, versionCount); return await Promise.all( versionIndexes.map(async (i): Promise<ApmVersionState> => { - const versionData = await repo - .getByVersionId(i) - .then(this.parseApmVersionReturn); + const versionData = await repo.getByVersionId(i).then(this.parseApmVersionReturn); return { ...versionData, - versionId: i, + versionId: i }; }) ); @@ -179,13 +157,12 @@ export class ApmRepository { version: string; contentUri: string; } { - if (!Array.isArray(res.semanticVersion)) - throw Error(`property 'semanticVersion' must be an array`); + if (!Array.isArray(res.semanticVersion)) throw Error(`property 'semanticVersion' must be an array`); return { version: res.semanticVersion.join("."), // Second argument = true: ignore UTF8 parsing errors // Let downstream code identify the content hash as wrong - contentUri: ethers.toUtf8String(res.contentURI), + contentUri: ethers.toUtf8String(res.contentURI) }; } @@ -195,11 +172,9 @@ export class ApmRepository { * @returns - The valid DNP name. */ private ensureValidDnpName(dnpName: string): string { - if (!isEnsDomain(dnpName)) - throw Error(`Invalid ENS domain for dnpName ${dnpName}`); + if (!isEnsDomain(dnpName)) throw Error(`Invalid ENS domain for dnpName ${dnpName}`); - if (!dnpName.endsWith(".dappnode.eth")) - throw Error(`Invalid dnpName ${dnpName}`); + if (!dnpName.endsWith(".dappnode.eth")) throw Error(`Invalid dnpName ${dnpName}`); return dnpName; } diff --git a/packages/toolkit/src/repository/params.ts b/packages/toolkit/src/repository/params.ts index aea5be8f6..6c75597e7 100644 --- a/packages/toolkit/src/repository/params.ts +++ b/packages/toolkit/src/repository/params.ts @@ -19,11 +19,11 @@ export const repositoryAbi: Abi = [ outputs: [ { name: "semanticVersion", type: "uint16[3]" }, { name: "contractAddress", type: "address" }, - { name: "contentURI", type: "bytes" }, + { name: "contentURI", type: "bytes" } ], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -32,20 +32,20 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: false, inputs: [ { name: "_newSemanticVersion", type: "uint16[3]" }, { name: "_contractAddress", type: "address" }, - { name: "_contentURI", type: "bytes" }, + { name: "_contentURI", type: "bytes" } ], name: "newVersion", outputs: [], payable: false, stateMutability: "nonpayable", - type: "function", + type: "function" }, { constant: true, @@ -54,11 +54,11 @@ export const repositoryAbi: Abi = [ outputs: [ { name: "semanticVersion", type: "uint16[3]" }, { name: "contractAddress", type: "address" }, - { name: "contentURI", type: "bytes" }, + { name: "contentURI", type: "bytes" } ], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -67,7 +67,7 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -76,7 +76,7 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "uint256" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -85,11 +85,11 @@ export const repositoryAbi: Abi = [ outputs: [ { name: "semanticVersion", type: "uint16[3]" }, { name: "contractAddress", type: "address" }, - { name: "contentURI", type: "bytes" }, + { name: "contentURI", type: "bytes" } ], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -98,32 +98,32 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, inputs: [ { name: "_sender", type: "address" }, { name: "_role", type: "bytes32" }, - { name: "params", type: "uint256[]" }, + { name: "params", type: "uint256[]" } ], name: "canPerform", outputs: [{ name: "", type: "bool" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, inputs: [ { name: "_oldVersion", type: "uint16[3]" }, - { name: "_newVersion", type: "uint16[3]" }, + { name: "_newVersion", type: "uint16[3]" } ], name: "isValidBump", outputs: [{ name: "", type: "bool" }], payable: false, stateMutability: "pure", - type: "function", + type: "function" }, { constant: true, @@ -132,7 +132,7 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "bytes32" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -141,11 +141,11 @@ export const repositoryAbi: Abi = [ outputs: [ { name: "semanticVersion", type: "uint16[3]" }, { name: "contractAddress", type: "address" }, - { name: "contentURI", type: "bytes" }, + { name: "contentURI", type: "bytes" } ], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -154,7 +154,7 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "uint256" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -163,7 +163,7 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { constant: true, @@ -172,15 +172,15 @@ export const repositoryAbi: Abi = [ outputs: [{ name: "", type: "address" }], payable: false, stateMutability: "view", - type: "function", + type: "function" }, { anonymous: false, inputs: [ { indexed: false, name: "versionId", type: "uint256" }, - { indexed: false, name: "semanticVersion", type: "uint16[3]" }, + { indexed: false, name: "semanticVersion", type: "uint16[3]" } ], name: "NewVersion", - type: "event", - }, + type: "event" + } ] as const; diff --git a/packages/toolkit/src/repository/releaseSignature.ts b/packages/toolkit/src/repository/releaseSignature.ts index 48f62aafc..746038f63 100644 --- a/packages/toolkit/src/repository/releaseSignature.ts +++ b/packages/toolkit/src/repository/releaseSignature.ts @@ -9,7 +9,7 @@ import { ReleaseSignatureProtocol, ReleaseSignature, ReleaseSignatureWithData, - releaseFiles, + releaseFiles } from "@dappnode/types"; import { CID } from "kubo-rpc-client"; import { IPFSEntry } from "./types.js"; @@ -24,11 +24,7 @@ export function getReleaseSignatureStatus( } const { signature, signedData } = signatureWithData; - const signingKey = getReleaseSigningKey( - signedData, - signature.signature, - signature.signature_protocol - ); + const signingKey = getReleaseSigningKey(signedData, signature.signature, signature.signature_protocol); for (const trustedKey of trustedKeys) { if ( @@ -39,7 +35,7 @@ export function getReleaseSignatureStatus( ) { return { status: ReleaseSignatureStatusCode.signedByKnownKey, - keyName: trustedKey.name, + keyName: trustedKey.name }; } } @@ -47,7 +43,7 @@ export function getReleaseSignatureStatus( return { status: ReleaseSignatureStatusCode.signedByUnknownKey, signatureProtocol: signature.signature_protocol, - key: signingKey, + key: signingKey }; } @@ -76,10 +72,7 @@ export function getReleaseSigningKey( * docker-compose.yml zdj7Wf2pYesVyvSbcTEwWVd8TFtTjv588FET9L7qgkP47kRkf * ``` */ -export function serializeIpfsDirectory( - files: IPFSEntry[], - opts: ReleaseSignature["cid"] -): string { +export function serializeIpfsDirectory(files: IPFSEntry[], opts: ReleaseSignature["cid"]): string { return ( files .filter((file) => !releaseFiles.signature.regex.test(file.name)) @@ -87,10 +80,7 @@ export function serializeIpfsDirectory( .sort((a, b) => a.name.localeCompare(b.name)) /** `${name} ${cidStr}` */ .map((file) => { - const cidStr = cidToString( - getCidAtVersion(file.cid, opts.version), - opts.base - ); + const cidStr = cidToString(getCidAtVersion(file.cid, opts.version), opts.base); return `${file.name} ${cidStr}`; }) .join("\n") diff --git a/packages/toolkit/src/repository/repository.ts b/packages/toolkit/src/repository/repository.ts index 4248e2fd7..a57c3cf63 100644 --- a/packages/toolkit/src/repository/repository.ts +++ b/packages/toolkit/src/repository/repository.ts @@ -22,14 +22,11 @@ import { releaseFiles, Manifest, Compose, - Architecture, + Architecture } from "@dappnode/types"; import YAML from "yaml"; import { ApmRepository } from "./apmRepository.js"; -import { - getReleaseSignatureStatus, - serializeIpfsDirectory, -} from "./releaseSignature.js"; +import { getReleaseSignatureStatus, serializeIpfsDirectory } from "./releaseSignature.js"; import { isEnsDomain } from "../isEnsDomain.js"; import { dappnodeRegistry } from "./params.js"; import { ethers } from "ethers"; @@ -69,9 +66,11 @@ export class DappnodeRepository extends ApmRepository { * Pins a hash to the IPFS node. Do not throw errors. * @param hash */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any private async pinAddNoThrow(hash: any): Promise<void> { try { await this.ipfs.pin.add(hash); + // eslint-disable-next-line @typescript-eslint/no-unused-vars } catch (e) { // Do not spam the terminal // console.error(`Error pinning ${hash}`, e); @@ -97,31 +96,24 @@ export class DappnodeRepository extends ApmRepository { dnpNameOrHash: name, trustedKeys, os, - version, + version }) ) ); } - public async getManifestFromDir( - dnpName: string, - version?: string - ): Promise<Manifest> { + public async getManifestFromDir(dnpName: string, version?: string): Promise<Manifest> { const { contentUri } = await this.getVersionAndIpfsHash({ dnpNameOrHash: dnpName, - version, + version }); const ipfsEntries = await this.list(contentUri); // get manifest - const manifest = await this.getPkgAsset<Manifest>( - releaseFilesToDownload.manifest, - ipfsEntries - ); + const manifest = await this.getPkgAsset<Manifest>(releaseFilesToDownload.manifest, ipfsEntries); - if (!manifest) - throw Error(`Invalid pkg release ${contentUri}, manifest not found`); + if (!manifest) throw Error(`Invalid pkg release ${contentUri}, manifest not found`); return manifest; } @@ -135,7 +127,7 @@ export class DappnodeRepository extends ApmRepository { dnpNameOrHash, trustedKeys, os = "x64", - version, + version }: { dnpNameOrHash: string; trustedKeys: TrustedReleaseKey[]; @@ -144,10 +136,9 @@ export class DappnodeRepository extends ApmRepository { }): Promise<PackageRelease> { const { contentUri, origin } = await this.getVersionAndIpfsHash({ dnpNameOrHash, - version, + version }); - if (!isIPFS.cid(this.sanitizeIpfsPath(contentUri))) - throw Error(`Invalid IPFS hash ${contentUri}`); + if (!isIPFS.cid(this.sanitizeIpfsPath(contentUri))) throw Error(`Invalid IPFS hash ${contentUri}`); // pin hash await this.pinAddNoThrow(this.sanitizeIpfsPath(contentUri)); @@ -155,52 +146,40 @@ export class DappnodeRepository extends ApmRepository { const ipfsEntries = await this.list(contentUri); // get manifest - const manifest = await this.getPkgAsset<Manifest>( - releaseFilesToDownload.manifest, - ipfsEntries - ); + const manifest = await this.getPkgAsset<Manifest>(releaseFilesToDownload.manifest, ipfsEntries); // Ensure its a directory release - if (!manifest) - throw Error(`Invalid pkg release ${contentUri}, manifest not found`); + if (!manifest) throw Error(`Invalid pkg release ${contentUri}, manifest not found`); const dnpName = manifest.name; const isCore = manifest.type === "dncore"; // get compose - const compose = await this.getPkgAsset<Compose>( - releaseFilesToDownload.compose, + const compose = await this.getPkgAsset<Compose>(releaseFilesToDownload.compose, ipfsEntries); + if (!compose) throw Error(`Invalid pkg release ${contentUri}, compose not found`); + + const signature: ReleaseSignature | undefined = await this.getPkgAsset<ReleaseSignature>( + releaseFilesToDownload.signature, ipfsEntries ); - if (!compose) - throw Error(`Invalid pkg release ${contentUri}, compose not found`); - - const signature: ReleaseSignature | undefined = - await this.getPkgAsset<ReleaseSignature>( - releaseFilesToDownload.signature, - ipfsEntries - ); const signatureStatus: ReleaseSignatureStatus = signature ? getReleaseSignatureStatus( manifest.name, { signature, - signedData: serializeIpfsDirectory(ipfsEntries, signature.cid), + signedData: serializeIpfsDirectory(ipfsEntries, signature.cid) }, trustedKeys ) : { status: ReleaseSignatureStatusCode.notSigned }; - const signedSafe = - signatureStatus.status === ReleaseSignatureStatusCode.signedByKnownKey; + const signedSafe = signatureStatus.status === ReleaseSignatureStatusCode.signedByKnownKey; - const avatarEntry = ipfsEntries.find((file) => - releaseFiles.avatar.regex.test(file.name) - ); + const avatarEntry = ipfsEntries.find((file) => releaseFiles.avatar.regex.test(file.name)); const avatarFile: DistributedFile | undefined = avatarEntry ? { hash: avatarEntry.cid.toString(), size: avatarEntry.size, - source, + source } : undefined; @@ -213,10 +192,7 @@ export class DappnodeRepository extends ApmRepository { imageFile: this.getImageByArch(manifest, ipfsEntries, os), avatarFile, manifest, - setupWizard: await this.getPkgAsset( - releaseFilesToDownload.setupWizard, - ipfsEntries - ), + setupWizard: await this.getPkgAsset(releaseFilesToDownload.setupWizard, ipfsEntries), compose, signature, signatureStatus, @@ -224,64 +200,47 @@ export class DappnodeRepository extends ApmRepository { signedSafe, warnings: { coreFromForeignRegistry: isCore && !dnpName.endsWith(dappnodeRegistry), - requestNameMismatch: - isEnsDomain(dnpNameOrHash) && dnpNameOrHash !== dnpName, + requestNameMismatch: isEnsDomain(dnpNameOrHash) && dnpNameOrHash !== dnpName }, - disclaimer: await this.getPkgAsset( - releaseFilesToDownload.disclaimer, - ipfsEntries - ), - gettingStarted: await this.getPkgAsset( - releaseFilesToDownload.gettingStarted, - ipfsEntries - ), - prometheusTargets: await this.getPkgAsset( - releaseFilesToDownload.prometheusTargets, - ipfsEntries - ), - grafanaDashboards: await this.getPkgAsset( - releaseFilesToDownload.grafanaDashboards, - ipfsEntries - ), + disclaimer: await this.getPkgAsset(releaseFilesToDownload.disclaimer, ipfsEntries), + gettingStarted: await this.getPkgAsset(releaseFilesToDownload.gettingStarted, ipfsEntries), + prometheusTargets: await this.getPkgAsset(releaseFilesToDownload.prometheusTargets, ipfsEntries), + grafanaDashboards: await this.getPkgAsset(releaseFilesToDownload.grafanaDashboards, ipfsEntries) }; } /** - * Get a given release asset for a request. It looks for an IPFS entry for - * a given release file given a release file config. - * - * @param ipfsEntries - An array of IPFS entries. - * @param fileConfig - A file configuration. - * @throws - If the file is required and not found. - * @returns - The release package for the request or undefined if not found. - */ - public async getPkgAsset<T>( - fileConfig: FileConfig, - ipfsEntries: IPFSEntry[] - ): Promise<T | undefined> { + * Get a given release asset for a request. It looks for an IPFS entry for + * a given release file given a release file config. + * + * @param ipfsEntries - An array of IPFS entries. + * @param fileConfig - A file configuration. + * @throws - If the file is required and not found. + * @returns - The release package for the request or undefined if not found. + */ + public async getPkgAsset<T>(fileConfig: FileConfig, ipfsEntries: IPFSEntry[]): Promise<T | undefined> { const { regex, required, multiple } = fileConfig; // We filter the entries (files) so that we only consider the ones that match the regex. // for example, all grafana dashboards must pass /.*grafana-dashboard.json$/ regex - const matchingEntries = ipfsEntries.filter(file => regex.test(file.name)); - + const matchingEntries = ipfsEntries.filter((file) => regex.test(file.name)); + // Handle no matches. If the file is required, throw an error, otherwise return undefined. if (matchingEntries.length === 0) { if (required) throw new Error(`Missing required file: ${regex}`); return undefined; } - + // Process matched entries. If multiple files are allowed, and more than one file matches, we parse all of them. const { maxSize: maxLength, format } = fileConfig; - const contents = await Promise.all(matchingEntries.map(entry => - this.writeFileToMemory(entry.cid.toString(), maxLength) - )); - + const contents = await Promise.all( + matchingEntries.map((entry) => this.writeFileToMemory(entry.cid.toString(), maxLength)) + ); + // If multiple files are allowed, we return an array of parsed assets. // Otherwise, we return a single parsed asset. return this.parseAsset<T>(multiple ? contents : contents[0], format); } - - + /** * Downloads the content pointed by the given hash, parses it to UTF8 and returns it as a string. * This function is intended for small files. @@ -293,10 +252,7 @@ export class DappnodeRepository extends ApmRepository { * @see catString * @see catCarReaderToMemory */ - public async writeFileToMemory( - hash: string, - maxLength?: number - ): Promise<string> { + public async writeFileToMemory(hash: string, maxLength?: number): Promise<string> { const chunks = []; const { carReader, root } = await this.getAndVerifyContentFromGateway(hash); const content = await this.unpackCarReader(carReader, root); @@ -312,8 +268,7 @@ export class DappnodeRepository extends ApmRepository { offset += chunk.length; }); - if (maxLength && buffer.length >= maxLength) - throw Error(`Maximum size ${maxLength} bytes exceeded`); + if (maxLength && buffer.length >= maxLength) throw Error(`Maximum size ${maxLength} bytes exceeded`); // Convert the Uint8Array to a string // TODO: This assumes the data is UTF-8 encoded. If it's not, you will need a more complex conversion. Research which encoding is used by IPFS. @@ -341,7 +296,7 @@ export class DappnodeRepository extends ApmRepository { path: _path, timeout, fileSize, - progress, + progress }: { hash: string; path: string; @@ -354,21 +309,22 @@ export class DappnodeRepository extends ApmRepository { return new Promise((resolve, reject) => { async function handleDownload(): Promise<void> { - if (!_path || _path.startsWith("/ipfs/") || !path.isAbsolute("/")) - reject(Error(`Invalid path: "${path}"`)); + if (!_path || _path.startsWith("/ipfs/") || !path.isAbsolute("/")) reject(Error(`Invalid path: "${path}"`)); const asyncIterableArray: Uint8Array[] = []; // Timeout cancel mechanism - const timeoutToCancel = setTimeout(() => { - reject(Error(`Timeout downloading ${hash}`)); - }, timeout || 30 * 1000); + const timeoutToCancel = setTimeout( + () => { + reject(Error(`Timeout downloading ${hash}`)); + }, + timeout || 30 * 1000 + ); let totalData = 0; let previousProgress = -1; const resolution = 1; - const round = (n: number): number => - resolution * Math.round((100 * n) / resolution); + const round = (n: number): number => resolution * Math.round((100 * n) / resolution); const onData = (chunk: Uint8Array): void => { clearTimeout(timeoutToCancel); @@ -399,10 +355,7 @@ export class DappnodeRepository extends ApmRepository { for await (const chunk of readable) onData(chunk); const writable = fs.createWriteStream(_path); - await util.promisify(stream.pipeline)( - stream.Readable.from(asyncIterableArray), - writable - ); + await util.promisify(stream.pipeline)(stream.Readable.from(asyncIterableArray), writable); onFinish(); } catch (e) { onError("Error writing to fs")(e as Error); @@ -426,10 +379,7 @@ export class DappnodeRepository extends ApmRepository { public async list(hash: string): Promise<IPFSEntry[]> { const files: IPFSEntry[] = []; - const dagGet = await this.ipfs.dag.get( - CID.parse(this.sanitizeIpfsPath(hash)), - { timeout: this.timeout } - ); + const dagGet = await this.ipfs.dag.get(CID.parse(this.sanitizeIpfsPath(hash)), { timeout: this.timeout }); if (dagGet.value.Links) for (const link of dagGet.value.Links) files.push({ @@ -437,7 +387,7 @@ export class DappnodeRepository extends ApmRepository { cid: CID.parse(this.sanitizeIpfsPath(link.Hash.toString())), name: link.Name, path: `${link.Hash.toString()}/${link.Name}`, // Do not use module path to be browser compatible. path.join(link.Hash.toString(), link.Name), - size: link.Tsize, + size: link.Tsize }); else throw Error(`Invalid IPFS hash ${hash}`); @@ -461,8 +411,7 @@ export class DappnodeRepository extends ApmRepository { const carReader = await CarReader.fromIterable(asynciterable); const roots = await carReader.getRoots(); const root = roots[0]; - if (cid.toString() !== root.toString()) - throw Error(`UNTRUSTED CONTENT: Invalid root CID ${root} for ${cid}`); + if (cid.toString() !== root.toString()) throw Error(`UNTRUSTED CONTENT: Invalid root CID ${root} for ${cid}`); return { carReader, root }; } @@ -486,15 +435,14 @@ export class DappnodeRepository extends ApmRepository { const block = await carReader.get(cid as CID); if (!block) throw Error(`Could not get block ${cid}`); return block.bytes; - }, + } }); for await (const entry of entries) { if (entry.type === "file") iterable.push(entry.content()); else throw Error(`Expected type: file, got: ${entry.type}`); } - if (iterable.length > 1) - throw Error(`Unexpected number of files. There must be only one`); + if (iterable.length > 1) throw Error(`Unexpected number of files. There must be only one`); return iterable[0]; } @@ -508,11 +456,7 @@ export class DappnodeRepository extends ApmRepository { * @param nodeArch - The architecture of the node. * @returns The distributed file object of the image. */ - private getImageByArch( - manifest: Manifest, - files: IPFSEntry[], - nodeArch: NodeJS.Architecture - ): DistributedFile { + private getImageByArch(manifest: Manifest, files: IPFSEntry[], nodeArch: NodeJS.Architecture): DistributedFile { let arch: Architecture; switch (nodeArch) { case "arm": @@ -529,15 +473,11 @@ export class DappnodeRepository extends ApmRepository { const { name, version } = manifest; const imageAsset = - files.find( - (file) => file.name === this.getImageName(name, version, arch) - ) || + files.find((file) => file.name === this.getImageName(name, version, arch)) || (arch === defaultArch ? // New DAppNodes should load old single arch packages, // and consider their single image as amd64 - files.find( - (file) => file.name === this.getLegacyImageName(name, version) - ) + files.find((file) => file.name === this.getLegacyImageName(name, version)) : undefined); if (!imageAsset) { @@ -552,7 +492,7 @@ export class DappnodeRepository extends ApmRepository { return { hash: imageAsset.cid.toString(), size: imageAsset.size, - source, // TODO: consdier adding different sources + source // TODO: consdier adding different sources }; } } @@ -594,7 +534,7 @@ export class DappnodeRepository extends ApmRepository { return parseSingle(input); } }; - + try { const parsedData = parseContent(data); return parsedData as T; @@ -603,8 +543,6 @@ export class DappnodeRepository extends ApmRepository { } } - - /** * Sanitizes an IPFS path by removing "/ipfs/" if it is present. * @@ -622,8 +560,7 @@ export class DappnodeRepository extends ApmRepository { * @param version Container version * @returns Legacy image path in the format <name>_<version>.tar.xz */ - private getLegacyImageName = (name: string, version: string): string => - `${name}_${version}.tar.xz`; + private getLegacyImageName = (name: string, version: string): string => `${name}_${version}.tar.xz`; /** * Returns the image path for the given container name, version and architecture @@ -632,11 +569,8 @@ export class DappnodeRepository extends ApmRepository { * @param arch Container architecture in the format <os>/<arch> * @returns Image path in the format <name>_<version>_<os>-<arch>.txz */ - private getImageName = ( - name: string, - version: string, - arch: Architecture - ): string => `${name}_${version}_${this.getArchTag(arch)}.txz`; + private getImageName = (name: string, version: string, arch: Architecture): string => + `${name}_${version}_${this.getArchTag(arch)}.txz`; /** * Returns the arch tag for the given architecture diff --git a/packages/toolkit/src/repository/types.ts b/packages/toolkit/src/repository/types.ts index 0ff5a0bb0..1cd1e8334 100644 --- a/packages/toolkit/src/repository/types.ts +++ b/packages/toolkit/src/repository/types.ts @@ -1,4 +1,4 @@ -import { CID } from "kubo-rpc-client"; +import type { CID } from "kubo-rpc-client"; /** * IPFS @@ -13,6 +13,7 @@ export interface IPFSEntry { readonly name: string; readonly path: string; mode?: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any mtime?: any; size: number; } diff --git a/packages/toolkit/test/directory/directory.test.ts b/packages/toolkit/test/directory/directory.test.ts index 741671e69..b18fb152d 100644 --- a/packages/toolkit/test/directory/directory.test.ts +++ b/packages/toolkit/test/directory/directory.test.ts @@ -4,9 +4,7 @@ import { expect } from "chai"; describe.skip("Dappnode Directory", function () { this.timeout(100000); - const contract = new DappNodeDirectory( - new ethers.InfuraProvider("mainnet", process.env.INFURA_MAINNET_KEY) - ); + const contract = new DappNodeDirectory(new ethers.InfuraProvider("mainnet", process.env.INFURA_MAINNET_KEY)); it(`should get directory pkgs`, async () => { // const expectedResult = [ diff --git a/packages/toolkit/test/repository/repository.test.ts b/packages/toolkit/test/repository/repository.test.ts index fc33ca7ac..a4a88b347 100644 --- a/packages/toolkit/test/repository/repository.test.ts +++ b/packages/toolkit/test/repository/repository.test.ts @@ -10,7 +10,7 @@ import { ethers } from "ethers"; describe.skip("Dappnode Repository", function () { const ipfsUrls = [ //"https://api.ipfs.dappnode.io", - "https://gateway.ipfs.dappnode.io", + "https://gateway.ipfs.dappnode.io" ]; const prysmDnpName = "prysm.dnp.dappnode.eth"; @@ -19,7 +19,7 @@ describe.skip("Dappnode Repository", function () { name: "DAppNode Association", signatureProtocol: "ECDSA_256", dnpNameSuffix: ".dnp.dappnode.eth", - key: "0xF35960302a07022aBa880DFFaEC2Fdd64d5BF1c1", + key: "0xF35960302a07022aBa880DFFaEC2Fdd64d5BF1c1" }; before(() => { @@ -36,11 +36,11 @@ describe.skip("Dappnode Repository", function () { it(`[${ipfsUrl}] Should get and validate package version for Prysm:${prysmVersion}`, async () => { const expectedVersionAndIpfsHash = { version: "3.0.8", - contentUri: "/ipfs/QmZrZeQwMBBfSb6FQUcKdnB9epGmUzqarmkw2RbwTVQgbZ", + contentUri: "/ipfs/QmZrZeQwMBBfSb6FQUcKdnB9epGmUzqarmkw2RbwTVQgbZ" }; const result = await contract.getVersionAndIpfsHash({ dnpNameOrHash: prysmDnpName, - version: prysmVersion, + version: prysmVersion }); expect(result).to.deep.equal(expectedVersionAndIpfsHash); }); @@ -49,12 +49,12 @@ describe.skip("Dappnode Repository", function () { const expectedImageFile = { hash: "QmWcJrobqhHF7GWpqEbxdv2cWCCXbACmq85Hh7aJ1eu8rn", size: 64461521, - source: "ipfs", + source: "ipfs" }; const expectedAvatarFile = { hash: "QmeZBTEAf3bXJreBECaMhHa53bhCPqvSwVng8q1UnPoL4L", size: 4303, - source: "ipfs", + source: "ipfs" }; const expectedManifest = { name: "prysm.dnp.dappnode.eth", @@ -70,56 +70,53 @@ describe.skip("Dappnode Repository", function () { type: "service", architectures: ["linux/amd64"], mainService: "validator", - author: - "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", - contributors: [ - "dappLion <dapplion@dappnode.io> (https://github.com/dapplion)", - ], + author: "DAppNode Association <admin@dappnode.io> (https://github.com/dappnode)", + contributors: ["dappLion <dapplion@dappnode.io> (https://github.com/dapplion)"], chain: { driver: "ethereum-beacon-chain", serviceName: "beacon-chain", - portNumber: 3500, + portNumber: 3500 }, license: "GPL-3.0", repository: { type: "git", - url: "git+https://github.com/dappnode/DAppNodePackage-prysm.git", + url: "git+https://github.com/dappnode/DAppNodePackage-prysm.git" }, bugs: { - url: "https://github.com/dappnode/DAppNodePackage-prysm/issues", + url: "https://github.com/dappnode/DAppNodePackage-prysm/issues" }, requirements: { minimumDappnodeVersion: "0.2.60" }, backup: [ { name: "eth2validators", path: "/root/.eth2validators", - service: "validator", - }, + service: "validator" + } ], categories: ["Blockchain", "ETH2.0"], style: { featuredBackground: "linear-gradient(67deg, #16000c, #123939)", - featuredColor: "white", + featuredColor: "white" }, links: { ui: "http://brain.web3signer.dappnode", homepage: "https://prysmaticlabs.com/", readme: "https://github.com/dappnode/DAppNodePackage-prysm", - docs: "https://docs.prylabs.network/docs/getting-started", + docs: "https://docs.prylabs.network/docs/getting-started" }, warnings: { onMajorUpdate: "This is a major update that enables multiclient validation on Mainnet.⚠️ BEFORE YOU START, MAKE SURE YOU HAVE A BACKUP OF THE VALIDATOR KEYS⚠️ . A new package, the web3signer, will be automatically installed and keys will be moved inside of this package. The web3signer will hold the keys and allow you to change validator clients safely. From now on, the UI to handle the keystores will be available at the web3signer package. You will be prompted to choose a validator client in the following steps; make sure you select one that is installed and synced (leave it as Prysm if you are not sure, you can change it later). Pay attention to the update and make sure the keystores are successfully relocated by checking the UI of the web3signer after the update.", onRemove: - "Make sure your StakersUI does not have this client selected! Double check in the Stakers Tab in the left NavBar", + "Make sure your StakersUI does not have this client selected! Double check in the Stakers Tab in the left NavBar" }, globalEnvs: [ { envs: ["EXECUTION_CLIENT_MAINNET", "MEVBOOST_MAINNET"], - services: ["beacon-chain"], + services: ["beacon-chain"] }, - { envs: ["MEVBOOST_MAINNET"], services: ["validator"] }, - ], + { envs: ["MEVBOOST_MAINNET"], services: ["validator"] } + ] }; const expectedCompose = { version: "3.4", @@ -131,12 +128,12 @@ describe.skip("Dappnode Repository", function () { EXTRA_OPTS: "", FEE_RECIPIENT_ADDRESS: "", P2P_TCP_PORT: 13103, - P2P_UDP_PORT: 12103, + P2P_UDP_PORT: 12103 }, image: "beacon-chain.prysm.dnp.dappnode.eth:3.0.8", ports: ["13103:13103/tcp", "12103:12103/udp"], restart: "unless-stopped", - volumes: ["beacon-chain-data:/data"], + volumes: ["beacon-chain-data:/data"] }, validator: { environment: { @@ -145,14 +142,14 @@ describe.skip("Dappnode Repository", function () { EXTRA_OPTS: "", FEE_RECIPIENT_ADDRESS: "", GRAFFITI: "validating_from_DAppNode", - LOG_TYPE: "INFO", + LOG_TYPE: "INFO" }, image: "validator.prysm.dnp.dappnode.eth:3.0.8", restart: "unless-stopped", - volumes: ["validator-data:/root/"], - }, + volumes: ["validator-data:/root/"] + } }, - volumes: { "beacon-chain-data": {}, "validator-data": {} }, + volumes: { "beacon-chain-data": {}, "validator-data": {} } }; const expectedSignature = { @@ -160,14 +157,14 @@ describe.skip("Dappnode Repository", function () { cid: { version: 0, base: "base58btc" }, signature_protocol: "ECDSA_256", signature: - "0x05df9a6449ac5fcbcaf98ee50cb5d40b08b797063058ee22dea5eff6fe493ef15a927f81132a80a94f43b5b35fe73662d4cbc2bc371c97a77683df3a0565fa821c", + "0x05df9a6449ac5fcbcaf98ee50cb5d40b08b797063058ee22dea5eff6fe493ef15a927f81132a80a94f43b5b35fe73662d4cbc2bc371c97a77683df3a0565fa821c" }; const pkgRelease = await contract.getPkgRelease({ dnpNameOrHash: prysmDnpName, trustedKeys: [dappnodeTrustedKey], version: prysmVersion, - os: "x64", + os: "x64" }); console.log(pkgRelease.signedSafe); @@ -181,10 +178,7 @@ describe.skip("Dappnode Repository", function () { // expected to be signed expect(pkgRelease.signedSafe).to.be.true; // expected to be signed by a known key - expect( - pkgRelease.signatureStatus.status === - ReleaseSignatureStatusCode.signedByKnownKey - ); + expect(pkgRelease.signatureStatus.status === ReleaseSignatureStatusCode.signedByKnownKey); }); it(`[${ipfsUrl}] Should get multiple pkgs releases: `, async () => { @@ -193,7 +187,7 @@ describe.skip("Dappnode Repository", function () { [prysmDnpName]: prysmVersion, "lodestar.dnp.dappnode.eth": "0.1.0", "geth.dnp.dappnode.eth": "0.1.40", - "swarm.public.dappnode.eth": "1.0.17", + "swarm.public.dappnode.eth": "1.0.17" }, [dappnodeTrustedKey], "x64" @@ -202,19 +196,18 @@ describe.skip("Dappnode Repository", function () { }); it(`[${ipfsUrl}] Should write avatar file to filesystem and verify its hash`, async () => { - const expectedHash = - "c69e3bdc66446d32c1ed91f3d2e5a4e56ccde571668c85e15a23ef3613c31cb8"; + const expectedHash = "c69e3bdc66446d32c1ed91f3d2e5a4e56ccde571668c85e15a23ef3613c31cb8"; const avatarFileName = "avatar.png"; const avatarFileExample = { hash: "QmeZBTEAf3bXJreBECaMhHa53bhCPqvSwVng8q1UnPoL4L", size: 4303, - source: "ipfs", + source: "ipfs" }; await contract.writeFileToFs({ hash: avatarFileExample.hash, path: path.join(testDir, avatarFileName), - fileSize: avatarFileExample.size, + fileSize: avatarFileExample.size }); const buffer = fs.readFileSync(path.join(testDir, avatarFileName)); @@ -223,20 +216,18 @@ describe.skip("Dappnode Repository", function () { }); it(`[${ipfsUrl}] Should write docker image file to filesystem and verify its hash`, async () => { - const expectedHash = - "1f838c82a415bf82fa98171206f25827dd4cb93234bbf24b58969cd6ef2df159"; - const dockerImageFileName = - "prysm.dnp.dappnode.eth_3.0.8_linux-amd64.txz"; + const expectedHash = "1f838c82a415bf82fa98171206f25827dd4cb93234bbf24b58969cd6ef2df159"; + const dockerImageFileName = "prysm.dnp.dappnode.eth_3.0.8_linux-amd64.txz"; const dockerImageFileExample = { hash: "QmWcJrobqhHF7GWpqEbxdv2cWCCXbACmq85Hh7aJ1eu8rn", size: 64461521, - source: "ipfs", + source: "ipfs" }; await contract.writeFileToFs({ hash: dockerImageFileExample.hash, path: path.join(testDir, dockerImageFileName), - fileSize: dockerImageFileExample.size, + fileSize: dockerImageFileExample.size }); const buffer = fs.readFileSync(path.join(testDir, dockerImageFileName)); diff --git a/packages/toolkit/test/repository/signedRelease.test.ts b/packages/toolkit/test/repository/signedRelease.test.ts index e8068f08c..1ec643360 100644 --- a/packages/toolkit/test/repository/signedRelease.test.ts +++ b/packages/toolkit/test/repository/signedRelease.test.ts @@ -2,51 +2,44 @@ import "mocha"; import { CID } from "kubo-rpc-client"; import { ethers } from "ethers"; import { expect } from "chai"; -import { - ReleaseSignature, - ReleaseSignatureStatusCode, - TrustedReleaseKey, -} from "@dappnode/types"; +import { ReleaseSignature, ReleaseSignatureStatusCode, TrustedReleaseKey } from "@dappnode/types"; import { IPFSEntry } from "../../src/repository/types.js"; -import { - serializeIpfsDirectory, - getReleaseSignatureStatus, -} from "../../src/repository/releaseSignature.js"; +import { serializeIpfsDirectory, getReleaseSignatureStatus } from "../../src/repository/releaseSignature.js"; describe("modules / release / verifyReleaseSignature", () => { const files: IPFSEntry[] = [ { name: "avatar.png", - hash: "QmfTpBLzoSdrG88ETRnDus27DTDRUrTXyyVmhXDuMNYVaN", + hash: "QmfTpBLzoSdrG88ETRnDus27DTDRUrTXyyVmhXDuMNYVaN" }, { name: "dappmanager.dnp.dappnode.eth_0.2.43.tar.xz", - hash: "QmbaLry6tVScoBXgcSHmdH7fGrFKdhfxWSDGiWMDUUaP8U", + hash: "QmbaLry6tVScoBXgcSHmdH7fGrFKdhfxWSDGiWMDUUaP8U" }, { name: "dappmanager.dnp.dappnode.eth_0.2.43_linux-amd64.txz", - hash: "QmbaLry6tVScoBXgcSHmdH7fGrFKdhfxWSDGiWMDUUaP8U", + hash: "QmbaLry6tVScoBXgcSHmdH7fGrFKdhfxWSDGiWMDUUaP8U" }, { name: "dappmanager.dnp.dappnode.eth_0.2.43_linux-arm64.txz", - hash: "QmaGWq3zhwpoGQhg78c1H8nLUeEv892i5pFndpPvwz8GuM", + hash: "QmaGWq3zhwpoGQhg78c1H8nLUeEv892i5pFndpPvwz8GuM" }, { name: "dappnode_package.json", - hash: "QmUPXWJ29dm5Rifwn6SD7w8J6LUKUQmf9bHeFFNB1fB9KN", + hash: "QmUPXWJ29dm5Rifwn6SD7w8J6LUKUQmf9bHeFFNB1fB9KN" }, { name: "signature.json", - hash: "QmaonPyyb1N74GiPJLUjQ7E6sepmSSRi5VgSaZnn3YP16x", - }, + hash: "QmaonPyyb1N74GiPJLUjQ7E6sepmSSRi5VgSaZnn3YP16x" + } ].map((file) => ({ name: file.name, path: "QmRhdmquYoiMR5GB2dKqhLipMzdFUeyZ2eSVvTLDvndTvh/-----------", size: 1000, - // eslint-disable-next-line @typescript-eslint/no-explicit-any + cid: CID.parse(file.hash), type: "file", - depth: 1, + depth: 1 })); it("serialize ipfs directory v0 base58btc", () => { @@ -58,7 +51,7 @@ dappnode_package.json QmUPXWJ29dm5Rifwn6SD7w8J6LUKUQmf9bHeFFNB1fB9KN`; const serialized = serializeIpfsDirectory(files, { version: 0, - base: "base58btc", + base: "base58btc" }); expect(serialized).to.equal(serializedExpected); }); @@ -72,7 +65,7 @@ dappnode_package.json bafybeicz4k4adz7g6ketn6ogv2ot7hvklfgv6ovtjrzq24ez7urphanmh const serialized = serializeIpfsDirectory(files, { version: 1, - base: "base32", + base: "base32" }); expect(serialized).to.equal(serializedExpected); }); @@ -81,8 +74,7 @@ dappnode_package.json bafybeicz4k4adz7g6ketn6ogv2ot7hvklfgv6ovtjrzq24ez7urphanmh const cidOpts: ReleaseSignature["cid"] = { version: 0, base: "base58btc" }; const signedData = serializeIpfsDirectory(files, cidOpts); - const privateKey = - "0x0123456789012345678901234567890123456789012345678901234567890123"; + const privateKey = "0x0123456789012345678901234567890123456789012345678901234567890123"; const wallet = new ethers.Wallet(privateKey); // Sign the string message @@ -93,7 +85,7 @@ dappnode_package.json bafybeicz4k4adz7g6ketn6ogv2ot7hvklfgv6ovtjrzq24ez7urphanmh version: 1, cid: cidOpts, signature_protocol: "ECDSA_256", - signature: flatSig, + signature: flatSig }; const dnpName = "dappmanager.dnp.dappnode.eth"; @@ -102,18 +94,14 @@ dappnode_package.json bafybeicz4k4adz7g6ketn6ogv2ot7hvklfgv6ovtjrzq24ez7urphanmh name: "DAppNode association", signatureProtocol: "ECDSA_256", dnpNameSuffix: ".dnp.dappnode.eth", - key: wallet.address, + key: wallet.address }; - const signatureStatus = getReleaseSignatureStatus( - dnpName, - { signature, signedData }, - [trustedKey] - ); + const signatureStatus = getReleaseSignatureStatus(dnpName, { signature, signedData }, [trustedKey]); expect(signatureStatus).to.deep.equal({ status: ReleaseSignatureStatusCode.signedByKnownKey, - keyName: trustedKey.name, + keyName: trustedKey.name }); }); }); diff --git a/packages/toolkit/test/testUtils.ts b/packages/toolkit/test/testUtils.ts index c5fe0409c..d935d0277 100644 --- a/packages/toolkit/test/testUtils.ts +++ b/packages/toolkit/test/testUtils.ts @@ -2,10 +2,7 @@ import { join, dirname } from "path"; import { fileURLToPath } from "url"; import fs from "fs"; -export const testDir = join( - dirname(fileURLToPath(import.meta.url)), - "test_files" -); +export const testDir = join(dirname(fileURLToPath(import.meta.url)), "test_files"); export function cleanTestDir() { if (fs.existsSync(testDir)) fs.rmdirSync(testDir, { recursive: true }); diff --git a/packages/toolkit/theGraph/dappnode-registry/src/registry.ts b/packages/toolkit/theGraph/dappnode-registry/src/registry.ts index 8dbe8965e..214304fab 100644 --- a/packages/toolkit/theGraph/dappnode-registry/src/registry.ts +++ b/packages/toolkit/theGraph/dappnode-registry/src/registry.ts @@ -1,33 +1,26 @@ -import { - NewRepo as NewRepoEvent, - NewAppProxy as NewAppProxyEvent -} from "../generated/Registry/Registry" -import { NewRepo, NewAppProxy } from "../generated/schema" +import { NewRepo as NewRepoEvent, NewAppProxy as NewAppProxyEvent } from "../generated/Registry/Registry"; +import { NewRepo, NewAppProxy } from "../generated/schema"; export function handleNewRepo(event: NewRepoEvent): void { - let entity = new NewRepo( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.Registry_id = event.params.id - entity.name = event.params.name - entity.repo = event.params.repo + const entity = new NewRepo(event.transaction.hash.concatI32(event.logIndex.toI32())); + entity.Registry_id = event.params.id; + entity.name = event.params.name; + entity.repo = event.params.repo; - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash + entity.blockNumber = event.block.number; + entity.blockTimestamp = event.block.timestamp; + entity.transactionHash = event.transaction.hash; - entity.save() + entity.save(); } export function handleNewAppProxy(event: NewAppProxyEvent): void { - let entity = new NewAppProxy( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.proxy = event.params.proxy + const entity = new NewAppProxy(event.transaction.hash.concatI32(event.logIndex.toI32())); + entity.proxy = event.params.proxy; - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash + entity.blockNumber = event.block.number; + entity.blockTimestamp = event.block.timestamp; + entity.transactionHash = event.transaction.hash; - entity.save() + entity.save(); } diff --git a/packages/toolkit/theGraph/public-registry/src/registry-public.ts b/packages/toolkit/theGraph/public-registry/src/registry-public.ts index c3a434d9c..382507875 100644 --- a/packages/toolkit/theGraph/public-registry/src/registry-public.ts +++ b/packages/toolkit/theGraph/public-registry/src/registry-public.ts @@ -1,33 +1,26 @@ -import { - NewRepo as NewRepoEvent, - NewAppProxy as NewAppProxyEvent -} from "../generated/RegistryPublic/RegistryPublic" -import { NewRepo, NewAppProxy } from "../generated/schema" +import { NewRepo as NewRepoEvent, NewAppProxy as NewAppProxyEvent } from "../generated/RegistryPublic/RegistryPublic"; +import { NewRepo, NewAppProxy } from "../generated/schema"; export function handleNewRepo(event: NewRepoEvent): void { - let entity = new NewRepo( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.RegistryPublic_id = event.params.id - entity.name = event.params.name - entity.repo = event.params.repo + const entity = new NewRepo(event.transaction.hash.concatI32(event.logIndex.toI32())); + entity.RegistryPublic_id = event.params.id; + entity.name = event.params.name; + entity.repo = event.params.repo; - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash + entity.blockNumber = event.block.number; + entity.blockTimestamp = event.block.timestamp; + entity.transactionHash = event.transaction.hash; - entity.save() + entity.save(); } export function handleNewAppProxy(event: NewAppProxyEvent): void { - let entity = new NewAppProxy( - event.transaction.hash.concatI32(event.logIndex.toI32()) - ) - entity.proxy = event.params.proxy + const entity = new NewAppProxy(event.transaction.hash.concatI32(event.logIndex.toI32())); + entity.proxy = event.params.proxy; - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash + entity.blockNumber = event.block.number; + entity.blockTimestamp = event.block.timestamp; + entity.transactionHash = event.transaction.hash; - entity.save() + entity.save(); } diff --git a/packages/types/.eslintignore b/packages/types/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/types/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/types/.eslintrc.cjs b/packages/types/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/types/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/types/package.json b/packages/types/package.json index f1bef8b86..51c655c5e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -14,8 +14,7 @@ }, "scripts": { "build": "tsc -p tsconfig.json", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "devDependencies": { "@types/node": "^20.14.10" diff --git a/packages/types/src/calls.ts b/packages/types/src/calls.ts index b02e5db96..32254d41d 100644 --- a/packages/types/src/calls.ts +++ b/packages/types/src/calls.ts @@ -1,12 +1,6 @@ import { ContainerState } from "./pkg.js"; import { ComposeNetworks, ComposeServiceNetworks, PackageEnvs } from "./compose.js"; -import { - Manifest, - Dependencies, - ChainDriver, - PackageBackup, - ManifestUpdateAlert, -} from "./manifest.js"; +import { Manifest, Dependencies, ChainDriver, PackageBackup, ManifestUpdateAlert } from "./manifest.js"; import { SetupWizard } from "./setupWizard.js"; /** @@ -132,13 +126,9 @@ export type ShhStatus = "enabled" | "disabled"; * ======= */ -export type VpnDeviceAdminPassword = - | { hasChangedPassword: true } - | { hasChangedPassword: false; password: string }; +export type VpnDeviceAdminPassword = { hasChangedPassword: true } | { hasChangedPassword: false; password: string }; -export type VpnDevice = - | { id: string; admin: false } - | ({ id: string; admin: true } & VpnDeviceAdminPassword); +export type VpnDevice = { id: string; admin: false } | ({ id: string; admin: true } & VpnDeviceAdminPassword); export type VpnDeviceCredentials = VpnDevice & { url: string; @@ -250,8 +240,8 @@ export interface UserSettings { // For keeping staker network in case client is selected networks?: { rootNetworks: ComposeNetworks; - serviceNetworks: { [serviceName: string]: ComposeServiceNetworks; } - } + serviceNetworks: { [serviceName: string]: ComposeServiceNetworks }; + }; domainAlias?: string[]; // ["fullnode", "my-custom-name"] // ### DEPRECATED Kept for legacy compatibility @@ -333,7 +323,7 @@ export interface SetupWizardAllDnps { export enum PortProtocol { UDP = "UDP", - TCP = "TCP", + TCP = "TCP" } export interface UpnpPortMapping { @@ -787,9 +777,7 @@ export interface CoreUpdateDataAvailable { versionId: string; coreVersion: string; } -export type CoreUpdateData = - | CoreUpdateDataNotAvailable - | CoreUpdateDataAvailable; +export type CoreUpdateData = CoreUpdateDataNotAvailable | CoreUpdateDataAvailable; /** * Releases types @@ -855,11 +843,7 @@ export interface AvahiDaemonStatus { avahiResolves: boolean; } -export type LocalProxyingStatus = - | "running" - | "stopped" - | "crashed" - | "https missing"; +export type LocalProxyingStatus = "running" | "stopped" | "crashed" | "https missing"; /** * Aggregated DAppNode system info @@ -952,7 +936,7 @@ export interface IpfsRepository { export enum IpfsClientTarget { local = "local", - remote = "remote", + remote = "remote" } /** @@ -1035,9 +1019,9 @@ export type EthClientSyncedNotificationStatus = { export type Eth2ClientTarget = | { - execClient: string; - consClient: string; - } + execClient: string; + consClient: string; + } | "remote"; /** @@ -1047,7 +1031,7 @@ export type EthClientFallback = "on" | "off"; export enum EthClientRemote { on = "on", - off = "off", + off = "off" } export type EthClientStatus = EthClientStatusOk | EthClientStatusError; diff --git a/packages/types/src/compose.ts b/packages/types/src/compose.ts index 5435910e8..c0456dbe3 100644 --- a/packages/types/src/compose.ts +++ b/packages/types/src/compose.ts @@ -6,9 +6,7 @@ export interface ComposeInspectVolumes { // NOT allowed to user, only used by DAppNode internally (if any) name?: string; // Volumes can only be declared locally or be external driver?: string; // Dangerous - driver_opts?: - | { type: "none"; device: string; o: "bind" } - | { [driverOptName: string]: string }; // driver_opts are passed down to whatever driver is being used, there's. No verification on docker's part nor detailed documentation + driver_opts?: { type: "none"; device: string; o: "bind" } | { [driverOptName: string]: string }; // driver_opts are passed down to whatever driver is being used, there's. No verification on docker's part nor detailed documentation labels?: { [labelName: string]: string }; // User should not use this feature }; } @@ -147,9 +145,7 @@ export interface ComposeVolume { external?: boolean; name?: string; // Volumes can only be declared locally or be external driver?: string; // Dangerous - driver_opts?: - | { type: "none"; device: string; o: "bind" } - | { [driverOptName: string]: string }; // driver_opts are passed down to whatever driver is being used, there's. No verification on docker's part nor detailed documentation + driver_opts?: { type: "none"; device: string; o: "bind" } | { [driverOptName: string]: string }; // driver_opts are passed down to whatever driver is being used, there's. No verification on docker's part nor detailed documentation labels?: { [labelName: string]: string }; // User should not use this feature } @@ -192,5 +188,5 @@ export const dockerComposeSafeKeys: (keyof ComposeService)[] = [ "container_name", "dns", "ulimits", - "deploy", + "deploy" ]; diff --git a/packages/types/src/globalEnvs.ts b/packages/types/src/globalEnvs.ts index 462422cb7..3455dda2e 100644 --- a/packages/types/src/globalEnvs.ts +++ b/packages/types/src/globalEnvs.ts @@ -25,7 +25,7 @@ export const GLOBAL_ENVS = { MEVBOOST_LUKSO: "_DAPPNODE_GLOBAL_MEVBOOST_LUKSO", // "mevboost-lukso.dnp.dappnode.eth" CONSENSUS_CLIENT_HOLESKY: "_DAPPNODE_GLOBAL_CONSENSUS_CLIENT_HOLESKY", // "prysm-holesky.dnp.dappnode.eth" EXECUTION_CLIENT_HOLESKY: "_DAPPNODE_GLOBAL_EXECUTION_CLIENT_HOLESKY", // "geth.dnp.dappnode.eth" - MEVBOOST_HOLESKY: "_DAPPNODE_GLOBAL_MEVBOOST_HOLESKY", // "mevboost-holesky.dnp.dappnode.eth" + MEVBOOST_HOLESKY: "_DAPPNODE_GLOBAL_MEVBOOST_HOLESKY" // "mevboost-holesky.dnp.dappnode.eth" }; /** diff --git a/packages/types/src/manifest.ts b/packages/types/src/manifest.ts index 6b266457d..f81ed8acd 100644 --- a/packages/types/src/manifest.ts +++ b/packages/types/src/manifest.ts @@ -1,9 +1,4 @@ -import { - SetupSchema, - SetupTarget, - SetupUiJson, - SetupWizard, -} from "./setupWizard.js"; +import { SetupSchema, SetupTarget, SetupUiJson, SetupWizard } from "./setupWizard.js"; export interface Manifest { // Package metadata @@ -157,7 +152,7 @@ export const chainDriversTypes = [ "ethereum", "ethereum-beacon-chain", "ethereum2-beacon-chain-prysm", - "monero", + "monero" ] as const; // HTTPS ports diff --git a/packages/types/src/pkg.ts b/packages/types/src/pkg.ts index e90130ddc..dd74b2916 100644 --- a/packages/types/src/pkg.ts +++ b/packages/types/src/pkg.ts @@ -115,7 +115,7 @@ export interface ReleasePkgAssets extends DirectoryFiles { export enum FileFormat { JSON = "JSON", YAML = "YAML", - TEXT = "TEXT", + TEXT = "TEXT" } /** @@ -145,7 +145,7 @@ export interface ReleaseSignature { export enum ReleaseSignatureStatusCode { notSigned = "notSigned", signedByKnownKey = "signedByKnownKey", - signedByUnknownKey = "signedByUnknownKey", + signedByUnknownKey = "signedByUnknownKey" } export type ReleaseSignatureStatus = @@ -165,9 +165,7 @@ export type ReleaseSignatureWithData = { /** TODO: Add RSA_2048, OpenPGP */ export type ReleaseSignatureProtocol = "ECDSA_256"; // NOTE: Must list all available protocols to be shown in the UI select component -export const releaseSignatureProtocols: ReleaseSignatureProtocol[] = [ - "ECDSA_256", -]; +export const releaseSignatureProtocols: ReleaseSignatureProtocol[] = ["ECDSA_256"]; export interface TrustedReleaseKey { /** Metadata name to identify this key: `DAppnode association` */ diff --git a/packages/types/src/releaseFiles.ts b/packages/types/src/releaseFiles.ts index 8f1efdfff..2c4d6df4b 100644 --- a/packages/types/src/releaseFiles.ts +++ b/packages/types/src/releaseFiles.ts @@ -6,85 +6,85 @@ export const releaseFiles = Object.freeze({ format: FileFormat.YAML, maxSize: 100e3, // Limit size to ~100KB required: true as const, - multiple: false as const, + multiple: false as const }), compose: Object.freeze({ regex: /compose.*\.yml$/, format: FileFormat.YAML, maxSize: 10e3, // Limit size to ~10KB required: true as const, - multiple: false as const, + multiple: false as const }), signature: Object.freeze({ regex: /^signature\.json$/, format: FileFormat.JSON, maxSize: 10e3, // Limit size to ~10KB required: false as const, - multiple: false as const, + multiple: false as const }), avatar: Object.freeze({ regex: /avatar.*\.png$/, format: null, maxSize: 100e3, required: true as const, - multiple: false as const, + multiple: false as const }), setupWizard: Object.freeze({ regex: /setup-wizard\..*(json|yaml|yml)$/, format: FileFormat.YAML, maxSize: 100e3, required: false as const, - multiple: false as const, + multiple: false as const }), setupSchema: Object.freeze({ regex: /setup\..*\.json$/, format: FileFormat.JSON, maxSize: 10e3, required: false as const, - multiple: false as const, + multiple: false as const }), setupTarget: Object.freeze({ regex: /setup-target\..*json$/, format: FileFormat.JSON, maxSize: 10e3, required: false as const, - multiple: false as const, + multiple: false as const }), setupUiJson: Object.freeze({ regex: /setup-ui\..*json$/, format: FileFormat.JSON, maxSize: 10e3, required: false as const, - multiple: false as const, + multiple: false as const }), disclaimer: Object.freeze({ regex: /disclaimer\.md$/i, format: FileFormat.TEXT, maxSize: 100e3, required: false as const, - multiple: false as const, + multiple: false as const }), gettingStarted: Object.freeze({ regex: /getting.*started\.md$/i, format: FileFormat.TEXT, maxSize: 100e3, required: false as const, - multiple: false as const, + multiple: false as const }), prometheusTargets: Object.freeze({ regex: /.*prometheus-targets.(json|yaml|yml)$/, format: FileFormat.YAML, maxSize: 10e3, required: false as const, - multiple: false as const, + multiple: false as const }), grafanaDashboards: Object.freeze({ regex: /.*grafana-dashboard.json$/, format: FileFormat.JSON, maxSize: 10e6, // ~ 10MB required: false as const, - multiple: true as const, - }), + multiple: true as const + }) } as const); export const releaseFilesToDownload = { @@ -95,5 +95,5 @@ export const releaseFilesToDownload = { disclaimer: releaseFiles.disclaimer, gettingStarted: releaseFiles.gettingStarted, prometheusTargets: releaseFiles.prometheusTargets, - grafanaDashboards: releaseFiles.grafanaDashboards, + grafanaDashboards: releaseFiles.grafanaDashboards }; diff --git a/packages/types/src/rollups.ts b/packages/types/src/rollups.ts index 07613b0e7..09e38a00c 100644 --- a/packages/types/src/rollups.ts +++ b/packages/types/src/rollups.ts @@ -4,9 +4,9 @@ import { PackageItemData } from "./stakers.js"; export const executionClientsOptimism = Object.freeze([ "op-geth.dnp.dappnode.eth", - "op-erigon.dnp.dappnode.eth", + "op-erigon.dnp.dappnode.eth" ] as const); -export type ExecutionClientOptimism = typeof executionClientsOptimism[number]; +export type ExecutionClientOptimism = (typeof executionClientsOptimism)[number]; export type OptimismNode = "op-node.dnp.dappnode.eth"; export const optimismNode: OptimismNode = "op-node.dnp.dappnode.eth"; @@ -15,9 +15,7 @@ export type OptimismL2Geth = "op-l2geth.dnp.dappnode.eth"; export const optimismL2Geth: OptimismL2Geth = "op-l2geth.dnp.dappnode.eth"; export type OptimismType = "archive" | "execution" | "rollup"; -export type OptimismItem<T extends OptimismType> = - | OptimismItemOk<T> - | OptimismItemError<T>; +export type OptimismItem<T extends OptimismType> = OptimismItemOk<T> | OptimismItemError<T>; interface OptimismArchive { dnpName: OptimismL2Geth; } @@ -32,10 +30,10 @@ interface OptimismRollup { type OptimismItemBasic<T extends OptimismType> = T extends "archive" ? OptimismArchive : T extends "execution" - ? OptimismExecution - : T extends "rollup" - ? OptimismRollup - : never; + ? OptimismExecution + : T extends "rollup" + ? OptimismRollup + : never; export type OptimismItemError<T extends OptimismType> = { status: "error"; diff --git a/packages/types/src/routes.ts b/packages/types/src/routes.ts index 6e12e7146..76417058a 100644 --- a/packages/types/src/routes.ts +++ b/packages/types/src/routes.ts @@ -41,7 +41,7 @@ import { CurrentWifiCredentials, WifiReport, WireguardDeviceCredentials, - DockerUpgradeRequirements, + DockerUpgradeRequirements } from "./calls.js"; import { PackageEnvs } from "./compose.js"; import { PackageBackup } from "./manifest.js"; @@ -60,29 +60,19 @@ export interface Routes { * @param id = "my-packages", "system-packages" or "bitcoin.dnp.dappnode.eth" * @param enabled Auto update is enabled for ID */ - autoUpdateSettingsEdit: (kwargs: { - id: string; - enabled: boolean; - }) => Promise<void>; + autoUpdateSettingsEdit: (kwargs: { id: string; enabled: boolean }) => Promise<void>; /** * Generates a backup of a package and sends it to the client for download. * @returns fileId = "64020f6e8d2d02aa2324dab9cd68a8ccb186e192232814f79f35d4c2fbf2d1cc" */ - backupGet: (kwargs: { - dnpName: string; - backup: PackageBackup[]; - }) => Promise<string>; + backupGet: (kwargs: { dnpName: string; backup: PackageBackup[] }) => Promise<string>; /** * Restores a backup of a package from the dataUri provided by the user * @returns fileId = "64020f6e8d2d02aa2324dab9cd68a8ccb186e192232814f79f35d4c2fbf2d1cc" */ - backupRestore: (kwargs: { - dnpName: string; - backup: PackageBackup[]; - fileId: string; - }) => Promise<void>; + backupRestore: (kwargs: { dnpName: string; backup: PackageBackup[]; fileId: string }) => Promise<void>; /** * Returns chain data for all installed packages declared as chains @@ -151,9 +141,7 @@ export interface Routes { * concatenated with the device id. * @param id Device id name */ - deviceCredentialsGet: (kwargs: { - id: string; - }) => Promise<VpnDeviceCredentials>; + deviceCredentialsGet: (kwargs: { id: string }) => Promise<VpnDeviceCredentials>; /** * Removes the device with the provided id, if exists. @@ -172,10 +160,7 @@ export interface Routes { * @param id Device id name * @param isAdmin new admin status */ - deviceAdminToggle: (kwargs: { - id: string; - isAdmin: boolean; - }) => Promise<void>; + deviceAdminToggle: (kwargs: { id: string; isAdmin: boolean }) => Promise<void>; /** * Returns true if a password has been created for this device @@ -213,9 +198,7 @@ export interface Routes { /** * Sets if a fallback should be used */ - ethClientFallbackSet: (kwargs: { - fallback: EthClientFallback; - }) => Promise<void>; + ethClientFallbackSet: (kwargs: { fallback: EthClientFallback }) => Promise<void>; /** * Changes the ethereum client used to fetch package data @@ -236,11 +219,7 @@ export interface Routes { * @param tgChannelId * @param sync */ - enableEthicalMetrics: (kwargs: { - mail: string | null; - tgChannelId: string | null; - sync: boolean; - }) => Promise<void>; + enableEthicalMetrics: (kwargs: { mail: string | null; tgChannelId: string | null; sync: boolean }) => Promise<void>; /** * Disables ethical metrics notifications @@ -289,10 +268,7 @@ export interface Routes { * @param first for pagination * @param after for pagination */ - getUserActionLogs: (kwargs: { - first?: number; - after?: number; - }) => Promise<UserActionLog[]>; + getUserActionLogs: (kwargs: { first?: number; after?: number }) => Promise<UserActionLog[]>; /** * Returns the host uptime @@ -304,9 +280,7 @@ export interface Routes { /** HTTPs Portal: map a subdomain */ httpsPortalMappingAdd(kwargs: { mapping: HttpsPortalMapping }): Promise<void>; /** HTTPs Portal: remove an existing mapping */ - httpsPortalMappingRemove(kwargs: { - mapping: HttpsPortalMapping; - }): Promise<void>; + httpsPortalMappingRemove(kwargs: { mapping: HttpsPortalMapping }): Promise<void>; /** HTTPs Portal: get all mappings */ httpsPortalMappingsGet(): Promise<HttpsPortalMapping[]>; /** HTTPs Portal: get exposable services with metadata */ @@ -322,9 +296,7 @@ export interface Routes { /** * Sets the ipfs client target: local | remote */ - ipfsClientTargetSet(kwargs: { - ipfsRepository: IpfsRepository; - }): Promise<void>; + ipfsClientTargetSet(kwargs: { ipfsRepository: IpfsRepository }): Promise<void>; /** * Gets the Ipfs client target @@ -359,11 +331,7 @@ export interface Routes { lvmLogicalVolumesGet: () => Promise<HostLogicalVolume[]>; /** LVM: extend host disk space */ - lvmDiskSpaceExtend: (kwargs: { - disk: string; - volumeGroup: string; - logicalVolume: string; - }) => Promise<string>; + lvmDiskSpaceExtend: (kwargs: { disk: string; volumeGroup: string; logicalVolume: string }) => Promise<string>; /** * Returns the list of current mountpoints in the host, @@ -374,10 +342,7 @@ export interface Routes { /** * Flag the UI welcome flow as completed */ - newFeatureStatusSet: (kwargs: { - featureId: NewFeatureId; - status: NewFeatureStatus; - }) => Promise<void>; + newFeatureStatusSet: (kwargs: { featureId: NewFeatureId; status: NewFeatureStatus }) => Promise<void>; /** * Returns not viewed notifications. @@ -396,9 +361,7 @@ export interface Routes { * Adds a notification to be shown the UI. * Set the notification param to null for a random notification */ - notificationsTest: (kwargs: { - notification?: PackageNotification; - }) => Promise<void>; + notificationsTest: (kwargs: { notification?: PackageNotification }) => Promise<void>; /** * Enables Optimism with the given config @@ -440,9 +403,7 @@ export interface Routes { /** * Get package detail information */ - packageGet: (kwargs: { - dnpName: string; - }) => Promise<InstalledPackageDetailData>; + packageGet: (kwargs: { dnpName: string }) => Promise<InstalledPackageDetailData>; /** * Returns the list of current containers associated to packages @@ -453,10 +414,7 @@ export interface Routes { * Toggles the visibility of a getting started block * @param show Should be shown on hidden */ - packageGettingStartedToggle: (kwargs: { - dnpName: string; - show: boolean; - }) => Promise<void>; + packageGettingStartedToggle: (kwargs: { dnpName: string; show: boolean }) => Promise<void>; /** * Returns the logs of the docker container of a package @@ -466,43 +424,27 @@ export interface Routes { * - tail: Number of lines to return from bottom: 200 * @returns String with escape codes */ - packageLog: (kwargs: { - containerName: string; - options?: { timestamps?: boolean; tail?: number }; - }) => Promise<string>; + packageLog: (kwargs: { containerName: string; options?: { timestamps?: boolean; tail?: number } }) => Promise<string>; /** * Remove a package and its data * @param id DNP .eth name * @param deleteVolumes flag to also clear permanent package data */ - packageRemove: (kwarg: { - dnpName: string; - deleteVolumes?: boolean; - timeout?: number; - }) => Promise<void>; + packageRemove: (kwarg: { dnpName: string; deleteVolumes?: boolean; timeout?: number }) => Promise<void>; /** * Recreates a package containers */ - packageRestart: (kwargs: { - dnpName: string; - serviceNames?: string[]; - }) => Promise<void>; + packageRestart: (kwargs: { dnpName: string; serviceNames?: string[] }) => Promise<void>; /** * Removes a package volumes. The re-ups the package */ - packageRestartVolumes: (kwargs: { - dnpName: string; - volumeId?: string; - }) => Promise<void>; + packageRestartVolumes: (kwargs: { dnpName: string; volumeId?: string }) => Promise<void>; /** Delete package sent data key */ - packageSentDataDelete: (kwargs: { - dnpName: string; - key?: string; - }) => Promise<void>; + packageSentDataDelete: (kwargs: { dnpName: string; key?: string }) => Promise<void>; /** * Updates the .env file of a package. If requested, also re-ups it @@ -565,16 +507,12 @@ export interface Routes { /** * Returns ports status from upnp scanning */ - portsUpnpStatusGet: (kwargs: { - portsToOpen: PortToOpen[]; - }) => Promise<UpnpTablePortStatus[]>; + portsUpnpStatusGet: (kwargs: { portsToOpen: PortToOpen[] }) => Promise<UpnpTablePortStatus[]>; /** * Returns ports status from API scanning */ - portsApiStatusGet: (kwargs: { - portsToOpen: PortToOpen[]; - }) => Promise<ApiTablePortStatus[]>; + portsApiStatusGet: (kwargs: { portsToOpen: PortToOpen[] }) => Promise<ApiTablePortStatus[]>; /** * Reboots the host machine via the DBus socket @@ -637,10 +575,7 @@ export interface Routes { /** * Set telegram configuration: token and user ID */ - telegramConfigSet: (kwargs: { - token: string; - userId: string; - }) => Promise<void>; + telegramConfigSet: (kwargs: { token: string; userId: string }) => Promise<void>; /** * Updates and upgrades the host machine @@ -827,7 +762,7 @@ export const routesData: { [P in keyof Routes]: RouteData } = { wireguardDeviceAdd: { log: true }, wireguardDeviceRemove: { log: true }, wireguardDeviceGet: {}, - wireguardDevicesGet: {}, + wireguardDevicesGet: {} }; // DO NOT REMOVE @@ -841,11 +776,8 @@ export type RoutesReturn = { * Returns the return resolved type of a function type */ /* eslint-disable @typescript-eslint/no-explicit-any */ -export type ResolvedType<T extends (...args: any) => Promise<any>> = T extends ( - ...args: any -) => Promise<infer R> +export type ResolvedType<T extends (...args: any) => Promise<any>> = T extends (...args: any) => Promise<infer R> ? R : never; -/* eslint-disable @typescript-eslint/no-explicit-any */ export type ReplaceVoidWithNull<T> = T extends void ? null : T; diff --git a/packages/types/src/stakers.ts b/packages/types/src/stakers.ts index 6bc0c9fb4..d2de3d212 100644 --- a/packages/types/src/stakers.ts +++ b/packages/types/src/stakers.ts @@ -7,7 +7,7 @@ export enum Network { Prater = "prater", Gnosis = "gnosis", Lukso = "lukso", - Holesky = "holesky", + Holesky = "holesky" } // MAINNET @@ -16,19 +16,19 @@ export enum ConsensusClientMainnet { Prysm = "prysm.dnp.dappnode.eth", Lighthouse = "lighthouse.dnp.dappnode.eth", Teku = "teku.dnp.dappnode.eth", - Nimbus = "nimbus.dnp.dappnode.eth", + Nimbus = "nimbus.dnp.dappnode.eth" } export enum ExecutionClientMainnet { Geth = "geth.dnp.dappnode.eth", Besu = "besu.public.dappnode.eth", Erigon = "erigon.dnp.dappnode.eth", - Nethermind = "nethermind.public.dappnode.eth", + Nethermind = "nethermind.public.dappnode.eth" } export enum SignerMainnet { - Web3signer = "web3signer.dnp.dappnode.eth", + Web3signer = "web3signer.dnp.dappnode.eth" } export enum MevBoostMainnet { - Mevboost = "mev-boost.dnp.dappnode.eth", + Mevboost = "mev-boost.dnp.dappnode.eth" } // PRATER @@ -37,19 +37,19 @@ export enum ConsensusClientPrater { Lighthouse = "lighthouse-prater.dnp.dappnode.eth", Teku = "teku-prater.dnp.dappnode.eth", Nimbus = "nimbus-prater.dnp.dappnode.eth", - Lodestar = "lodestar-prater.dnp.dappnode.eth", + Lodestar = "lodestar-prater.dnp.dappnode.eth" } export enum ExecutionClientPrater { Geth = "goerli-geth.dnp.dappnode.eth", Erigon = "goerli-erigon.dnp.dappnode.eth", Nethermind = "goerli-nethermind.dnp.dappnode.eth", - Besu = "goerli-besu.dnp.dappnode.eth", + Besu = "goerli-besu.dnp.dappnode.eth" } export enum SignerPrater { - Web3signer = "web3signer-prater.dnp.dappnode.eth", + Web3signer = "web3signer-prater.dnp.dappnode.eth" } export enum MevBoostPrater { - Mevboost = "mev-boost-goerli.dnp.dappnode.eth", + Mevboost = "mev-boost-goerli.dnp.dappnode.eth" } // HOLESKY @@ -58,20 +58,20 @@ export enum ConsensusClientHolesky { Lighthouse = "lighthouse-holesky.dnp.dappnode.eth", Teku = "teku-holesky.dnp.dappnode.eth", Nimbus = "nimbus-holesky.dnp.dappnode.eth", - Lodestar = "lodestar-holesky.dnp.dappnode.eth", + Lodestar = "lodestar-holesky.dnp.dappnode.eth" } export enum ExecutionClientHolesky { Geth = "holesky-geth.dnp.dappnode.eth", Erigon = "holesky-erigon.dnp.dappnode.eth", Nethermind = "holesky-nethermind.dnp.dappnode.eth", Besu = "holesky-besu.dnp.dappnode.eth", - Reth = "holesky-reth.dnp.dappnode.eth", + Reth = "holesky-reth.dnp.dappnode.eth" } export enum SignerHolesky { - Web3signer = "web3signer-holesky.dnp.dappnode.eth", + Web3signer = "web3signer-holesky.dnp.dappnode.eth" } export enum MevBoostHolesky { - Mevboost = "mev-boost-holesky.dnp.dappnode.eth", + Mevboost = "mev-boost-holesky.dnp.dappnode.eth" } // GNOSIS @@ -79,29 +79,29 @@ export enum ConsensusClientGnosis { Lighthouse = "lighthouse-gnosis.dnp.dappnode.eth", Teku = "teku-gnosis.dnp.dappnode.eth", Lodestar = "lodestar-gnosis.dnp.dappnode.eth", - Nimbus = "nimbus-gnosis.dnp.dappnode.eth", + Nimbus = "nimbus-gnosis.dnp.dappnode.eth" } export enum ExecutionClientGnosis { Nethermind = "nethermind-xdai.dnp.dappnode.eth", - Erigon = "gnosis-erigon.dnp.dappnode.eth", + Erigon = "gnosis-erigon.dnp.dappnode.eth" } export enum SignerGnosis { - Web3signer = "web3signer-gnosis.dnp.dappnode.eth", + Web3signer = "web3signer-gnosis.dnp.dappnode.eth" } // LUKSO export enum ConsensusClientLukso { /*"lighthouse-lukso.dnp.dappnode.eth",*/ Prysm = "prysm-lukso.dnp.dappnode.eth", - Teku = "teku-lukso.dnp.dappnode.eth", + Teku = "teku-lukso.dnp.dappnode.eth" } export enum ExecutionClientLukso { - Geth = "lukso-geth.dnp.dappnode.eth", + Geth = "lukso-geth.dnp.dappnode.eth" /*"lukso-erigon.dnp.dappnode.eth",*/ } export enum SignerLukso { - Web3signer = "web3signer-lukso.dnp.dappnode.eth", + Web3signer = "web3signer-lukso.dnp.dappnode.eth" } export type StakerItem = StakerItemOk | StakerItemError; diff --git a/packages/types/src/subscriptions.ts b/packages/types/src/subscriptions.ts index 46c710fed..8b6930b42 100644 --- a/packages/types/src/subscriptions.ts +++ b/packages/types/src/subscriptions.ts @@ -7,7 +7,7 @@ import { PackageNotification, SystemInfo, UserActionLog, - VolumeData, + VolumeData } from "./calls.js"; export interface SubscriptionsTypes { @@ -104,7 +104,7 @@ export const subscriptionsData: { [P in keyof Subscriptions]: object } = { registry: {}, systemInfo: {}, userActionLog: {}, - volumes: {}, + volumes: {} }; // DO NOT REMOVE diff --git a/packages/types/src/utils/getContainerDomain.ts b/packages/types/src/utils/getContainerDomain.ts index ea348f6c8..95b0794fd 100644 --- a/packages/types/src/utils/getContainerDomain.ts +++ b/packages/types/src/utils/getContainerDomain.ts @@ -4,14 +4,6 @@ * @param serviceName Service name (optional) * @returns Container domain in the format <service-name>.<dappnode-package-name> if service-name is not empty and different from dappnode-package-name, otherwise returns dappnode-package-name */ -export const getContainerDomain = ({ - dnpName, - serviceName, -}: { - serviceName?: string; - dnpName: string; -}): string => { - return !serviceName || serviceName === dnpName - ? dnpName - : `${serviceName}.${dnpName}`; +export const getContainerDomain = ({ dnpName, serviceName }: { serviceName?: string; dnpName: string }): string => { + return !serviceName || serviceName === dnpName ? dnpName : `${serviceName}.${dnpName}`; }; diff --git a/packages/types/src/utils/getContainerName.ts b/packages/types/src/utils/getContainerName.ts index 55955a289..8dbf3d6d9 100644 --- a/packages/types/src/utils/getContainerName.ts +++ b/packages/types/src/utils/getContainerName.ts @@ -10,14 +10,11 @@ import { getContainerDomain } from "./getContainerDomain.js"; export const getContainerName = ({ dnpName, serviceName, - isCore, + isCore }: { dnpName: string; serviceName: string; isCore: boolean; }): string => // Note: _PREFIX variables already end with the character "-" - [ - isCore ? "DAppNodeCore-" : "DAppNodePackage-", - getContainerDomain({ dnpName, serviceName }), - ].join(""); + [isCore ? "DAppNodeCore-" : "DAppNodePackage-", getContainerDomain({ dnpName, serviceName })].join(""); diff --git a/packages/types/src/utils/getImageTag.ts b/packages/types/src/utils/getImageTag.ts index 49ed7045b..5da2af420 100644 --- a/packages/types/src/utils/getImageTag.ts +++ b/packages/types/src/utils/getImageTag.ts @@ -13,7 +13,7 @@ import { getContainerDomain } from "./getContainerDomain.js"; export const getImageTag = ({ dnpName, serviceName, - version, + version }: { dnpName: string; serviceName: string; diff --git a/packages/types/src/utils/index.ts b/packages/types/src/utils/index.ts index 4470dd338..8f2a2ad23 100644 --- a/packages/types/src/utils/index.ts +++ b/packages/types/src/utils/index.ts @@ -1,4 +1,4 @@ export { getImageTag } from "./getImageTag.js"; export { getContainerName } from "./getContainerName.js"; export { getContainerDomain } from "./getContainerDomain.js"; -export { upstreamVersionToString } from "./upstreamVersionToString.js"; \ No newline at end of file +export { upstreamVersionToString } from "./upstreamVersionToString.js"; diff --git a/packages/types/src/utils/upstreamVersionToString.ts b/packages/types/src/utils/upstreamVersionToString.ts index ef2c14813..f95936e55 100644 --- a/packages/types/src/utils/upstreamVersionToString.ts +++ b/packages/types/src/utils/upstreamVersionToString.ts @@ -1,11 +1,13 @@ import { UpstreamItem } from "../manifest.js"; export const upstreamVersionToString = ({ - upstreamVersion, - upstream + upstreamVersion, + upstream }: { - upstreamVersion?: string; - upstream?: UpstreamItem[]; + upstreamVersion?: string; + upstream?: UpstreamItem[]; }): string | undefined => { - return upstreamVersion ? upstreamVersion : upstream && upstream.map(item => `${item.repo}@${item.version}`).join(", "); -} \ No newline at end of file + return upstreamVersion + ? upstreamVersion + : upstream && upstream.map((item) => `${item.repo}@${item.version}`).join(", "); +}; diff --git a/packages/upnpc/.eslintignore b/packages/upnpc/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/upnpc/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/upnpc/.eslintrc.cjs b/packages/upnpc/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/upnpc/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/upnpc/package.json b/packages/upnpc/package.json index a102942fb..b7e9846b2 100644 --- a/packages/upnpc/package.json +++ b/packages/upnpc/package.json @@ -15,8 +15,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/dockerapi": "workspace:^0.1.0", diff --git a/packages/upnpc/src/getExternalUpnpIp.ts b/packages/upnpc/src/getExternalUpnpIp.ts index d1a77cef7..959a7eccc 100644 --- a/packages/upnpc/src/getExternalUpnpIp.ts +++ b/packages/upnpc/src/getExternalUpnpIp.ts @@ -5,9 +5,7 @@ import { parseUpnpErrors } from "./upnpError.js"; export async function getExternalUpnpIp(): Promise<string> { try { const res = await upnpcCommand("-l"); - const externalIp = ((res || "").match( - /ExternalIPAddress.=.((\d+\.?){4})/ - ) || [])[1]; + const externalIp = ((res || "").match(/ExternalIPAddress.=.((\d+\.?){4})/) || [])[1]; if (isIp(externalIp)) return externalIp; else throw Error("Wrong IP"); } catch (e) { diff --git a/packages/upnpc/src/isUpnpAvailable.ts b/packages/upnpc/src/isUpnpAvailable.ts index 63d22c379..7bd8a0c08 100644 --- a/packages/upnpc/src/isUpnpAvailable.ts +++ b/packages/upnpc/src/isUpnpAvailable.ts @@ -6,11 +6,7 @@ export async function isUpnpAvailable(): Promise<boolean> { await list(); return true; } catch (e) { - if ( - e instanceof UpnpError && - e.typeUpnpError === UPnPErrors.UPNP_NOT_AVAILABLE - ) - return false; + if (e instanceof UpnpError && e.typeUpnpError === UPnPErrors.UPNP_NOT_AVAILABLE) return false; return true; } } diff --git a/packages/upnpc/src/list.ts b/packages/upnpc/src/list.ts index 0621be6b2..7ac0ae2c5 100644 --- a/packages/upnpc/src/list.ts +++ b/packages/upnpc/src/list.ts @@ -76,17 +76,13 @@ export async function list(): Promise<UpnpPortMapping[]> { */ export function parseListOutput(terminalOutput: string): UpnpPortMapping[] { // 1. Cut to the start of the table - const validLineRegex = RegExp( - /\d+\s+(UDP|TCP)\s+\d+->(\d+\.){3}\d+:\d+\s+.DAppNode/ - ); + const validLineRegex = RegExp(/\d+\s+(UDP|TCP)\s+\d+->(\d+\.){3}\d+:\d+\s+.DAppNode/); return ( terminalOutput .trim() .split(/\r?\n/) // Filter by lines that have the table format above - .filter( - (line) => line && typeof line === "string" && validLineRegex.test(line) - ) + .filter((line) => line && typeof line === "string" && validLineRegex.test(line)) // Parse the line to extract the protocol and port mapping .map((line) => { // 3 UDP 30303->192.168.1.42:30303 'DAppNode' '' 0 @@ -97,12 +93,10 @@ export function parseListOutput(terminalOutput: string): UpnpPortMapping[] { protocol: protocol === "UDP" ? PortProtocol.UDP : PortProtocol.TCP, exPort, inPort, - ip, + ip }; }) // Make sure each result is correct, otherwise remove it - .filter( - ({ exPort, inPort }) => !isNaN(Number(exPort)) && !isNaN(Number(inPort)) - ) + .filter(({ exPort, inPort }) => !isNaN(Number(exPort)) && !isNaN(Number(inPort))) ); } diff --git a/packages/upnpc/src/open.ts b/packages/upnpc/src/open.ts index d9b9691d9..38a8b472e 100644 --- a/packages/upnpc/src/open.ts +++ b/packages/upnpc/src/open.ts @@ -16,10 +16,7 @@ import { PackagePort } from "@dappnode/types"; // Timeout in seconds. Should be greater than the natRenewalInterval const natRenewalTimeout = 7200; -export async function open( - port: PackagePort, - localIp: string -): Promise<boolean> { +export async function open(port: PackagePort, localIp: string): Promise<boolean> { const { portNumber, protocol } = port; try { diff --git a/packages/upnpc/src/upnpError.ts b/packages/upnpc/src/upnpError.ts index 1e6159a49..0891edcaa 100644 --- a/packages/upnpc/src/upnpError.ts +++ b/packages/upnpc/src/upnpError.ts @@ -1,8 +1,6 @@ export function parseUpnpErrors(terminalOutput: string): UpnpError { - if (isUpnpAvailable(terminalOutput)) - return new UpnpError(terminalOutput, UPnPErrors.UPNP_NOT_AVAILABLE); - if (isNotExistingPort(terminalOutput)) - return new UpnpError(terminalOutput, UPnPErrors.UPNP_NOT_PORT); + if (isUpnpAvailable(terminalOutput)) return new UpnpError(terminalOutput, UPnPErrors.UPNP_NOT_AVAILABLE); + if (isNotExistingPort(terminalOutput)) return new UpnpError(terminalOutput, UPnPErrors.UPNP_NOT_PORT); return new UpnpError(terminalOutput, UPnPErrors.UNKNOWN); } diff --git a/packages/upnpc/src/upnpcCommand.ts b/packages/upnpc/src/upnpcCommand.ts index 9d2349100..d81f6c6c2 100644 --- a/packages/upnpc/src/upnpcCommand.ts +++ b/packages/upnpc/src/upnpcCommand.ts @@ -5,9 +5,7 @@ import { parseUpnpErrors } from "./upnpError.js"; export default async function upnpcCommand(cmd: string): Promise<string> { try { const image = await getDappmanagerImage(); - return await shell( - `docker run --rm --net=host --entrypoint=/usr/bin/upnpc ${image} ${cmd}` - ); + return await shell(`docker run --rm --net=host --entrypoint=/usr/bin/upnpc ${image} ${cmd}`); } catch (e) { const upnpError = parseUpnpErrors(e.message); throw upnpError; diff --git a/packages/upnpc/test/unit/parseCloseOutput.test.ts b/packages/upnpc/test/unit/parseCloseOutput.test.ts index e1e6ce41b..20e38e2dc 100644 --- a/packages/upnpc/test/unit/parseCloseOutput.test.ts +++ b/packages/upnpc/test/unit/parseCloseOutput.test.ts @@ -17,7 +17,7 @@ UPNP_DeletePortMapping() returned : 0 `; it("On success, it should return ok", async () => { - const ok = parseCloseOutput(terminalOutputSuccess); - expect(ok).to.be.ok; + const result = parseCloseOutput(terminalOutputSuccess); + expect(result).to.be.ok; }); }); diff --git a/packages/upnpc/test/unit/parseListOutput.test.ts b/packages/upnpc/test/unit/parseListOutput.test.ts index bdf6a2dee..3dc52e543 100644 --- a/packages/upnpc/test/unit/parseListOutput.test.ts +++ b/packages/upnpc/test/unit/parseListOutput.test.ts @@ -40,7 +40,7 @@ GetGenericPortMappingEntry() returned 713 (SpecifiedArrayIndexInvalid) { protocol: "UDP", exPort: "30303", inPort: "30303", ip: "192.168.1.42" }, { protocol: "TCP", exPort: "30303", inPort: "30303", ip: "192.168.1.42" }, { protocol: "TCP", exPort: "4001", inPort: "4001", ip: "192.168.1.42" }, - { protocol: "UDP", exPort: "4002", inPort: "4002", ip: "192.168.1.42" }, + { protocol: "UDP", exPort: "4002", inPort: "4002", ip: "192.168.1.42" } ]); }); }); diff --git a/packages/utils/.eslintignore b/packages/utils/.eslintignore deleted file mode 100644 index db4c6d9b6..000000000 --- a/packages/utils/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -node_modules \ No newline at end of file diff --git a/packages/utils/.eslintrc.cjs b/packages/utils/.eslintrc.cjs deleted file mode 100644 index 881637db7..000000000 --- a/packages/utils/.eslintrc.cjs +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - extends: [ - "../../.eslintrc.cjs", // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], -} \ No newline at end of file diff --git a/packages/utils/package.json b/packages/utils/package.json index dd31fdc0d..670e9e8ad 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -16,8 +16,7 @@ "scripts": { "build": "tsc -p tsconfig.json", "test": "TEST=true mocha --config ./.mocharc.yaml --recursive ./test/unit", - "dev": "tsc -w", - "lint": "eslint . --ext .ts --fix src" + "dev": "tsc -w" }, "dependencies": { "@dappnode/params": "workspace:^0.1.0", diff --git a/packages/utils/src/applyRecursivelyToStringValues.ts b/packages/utils/src/applyRecursivelyToStringValues.ts index 45e8551b9..76a4f8b93 100644 --- a/packages/utils/src/applyRecursivelyToStringValues.ts +++ b/packages/utils/src/applyRecursivelyToStringValues.ts @@ -4,12 +4,8 @@ import { mapValues, isObject } from "lodash-es"; // eslint-disable-next-line @typescript-eslint/no-explicit-any type GenericObject = { [key: string]: any }; -export function applyRecursivelyToStringValues( - stringModifier: (value: string, key: string) => string -) { - return function objectModifier<T extends GenericObject>( - obj: T | T[] - ): T | T[] { +export function applyRecursivelyToStringValues(stringModifier: (value: string, key: string) => string) { + return function objectModifier<T extends GenericObject>(obj: T | T[]): T | T[] { if (typeof obj === "object") { if (Array.isArray(obj)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/utils/src/asyncFlows.ts b/packages/utils/src/asyncFlows.ts index fa8929404..a2e5e9bca 100644 --- a/packages/utils/src/asyncFlows.ts +++ b/packages/utils/src/asyncFlows.ts @@ -29,14 +29,10 @@ export function memoizeDebounce<F extends AnyFunction>( resolver?: Options<(...args: Parameters<F>) => DebouncedFunc<F>> ): MemoizeDebouncedFunction<F> { const debounceMemo = memoize<(...args: Parameters<F>) => DebouncedFunc<F>>( - // eslint-disable-next-line @typescript-eslint/no-unused-vars (..._args: Parameters<F>) => debounce(func, wait, options), resolver ); - function wrappedFunction( - this: MemoizeDebouncedFunction<F>, - ...args: Parameters<F> - ): ReturnType<F> | undefined { + function wrappedFunction(this: MemoizeDebouncedFunction<F>, ...args: Parameters<F>): ReturnType<F> | undefined { return debounceMemo(...args)(...args); } @@ -54,8 +50,7 @@ export function memoizeDebounce<F extends AnyFunction>( return wrappedFunction; } -interface MemoizeDebouncedFunction<F extends AnyFunction> - extends DebouncedFunc<F> { +interface MemoizeDebouncedFunction<F extends AnyFunction> extends DebouncedFunc<F> { (...args: Parameters<F>): ReturnType<F> | undefined; flush: (...args: Parameters<F>) => ReturnType<F> | undefined; cancel: (...args: Parameters<F>) => void; @@ -97,10 +92,8 @@ export async function runAtMostEveryIntervals( let lastRunMs = 0; const intervalMsFinal = intervalsMs[intervalsMs.length - 1]; - if (intervalMsFinal === undefined) - throw Error(`msArray must have at least one element`); + if (intervalMsFinal === undefined) throw Error(`msArray must have at least one element`); - // eslint-disable-next-line no-constant-condition while (true) { lastRunMs = Date.now(); @@ -128,7 +121,6 @@ export async function sleep(ms: number, signal?: AbortSignal): Promise<void> { return new Promise((resolve, reject) => { if (signal && signal.aborted) return reject(new ErrorAborted()); - // eslint-disable-next-line @typescript-eslint/no-empty-function let onDone: () => void = () => {}; const timeout = setTimeout(() => { @@ -167,26 +159,17 @@ export async function sleep(ms: number, signal?: AbortSignal): Promise<void> { * * @param fn Target function */ -export function runOnlyOneSequentially<A, R>( - fn: (arg?: A) => Promise<R> -): (arg?: A) => void { +export function runOnlyOneSequentially<A, R>(fn: (arg?: A) => Promise<R>): (arg?: A) => void { // create a cargo object with an infinite payload - const cargo = async.cargo(function ( - tasks: { arg: A }[], - callback: () => void - ) { + const cargo = async.cargo(function (tasks: { arg: A }[], callback: () => void) { fn(tasks[0]?.arg) .then(() => { callback(); }) .catch((e) => { - console.error( - `WARNING! functions in runOnlyOneSequentially MUST not throw, wrap them in try/catch blocks`, - e - ); + console.error(`WARNING! functions in runOnlyOneSequentially MUST not throw, wrap them in try/catch blocks`, e); }); - }, - 1e9); + }, 1e9); return function (arg?: A): void { cargo.push({ arg: arg as A }); @@ -208,15 +191,13 @@ export function runOnlyOneSequentially<A, R>( * @param fn Target function (Callback style) */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -export function runOnlyOneReturnToAll<F extends (...args: any[]) => any>( - f: F -): F { +export function runOnlyOneReturnToAll<F extends (...args: any[]) => any>(f: F): F { return memoize(f, { // Wait for Promises to resolve. Do not cache rejections promise: true, // Return the computed cached result to only waiting calls while the // result if being computed. Right as it is resolved, compute it again - maxAge: 1, + maxAge: 1 }); } diff --git a/packages/utils/src/buildNetworkAlias.ts b/packages/utils/src/buildNetworkAlias.ts index fab2ecae5..80b843f15 100644 --- a/packages/utils/src/buildNetworkAlias.ts +++ b/packages/utils/src/buildNetworkAlias.ts @@ -28,7 +28,7 @@ export function buildNetworkAlias({ dnpName, serviceName, isMainOrMonoservice, - isExternal = false, + isExternal = false }: { dnpName: string; serviceName: string; diff --git a/packages/utils/src/coreVersionId.ts b/packages/utils/src/coreVersionId.ts index 28252b4e9..97edb7349 100644 --- a/packages/utils/src/coreVersionId.ts +++ b/packages/utils/src/coreVersionId.ts @@ -8,9 +8,7 @@ import { gte } from "semver"; * @param coreDnps * @returns versionId = "admin@0.2.4,vpn@0.2.2,core@0.2.6" */ -export function getCoreVersionId( - coreDnps: { dnpName: string; version: string }[] -): string { +export function getCoreVersionId(coreDnps: { dnpName: string; version: string }[]): string { return coreDnps .filter(({ dnpName, version }) => dnpName && version) .map(({ dnpName, version }) => [dnpName.split(".")[0], version].join("@")) @@ -18,13 +16,11 @@ export function getCoreVersionId( .join(","); } -export function parseCoreVersionId( - versionId: string -): { dnpName: string; version: string }[] { +export function parseCoreVersionId(versionId: string): { dnpName: string; version: string }[] { return versionId .split(",") - .filter(nameAtVersion => nameAtVersion) - .map(nameAtVersion => { + .filter((nameAtVersion) => nameAtVersion) + .map((nameAtVersion) => { const [shortName, version] = nameAtVersion.split("@"); return { dnpName: `${shortName}.dnp.dappnode.eth`, version }; }); @@ -39,11 +35,9 @@ export function isVersionIdUpdated( coreVersionId: string, currentCorePackages: { dnpName: string; version: string }[] ): boolean { - const currentVersions = new Map<string, string>( - currentCorePackages.map(p => [p.dnpName, p.version]) - ); + const currentVersions = new Map<string, string>(currentCorePackages.map((p) => [p.dnpName, p.version])); const versionIdDnps = parseCoreVersionId(coreVersionId); - return versionIdDnps.every(versionIdDnp => { + return versionIdDnps.every((versionIdDnp) => { const currentVersion = currentVersions.get(versionIdDnp.dnpName); return currentVersion && gte(currentVersion, versionIdDnp.version); }); diff --git a/packages/utils/src/environment.ts b/packages/utils/src/environment.ts index 20c1c5002..f0da69424 100644 --- a/packages/utils/src/environment.ts +++ b/packages/utils/src/environment.ts @@ -11,12 +11,9 @@ import { pickBy } from "lodash-es"; * @returns envs = * { NAME: "VALUE", NOVAL: "", COMPLEX: "D=D=D = 2" } */ -export function parseEnvironment( - envsArray: string[] | PackageEnvs -): PackageEnvs { +export function parseEnvironment(envsArray: string[] | PackageEnvs): PackageEnvs { // Make sure ENVs are in array format - if (typeof envsArray === "object" && !Array.isArray(envsArray)) - return envsArray; + if (typeof envsArray === "object" && !Array.isArray(envsArray)) return envsArray; return envsArray .filter((row) => (row || "").trim()) @@ -53,7 +50,7 @@ export function mergeEnvs(envs1: PackageEnvs, envs2: PackageEnvs): PackageEnvs { return pickBy( { ...envs2, - ...envs1, + ...envs1 }, (_0, key) => key ); diff --git a/packages/utils/src/ethers.ts b/packages/utils/src/ethers.ts index 253280606..cfbbd7201 100644 --- a/packages/utils/src/ethers.ts +++ b/packages/utils/src/ethers.ts @@ -44,7 +44,7 @@ export type NetPeersCount = number; export function parseEthersSyncing(syncing: EthSyncingReturn): EthSyncing { if (!syncing) return false; - const parsedSyncing = mapValues(syncing, hexValue => { + const parsedSyncing = mapValues(syncing, (hexValue) => { switch (typeof hexValue) { case "string": return parseInt(hexValue); diff --git a/packages/utils/src/fileToGatewayUrl.ts b/packages/utils/src/fileToGatewayUrl.ts index e80e4623c..d3789c4d8 100644 --- a/packages/utils/src/fileToGatewayUrl.ts +++ b/packages/utils/src/fileToGatewayUrl.ts @@ -14,10 +14,7 @@ export function fileToGatewayUrl(distributedFile?: DistributedFile): string { switch (distributedFile.source) { case "ipfs": - return url.resolve( - url.resolve(params.IPFS_REMOTE, params.IPFS_GATEWAY), - normalizeHash(distributedFile.hash) - ); + return url.resolve(url.resolve(params.IPFS_REMOTE, params.IPFS_GATEWAY), normalizeHash(distributedFile.hash)); default: throw Error(`Source not supported: ${distributedFile.source}`); } diff --git a/packages/utils/src/getBackupPath.ts b/packages/utils/src/getBackupPath.ts index e705cbebe..73092f7df 100644 --- a/packages/utils/src/getBackupPath.ts +++ b/packages/utils/src/getBackupPath.ts @@ -7,6 +7,6 @@ export function getBackupPath(anyPath: string): string { // `name` + `ext` will be used if `base` is not specified. return path.format({ ...omit(pathObj, "base"), - ext: `.backup${pathObj.ext}`, + ext: `.backup${pathObj.ext}` }); } diff --git a/packages/utils/src/getDockerComposePath.ts b/packages/utils/src/getDockerComposePath.ts index f97cc30f9..1e966ca88 100644 --- a/packages/utils/src/getDockerComposePath.ts +++ b/packages/utils/src/getDockerComposePath.ts @@ -3,10 +3,7 @@ import fs from "fs"; import { getRepoDirPath } from "./getRepoDirPath.js"; export function getDockerComposePath(dnpName: string, isCore: boolean): string { - return path.join( - getRepoDirPath(dnpName, isCore), - getDockerComposeName(dnpName, isCore) - ); + return path.join(getRepoDirPath(dnpName, isCore), getDockerComposeName(dnpName, isCore)); } export function getDockerComposePathSmart(dnpName: string): string { @@ -29,9 +26,5 @@ function getShortName(dnpName: string): string { function verifyDnpName(dnpName: string): void { if (typeof dnpName !== "string") - throw Error( - `dnpName must be a string, but it's ${typeof dnpName}: ${JSON.stringify( - dnpName - )}` - ); + throw Error(`dnpName must be a string, but it's ${typeof dnpName}: ${JSON.stringify(dnpName)}`); } diff --git a/packages/utils/src/getImagePath.ts b/packages/utils/src/getImagePath.ts index 6674488da..dff96c140 100644 --- a/packages/utils/src/getImagePath.ts +++ b/packages/utils/src/getImagePath.ts @@ -1,13 +1,6 @@ import path from "path"; import { getRepoDirPath } from "./getRepoDirPath.js"; -export function getImagePath( - dnpName: string, - version: string, - isCore: boolean -): string { - return path.join( - getRepoDirPath(dnpName, isCore), - `${dnpName}_${version}.tar.xz` - ); +export function getImagePath(dnpName: string, version: string, isCore: boolean): string { + return path.join(getRepoDirPath(dnpName, isCore), `${dnpName}_${version}.tar.xz`); } diff --git a/packages/utils/src/getIsInstalled.ts b/packages/utils/src/getIsInstalled.ts index 3e7e02217..b5efe9690 100644 --- a/packages/utils/src/getIsInstalled.ts +++ b/packages/utils/src/getIsInstalled.ts @@ -3,9 +3,6 @@ import { InstalledPackageData } from "@dappnode/types"; /** * Helper to check if a package is installed */ -export function getIsInstalled( - { dnpName }: { dnpName: string }, - dnpList: InstalledPackageData[] -): boolean { +export function getIsInstalled({ dnpName }: { dnpName: string }, dnpList: InstalledPackageData[]): boolean { return !!dnpList.find((dnp) => dnp.dnpName === dnpName); } diff --git a/packages/utils/src/getIsRunning.ts b/packages/utils/src/getIsRunning.ts index 0dcb60af4..168c46c3e 100644 --- a/packages/utils/src/getIsRunning.ts +++ b/packages/utils/src/getIsRunning.ts @@ -4,18 +4,12 @@ import { InstalledPackageData } from "@dappnode/types"; * Returns true if the package is running or false if not * For web3signer, it does not take into account the container "flyway" which may not be running */ -export function getIsRunning( - { dnpName }: { dnpName: string }, - dnpList: InstalledPackageData[] -): boolean { +export function getIsRunning({ dnpName }: { dnpName: string }, dnpList: InstalledPackageData[]): boolean { const flywayServiceName = "flyway"; const isSigner = dnpName.includes("web3signer"); const dnp = dnpList.find((dnp) => dnp.dnpName === dnpName); if (dnp) { - if (isSigner) - return dnp.containers - .filter((c) => c.serviceName !== flywayServiceName) - .every((c) => c.running); + if (isSigner) return dnp.containers.filter((c) => c.serviceName !== flywayServiceName).every((c) => c.running); else return dnp.containers.every((c) => c.running); } return false; diff --git a/packages/utils/src/getManifestPath.ts b/packages/utils/src/getManifestPath.ts index 3a223eb6f..8c45511ab 100644 --- a/packages/utils/src/getManifestPath.ts +++ b/packages/utils/src/getManifestPath.ts @@ -2,10 +2,7 @@ import path from "path"; import { getRepoDirPath } from "./getRepoDirPath.js"; export function getManifestPath(dnpName: string, isCore: boolean): string { - return path.join( - getRepoDirPath(dnpName, isCore), - getManifestName(dnpName, isCore) - ); + return path.join(getRepoDirPath(dnpName, isCore), getManifestName(dnpName, isCore)); } function getManifestName(dnpName: string, isCore: boolean): string { @@ -20,9 +17,5 @@ function getShortName(dnpName: string): string { function verifyDnpName(dnpName: string): void { if (typeof dnpName !== "string") - throw Error( - `dnpName must be a string, but it's ${typeof dnpName}: ${JSON.stringify( - dnpName - )}` - ); + throw Error(`dnpName must be a string, but it's ${typeof dnpName}: ${JSON.stringify(dnpName)}`); } diff --git a/packages/utils/src/getPrivateNetworkAliases.ts b/packages/utils/src/getPrivateNetworkAliases.ts index befca6442..77471ff5f 100644 --- a/packages/utils/src/getPrivateNetworkAliases.ts +++ b/packages/utils/src/getPrivateNetworkAliases.ts @@ -7,29 +7,21 @@ import { buildNetworkAlias } from "./buildNetworkAlias.js"; * @param container * @returns */ -export function getPrivateNetworkAliases( - container: ContainerNames & { isMainOrMonoservice: boolean } -): string[] { +export function getPrivateNetworkAliases(container: ContainerNames & { isMainOrMonoservice: boolean }): string[] { const { isMainOrMonoservice, dnpName, serviceName } = container; const aliases: string[] = []; // push full alias // The "isMainOrMonoservice" is false because we always want a full alias for each service (container) - aliases.push( - buildNetworkAlias({ dnpName, serviceName, isMainOrMonoservice: false }) - ); + aliases.push(buildNetworkAlias({ dnpName, serviceName, isMainOrMonoservice: false })); // push short alias // if service is "isMain", we also want to add the short alias for it - if (isMainOrMonoservice) - aliases.push( - buildNetworkAlias({ dnpName, serviceName, isMainOrMonoservice: true }) - ); + if (isMainOrMonoservice) aliases.push(buildNetworkAlias({ dnpName, serviceName, isMainOrMonoservice: true })); // Special unique alias for the Admin UI - if (dnpName === params.dappmanagerDnpName) - aliases.push(...params.DAPPMANAGER_ALIASES); + if (dnpName === params.dappmanagerDnpName) aliases.push(...params.DAPPMANAGER_ALIASES); // Ensure uniqueness return [...new Set(aliases)]; diff --git a/packages/utils/src/getPublicIpFromUrls.ts b/packages/utils/src/getPublicIpFromUrls.ts index 26953aaba..0882b8721 100644 --- a/packages/utils/src/getPublicIpFromUrls.ts +++ b/packages/utils/src/getPublicIpFromUrls.ts @@ -1,11 +1,7 @@ import isIp from "is-ip"; import retry from "async-retry"; -const urls = [ - "https://ns.dappnode.io/myip", - "http://ipv4.icanhazip.com", - "http://ident.me", -]; +const urls = ["https://ns.dappnode.io/myip", "http://ipv4.icanhazip.com", "http://ident.me"]; /** * Attempts to get an IP from the above list of urls sequentially @@ -15,10 +11,7 @@ const urls = [ * @param silent suppress logs * @returns public IP: 85.84.83.82 */ -export async function getPublicIpFromUrls(options?: { - timeout?: number; - retries?: number; -}): Promise<string> { +export async function getPublicIpFromUrls(options?: { timeout?: number; retries?: number }): Promise<string> { const timeout = options?.timeout || 15 * 1000; const retries = options?.retries || 10; diff --git a/packages/utils/src/getSchemaValidator.ts b/packages/utils/src/getSchemaValidator.ts index 9d5ca6527..09f988b7e 100644 --- a/packages/utils/src/getSchemaValidator.ts +++ b/packages/utils/src/getSchemaValidator.ts @@ -2,19 +2,13 @@ import Ajv from "ajv"; const ajv = new Ajv({ allErrors: true }); -export function getSchemaValidator<T>( - schema: { title: string }, - dataName?: string -): (data: T) => T { +export function getSchemaValidator<T>(schema: { title: string }, dataName?: string): (data: T) => T { const name = dataName || schema.title || "data"; const validate = ajv.compile(schema); return (data: T): T => { if (!validate(data)) { const { errors } = validate; - throw Error( - `Invalid ${name}:\n` + - ajv.errorsText(errors, { separator: "\n", dataVar: name }) - ); + throw Error(`Invalid ${name}:\n` + ajv.errorsText(errors, { separator: "\n", dataVar: name })); } return data; }; diff --git a/packages/utils/src/globalEnvs.ts b/packages/utils/src/globalEnvs.ts index 349b1a12b..321886495 100644 --- a/packages/utils/src/globalEnvs.ts +++ b/packages/utils/src/globalEnvs.ts @@ -10,8 +10,7 @@ export const globalEnvsFilePath = params.GLOBAL_ENVS_PATH; * Create a global ENVs file with only a sanity check value: { ACTIVE: "true" } */ export function createGlobalEnvsEnvFile(): void { - if (!fs.existsSync(globalEnvsFilePath)) - writeEnvFile(globalEnvsFilePath, { ACTIVE: "true" } as GlobalEnvs); + if (!fs.existsSync(globalEnvsFilePath)) writeEnvFile(globalEnvsFilePath, { ACTIVE: "true" } as GlobalEnvs); } /** @@ -27,10 +26,7 @@ export function createGlobalEnvsEnvFile(): void { * @param envs = */ export function writeEnvFile(envPath: string, envs: GlobalEnvs): void { - const envsWithPrefix = mapKeys( - envs, - (_0, key) => GLOBAL_ENVS[key as keyof typeof envs] - ); + const envsWithPrefix = mapKeys(envs, (_0, key) => GLOBAL_ENVS[key as keyof typeof envs]); const envData = stringifyEnvironment(envsWithPrefix).join("\n"); fs.writeFileSync(envPath, envData); } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index e5c33e8a0..989320ea7 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -5,10 +5,7 @@ export { validatePath } from "./validatePath.js"; export { isNotFoundError } from "./isNotFoundError.js"; export { yamlParse, yamlDump } from "./yaml.js"; export { getSchemaValidator } from "./getSchemaValidator.js"; -export { - getDockerComposePath, - getDockerComposePathSmart, -} from "./getDockerComposePath.js"; +export { getDockerComposePath, getDockerComposePathSmart } from "./getDockerComposePath.js"; export { getRepoDirPath } from "./getRepoDirPath.js"; export { removeUnderscores } from "./removeUnderscores.js"; export { getShortUniqueDnp } from "./getShortUniqueDnp.js"; @@ -19,11 +16,7 @@ export { shell, shellHost, ShellError } from "./shell.js"; export { normalizeHash } from "./normalizeHash.js"; export { fileToGatewayUrl } from "./fileToGatewayUrl.js"; export { packageInstalledHasPid } from "./packageInstalledHasPid.js"; -export { - parseEnvironment, - stringifyEnvironment, - mergeEnvs, -} from "./environment.js"; +export { parseEnvironment, stringifyEnvironment, mergeEnvs } from "./environment.js"; export { writeEnvFile, createGlobalEnvsEnvFile } from "./globalEnvs.js"; export { getManifestPath } from "./getManifestPath.js"; export { getImagePath } from "./getImagePath.js"; @@ -34,10 +27,7 @@ export * from "./asyncFlows.js"; export * from "./pid.js"; export { urlJoin } from "./urlJoin.js"; export { prettyDnpName } from "./prettyDnpName.js"; -export { - getBeaconServiceName, - getConsensusUserSettings, -} from "./stakerUtils.js"; +export { getBeaconServiceName, getConsensusUserSettings } from "./stakerUtils.js"; export * from "./ethers.js"; export { shellSafe } from "./shellSafe.js"; export { getIsInstalled } from "./getIsInstalled.js"; @@ -49,4 +39,4 @@ export { computeSemverUpdateType } from "./computeSemverUpdateType.js"; export * from "./coreVersionId.js"; export { writeManifest } from "./writeManifest.js"; export { readManifestIfExists } from "./readManifestIfExists.js"; -export { removeCidrSuffix } from "./removeCidrSuffix.js"; \ No newline at end of file +export { removeCidrSuffix } from "./removeCidrSuffix.js"; diff --git a/packages/utils/src/pid.ts b/packages/utils/src/pid.ts index eeb299bc0..abf7c3fc3 100644 --- a/packages/utils/src/pid.ts +++ b/packages/utils/src/pid.ts @@ -17,13 +17,8 @@ export function packageToInstallHasPid(pkg: InstallPackageData): boolean { return false; } -export function isTargetPidServiceIncluded( - targetContainers: PackageContainer[], - targetPidServices: string[] -): boolean { - return targetContainers.some((tc) => - targetPidServices.includes(tc.serviceName) - ); +export function isTargetPidServiceIncluded(targetContainers: PackageContainer[], targetPidServices: string[]): boolean { + return targetContainers.some((tc) => targetPidServices.includes(tc.serviceName)); } /** @@ -46,25 +41,16 @@ export function getServicesSharingPid( const dependantPidService = Object.keys(compose.services)[index]; // Ensure targetPidService is well formatted and exists in compose - if (!targetPidService) - throw Error( - `target pid service in wrong format: ${targetPidService}` - ); + if (!targetPidService) throw Error(`target pid service in wrong format: ${targetPidService}`); if (!Object.keys(compose.services).includes(targetPidService)) - throw Error( - `target pid service ${targetPidService} not found in the compose` - ); + throw Error(`target pid service ${targetPidService} not found in the compose`); targetPidServices.push(targetPidService); dependantPidServices.push(dependantPidService); } } // Return null if the targetPid is not included because these - if ( - targetContainers && - !isTargetPidServiceIncluded(targetContainers, targetPidServices) - ) - return null; + if (targetContainers && !isTargetPidServiceIncluded(targetContainers, targetPidServices)) return null; return { dependantPidServices, targetPidServices }; } return null; diff --git a/packages/utils/src/readManifestIfExists.ts b/packages/utils/src/readManifestIfExists.ts index 94db4f4dd..48ce1f5f7 100644 --- a/packages/utils/src/readManifestIfExists.ts +++ b/packages/utils/src/readManifestIfExists.ts @@ -21,13 +21,7 @@ function readManifest(manfiestPath: string): Manifest { return parseManifest(fs.readFileSync(manfiestPath, "utf8")); } -export function readManifestIfExists({ - dnpName, - isCore, -}: { - dnpName: string; - isCore: boolean; -}): Manifest | null { +export function readManifestIfExists({ dnpName, isCore }: { dnpName: string; isCore: boolean }): Manifest | null { const manifestPath = validatePath(getManifestPath(dnpName, isCore)); try { return readManifest(manifestPath); diff --git a/packages/utils/src/shell.ts b/packages/utils/src/shell.ts index 99ffa8036..2de205752 100644 --- a/packages/utils/src/shell.ts +++ b/packages/utils/src/shell.ts @@ -30,8 +30,7 @@ export async function shell( } catch (e) { // Rethrow a typed error, and ignore the internal NodeJS stack trace const err: child.ExecException = e; - if (err.signal === "SIGTERM") - throw new ShellError(e, `process timeout ${timeout} ms, cmd: ${cmd}`); + if (err.signal === "SIGTERM") throw new ShellError(e, `process timeout ${timeout} ms, cmd: ${cmd}`); else throw new ShellError(e); } } @@ -43,10 +42,7 @@ export async function shell( * part of the `docker run ... nsenter` command * `mkdir -- -p /some/dir` will succeed */ -export function shellHost( - cmd: string, - options?: { timeout?: number } -): Promise<string> { +export function shellHost(cmd: string, options?: { timeout?: number }): Promise<string> { return shell(`${nsenterCommand} ${cmd}`, options); } @@ -61,10 +57,7 @@ export class ShellError extends Error implements child.ExecException { signal?: NodeJS.Signals; stdout?: string; stderr?: string; - constructor( - e: child.ExecException & { stdout?: string; stderr?: string }, - message?: string - ) { + constructor(e: child.ExecException & { stdout?: string; stderr?: string }, message?: string) { super(message || e.message); this.cmd = e.cmd; this.killed = e.killed; diff --git a/packages/utils/src/stakerUtils.ts b/packages/utils/src/stakerUtils.ts index f83f09bb5..f346f8c05 100644 --- a/packages/utils/src/stakerUtils.ts +++ b/packages/utils/src/stakerUtils.ts @@ -27,7 +27,7 @@ export function getBeaconServiceName(dnpName: string): string { */ export function getConsensusUserSettings({ dnpName, - network, + network }: { dnpName: string; network: Network; @@ -47,25 +47,25 @@ export function getConsensusUserSettings({ // Graffiti is a mandatory value ["GRAFFITI"]: defaultDappnodeGraffiti, // Checkpoint sync is an optional value - ["CHECKPOINT_SYNC_URL"]: getDefaultCheckpointSync(network), - }, + ["CHECKPOINT_SYNC_URL"]: getDefaultCheckpointSync(network) + } } : { [validatorServiceName]: { // Fee recipient is set as global env, keep this for backwards compatibility ["FEE_RECIPIENT_ADDRESS"]: defaultFeeRecipient, // Graffiti is a mandatory value - ["GRAFFITI"]: defaultDappnodeGraffiti, + ["GRAFFITI"]: defaultDappnodeGraffiti }, [beaconServiceName]: { // Fee recipient is set as global env, keep this for backwards compatibility ["FEE_RECIPIENT_ADDRESS"]: defaultFeeRecipient, // Checkpoint sync is an optional value - ["CHECKPOINT_SYNC_URL"]: getDefaultCheckpointSync(network), - }, - }, - }, + ["CHECKPOINT_SYNC_URL"]: getDefaultCheckpointSync(network) + } + } + } }; } @@ -73,11 +73,11 @@ const getDefaultCheckpointSync = (network: Network): string => network === "mainnet" ? "https://checkpoint-sync.dappnode.io" : network === "prater" - ? "https://checkpoint-sync-prater.dappnode.io" - : network === "gnosis" - ? "https://checkpoint-sync-gnosis.dappnode.io" - : network === "holesky" - ? "https://checkpoint-sync-holesky.dappnode.io" - : network === "lukso" - ? "https://checkpoints.mainnet.lukso.network" - : ""; + ? "https://checkpoint-sync-prater.dappnode.io" + : network === "gnosis" + ? "https://checkpoint-sync-gnosis.dappnode.io" + : network === "holesky" + ? "https://checkpoint-sync-holesky.dappnode.io" + : network === "lukso" + ? "https://checkpoints.mainnet.lukso.network" + : ""; diff --git a/packages/utils/src/yaml.ts b/packages/utils/src/yaml.ts index cc90113d4..eb2c6fe6d 100644 --- a/packages/utils/src/yaml.ts +++ b/packages/utils/src/yaml.ts @@ -7,8 +7,7 @@ import yaml from "js-yaml"; export function yamlParse<T>(yamlString: string): T { try { const parsedData = yaml.load(yamlString); - if (!parsedData || typeof parsedData === "string") - throw Error(`returned invalid object`); + if (!parsedData || typeof parsedData === "string") throw Error(`returned invalid object`); return parsedData as unknown as T; } catch (e) { throw Error(`Error parsing YAML: ${e.message}`); diff --git a/packages/utils/test/unit/asyncFlows.test.ts b/packages/utils/test/unit/asyncFlows.test.ts index 8ff20a8d3..e755f304e 100644 --- a/packages/utils/test/unit/asyncFlows.test.ts +++ b/packages/utils/test/unit/asyncFlows.test.ts @@ -1,10 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { - runOnlyOneSequentially, - runOnlyOneReturnToAll, - pause, -} from "../../src/asyncFlows.js"; +import { runOnlyOneSequentially, runOnlyOneReturnToAll, pause } from "../../src/asyncFlows.js"; describe("Util: asyncFlows", () => { describe("runOnlyOneSequentially", () => { @@ -35,7 +31,7 @@ describe("Util: asyncFlows", () => { "Requesting 2", "Requesting 3", "success async 0", - "success async 1", + "success async 1" ]); }); @@ -55,12 +51,7 @@ describe("Util: asyncFlows", () => { await pause(callDelay); } - expect(mockLog).to.deep.equal([ - "Requesting 0", - "Requesting 1", - "Requesting 2", - "Requesting 3", - ]); + expect(mockLog).to.deep.equal(["Requesting 0", "Requesting 1", "Requesting 2", "Requesting 3"]); }); }); @@ -113,20 +104,16 @@ Error 15: 0.616938341865086 console.log(s); mockLog.push(s); } - const throttledCallback = runOnlyOneReturnToAll( - async (c: { a: number }) => { - c; - if (isProcessing) - throw Error(`Cannot process twice at the same time`); - isProcessing = true; - log(`processing...`); - await pause(internalFunctionPause); - isProcessing = false; - const res = Math.random(); - if (res > 0.5) throw Error(String(res)); - else return res; - } - ); + const throttledCallback = runOnlyOneReturnToAll(async (c: { a: number }) => { + if (isProcessing) throw Error(`Cannot process twice at the same time`); + isProcessing = true; + log(`processing ${c} ...`); + await pause(internalFunctionPause); + isProcessing = false; + const res = Math.random(); + if (res > 0.5) throw Error(String(res)); + else return res; + }); for (let i = 0; i < 100; i++) { log(`Requesting ${i}`); @@ -164,7 +151,7 @@ Error 15: 0.616938341865086 "Requesting 1", "Requesting 2", "Requesting 3", - "success async 0", + "success async 0" ]); }); @@ -196,7 +183,7 @@ Error 15: 0.616938341865086 "Requesting 2", "Requesting 3", "success async 2", - "success async 3", + "success async 3" ]); }); @@ -231,7 +218,7 @@ Error 15: 0.616938341865086 "Requesting 2", "Requesting 3", "mock error async 2", - "mock error async 3", + "mock error async 3" ]); }); }); diff --git a/packages/utils/test/unit/computeSemverUpdateType.test.ts b/packages/utils/test/unit/computeSemverUpdateType.test.ts index dad7fada6..09e0142d9 100644 --- a/packages/utils/test/unit/computeSemverUpdateType.test.ts +++ b/packages/utils/test/unit/computeSemverUpdateType.test.ts @@ -18,14 +18,11 @@ describe("Util: computeSemverUpdateType", () => { // Incorrect from { result: null, from: "/ipfs/asudbqbwif", to: "0.1.8" }, // Incorrect to - { result: null, from: "0.2.0", to: "/ipfs/asudbqbwif" }, + { result: null, from: "0.2.0", to: "/ipfs/asudbqbwif" } ]; for (const { from, to, result } of updates) { - expect(computeSemverUpdateType(from, to)).to.equal( - result, - `from ${from} to ${to} should be ${result}` - ); + expect(computeSemverUpdateType(from, to)).to.equal(result, `from ${from} to ${to} should be ${result}`); } }); }); diff --git a/packages/utils/test/unit/coreVersionId.test.ts b/packages/utils/test/unit/coreVersionId.test.ts index 8c3413e57..1da6ca9f7 100644 --- a/packages/utils/test/unit/coreVersionId.test.ts +++ b/packages/utils/test/unit/coreVersionId.test.ts @@ -1,17 +1,13 @@ import "mocha"; import { expect } from "chai"; -import { - getCoreVersionId, - parseCoreVersionId, - isVersionIdUpdated, -} from "../../src/coreVersionId.js"; +import { getCoreVersionId, parseCoreVersionId, isVersionIdUpdated } from "../../src/coreVersionId.js"; describe("Util: coreVersionId", () => { describe("Normal cases", () => { const coreDnps: { dnpName: string; version: string }[] = [ { dnpName: "admin.dnp.dappnode.eth", version: "0.2.6" }, { dnpName: "vpn.dnp.dappnode.eth", version: "0.2.2" }, - { dnpName: "core.dnp.dappnode.eth", version: "0.2.8" }, + { dnpName: "core.dnp.dappnode.eth", version: "0.2.8" } ]; const versionId = "admin@0.2.6,core@0.2.8,vpn@0.2.2"; @@ -20,9 +16,7 @@ describe("Util: coreVersionId", () => { }); it("Should parse a versionId", async () => { - expect(parseCoreVersionId(versionId)).to.deep.equal( - coreDnps.sort((a, b) => (a.dnpName > b.dnpName ? 1 : -1)) - ); + expect(parseCoreVersionId(versionId)).to.deep.equal(coreDnps.sort((a, b) => (a.dnpName > b.dnpName ? 1 : -1))); }); }); @@ -36,7 +30,7 @@ describe("Util: coreVersionId", () => { it("Empty and null versions", async () => { const coreDnps: { dnpName: string; version: string }[] = [ { dnpName: "admin.dnp.dappnode.eth", version: "" }, - { dnpName: "core.dnp.dappnode.eth", version: "" }, + { dnpName: "core.dnp.dappnode.eth", version: "" } ]; const versionId = ""; expect(getCoreVersionId(coreDnps)).to.equal(versionId); @@ -67,23 +61,18 @@ describe("Util: coreVersionId", () => { describe("Compare a subset with a superset", () => { const corePkgsSubset = [ { dnpName: "admin.dnp.dappnode.eth", version: "0.2.0" }, - { dnpName: "core.dnp.dappnode.eth", version: "0.2.0" }, - ]; - const corePkgsSuperset = [ - ...corePkgsSubset, - { dnpName: "vpn.dnp.dappnode.eth", version: "0.2.0" }, + { dnpName: "core.dnp.dappnode.eth", version: "0.2.0" } ]; + const corePkgsSuperset = [...corePkgsSubset, { dnpName: "vpn.dnp.dappnode.eth", version: "0.2.0" }]; const versionIdSubset = getCoreVersionId(corePkgsSubset); const versionIdSuperset = getCoreVersionId(corePkgsSuperset); it("Should return true for including core version ids", () => { - expect(isVersionIdUpdated(versionIdSubset, corePkgsSuperset)).to.be - .true; + expect(isVersionIdUpdated(versionIdSubset, corePkgsSuperset)).to.be.true; }); it("Should return false for NOT including core version ids", () => { - expect(isVersionIdUpdated(versionIdSuperset, corePkgsSubset)).to.be - .false; + expect(isVersionIdUpdated(versionIdSuperset, corePkgsSubset)).to.be.false; }); }); }); diff --git a/packages/utils/test/unit/domains.test.ts b/packages/utils/test/unit/domains.test.ts index d1f08fc65..0ed9acc83 100644 --- a/packages/utils/test/unit/domains.test.ts +++ b/packages/utils/test/unit/domains.test.ts @@ -7,7 +7,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "dappmanager.dnp.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: true, + isMainOrMonoservice: true }); expect(result).to.equal("dappmanager.dappnode"); }); @@ -16,7 +16,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "dappmanager.dnp.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: false, + isMainOrMonoservice: false }); expect(result).to.equal("serviceName.dappmanager.dappnode"); }); @@ -26,7 +26,7 @@ describe("determineNetworkAlias", () => { dnpName: "dappmanager.dnp.dappnode.eth", serviceName: "serviceName", isMainOrMonoservice: true, - isExternal: true, + isExternal: true }); expect(result).to.equal("dappmanager.dappnode.external"); }); @@ -36,7 +36,7 @@ describe("determineNetworkAlias", () => { dnpName: "dappmanager.dnp.dappnode.eth", serviceName: "serviceName", isMainOrMonoservice: false, - isExternal: true, + isExternal: true }); expect(result).to.equal("serviceName.dappmanager.dappnode.external"); }); @@ -47,7 +47,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "dappmanager.public.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: true, + isMainOrMonoservice: true }); expect(result).to.equal("dappmanager.public.dappnode"); }); @@ -56,7 +56,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "dappmanager.public.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: false, + isMainOrMonoservice: false }); expect(result).to.equal("serviceName.dappmanager.public.dappnode"); }); @@ -66,7 +66,7 @@ describe("determineNetworkAlias", () => { dnpName: "dappmanager.public.dappnode.eth", serviceName: "serviceName", isMainOrMonoservice: true, - isExternal: true, + isExternal: true }); expect(result).to.equal("dappmanager.public.dappnode.external"); }); @@ -76,11 +76,9 @@ describe("determineNetworkAlias", () => { dnpName: "dappmanager.public.dappnode.eth", serviceName: "serviceName", isMainOrMonoservice: false, - isExternal: true, + isExternal: true }); - expect(result).to.equal( - "serviceName.dappmanager.public.dappnode.external" - ); + expect(result).to.equal("serviceName.dappmanager.public.dappnode.external"); }); }); @@ -89,7 +87,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "example.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: false, + isMainOrMonoservice: false }); expect(result).to.equal("serviceName.example.dappnode"); }); @@ -98,7 +96,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "example.eth", serviceName: "serviceName", - isMainOrMonoservice: false, + isMainOrMonoservice: false }); expect(result).to.equal("serviceName.example.dappnode"); }); @@ -107,7 +105,7 @@ describe("determineNetworkAlias", () => { const result = buildNetworkAlias({ dnpName: "example_name.dnp.dappnode.eth", serviceName: "serviceName", - isMainOrMonoservice: false, + isMainOrMonoservice: false }); expect(result).to.equal("serviceName.examplename.dappnode"); }); diff --git a/packages/utils/test/unit/environment.test.ts b/packages/utils/test/unit/environment.test.ts index ee15a3cbf..c463eea91 100644 --- a/packages/utils/test/unit/environment.test.ts +++ b/packages/utils/test/unit/environment.test.ts @@ -7,7 +7,7 @@ describe("environment: parse, stringify", () => { const envs = { NAME: "VALUE", NOVAL: "", - COMPLEX: "D=D=D = 2", + COMPLEX: "D=D=D = 2" }; it("Should parse an envsArray", () => { diff --git a/packages/utils/test/unit/getPath.test.ts b/packages/utils/test/unit/getPath.test.ts index f0496de99..dc47b4863 100644 --- a/packages/utils/test/unit/getPath.test.ts +++ b/packages/utils/test/unit/getPath.test.ts @@ -11,19 +11,17 @@ import { getEnvFilePath, getImagePath, getManifestPath, - getRepoDirPath, + getRepoDirPath } from "../../src/index.js"; const { REPO_DIR } = params; -describe("Util: get paths", function() { +describe("Util: get paths", function () { const dnpName = "some_package.dnp.dappnode.eth"; const version = "0.2.0"; it("return PACKAGE_REPO_DIR path", () => { - expect(getRepoDirPath(dnpName, false)).to.equal( - path.join(REPO_DIR, dnpName) - ); + expect(getRepoDirPath(dnpName, false)).to.equal(path.join(REPO_DIR, dnpName)); }); it("return MANIFEST path", () => { @@ -40,19 +38,13 @@ describe("Util: get paths", function() { it("return ENV_FILE path", () => { expect(getEnvFilePath(dnpName, false)).to.equal( - path.join( - REPO_DIR, - "some_package.dnp.dappnode.eth/some_package.dnp.dappnode.eth.env" - ) + path.join(REPO_DIR, "some_package.dnp.dappnode.eth/some_package.dnp.dappnode.eth.env") ); }); it("return IMAGE path", () => { expect(getImagePath(dnpName, version, false)).to.equal( - path.join( - REPO_DIR, - "some_package.dnp.dappnode.eth/some_package.dnp.dappnode.eth_0.2.0.tar.xz" - ) + path.join(REPO_DIR, "some_package.dnp.dappnode.eth/some_package.dnp.dappnode.eth_0.2.0.tar.xz") ); }); @@ -60,9 +52,8 @@ describe("Util: get paths", function() { const nextPaths = { "docker-compose.yml": "docker-compose.backup.yml", "DNCORE/docker-compose.yml": "DNCORE/docker-compose.backup.yml", - "/dnp_repo/my.dnp.dappnode.eth/docker-compose.yml": - "/dnp_repo/my.dnp.dappnode.eth/docker-compose.backup.yml", - "dappnode_package.json": "dappnode_package.backup.json", + "/dnp_repo/my.dnp.dappnode.eth/docker-compose.yml": "/dnp_repo/my.dnp.dappnode.eth/docker-compose.backup.yml", + "dappnode_package.json": "dappnode_package.backup.json" }; for (const [from, next] of Object.entries(nextPaths)) it(`Should return next path of ${from}`, () => { diff --git a/packages/utils/test/unit/getPrivateNetworkAliases.test.ts b/packages/utils/test/unit/getPrivateNetworkAliases.test.ts index 9b08b5214..7343a2da9 100644 --- a/packages/utils/test/unit/getPrivateNetworkAliases.test.ts +++ b/packages/utils/test/unit/getPrivateNetworkAliases.test.ts @@ -9,8 +9,8 @@ describe("getPrivateNetworkAliases", () => { "dappmanager.dnp.dappnode.eth.dappmanager.dappnode", "dappmanager.dappnode", "my.dappnode", - "dappnode.local", - ], + "dappnode.local" + ] }; it("should return an array with the full alias for any container", () => { @@ -18,32 +18,27 @@ describe("getPrivateNetworkAliases", () => { const container = { serviceName: "testService", dnpName: "testDnp", - isMainOrMonoservice: false, + isMainOrMonoservice: false }; const result = getPrivateNetworkAliases(container); - expect(result) - .to.be.an("array") - .that.includes("testService.testDnp.dappnode"); + expect(result).to.be.an("array").that.includes("testService.testDnp.dappnode"); }); it("should include the short alias for main or monoservice containers", () => { const container = { serviceName: "mainService", dnpName: "mainDnp", - isMainOrMonoservice: true, + isMainOrMonoservice: true }; const result = getPrivateNetworkAliases(container); - expect(result).to.include( - "mainService.mainDnp.dappnode", - "'mainDnp.dappnode'" - ); + expect(result).to.include("mainService.mainDnp.dappnode", "'mainDnp.dappnode'"); }); it("should not include the short alias for non-main/monoservice containers", () => { const container = { serviceName: "regularService", dnpName: "regularDnp", - isMainOrMonoservice: false, + isMainOrMonoservice: false }; const result = getPrivateNetworkAliases(container); expect(result).to.not.include("regularService"); @@ -53,7 +48,7 @@ describe("getPrivateNetworkAliases", () => { const container = { serviceName: "dappmanager.dnp.dappnode.eth", dnpName: params.dappmanagerDnpName, - isMainOrMonoservice: true, + isMainOrMonoservice: true }; const result = getPrivateNetworkAliases(container); console.log(result); @@ -65,7 +60,7 @@ describe("getPrivateNetworkAliases", () => { const container = { serviceName: "admin", dnpName: params.dappmanagerDnpName, - isMainOrMonoservice: true, + isMainOrMonoservice: true }; const result = getPrivateNetworkAliases(container); expect(result).to.have.members([...new Set(result)]); diff --git a/packages/utils/test/unit/prettyDnpName.test.ts b/packages/utils/test/unit/prettyDnpName.test.ts index 42c70d04f..2ba58163c 100644 --- a/packages/utils/test/unit/prettyDnpName.test.ts +++ b/packages/utils/test/unit/prettyDnpName.test.ts @@ -9,7 +9,7 @@ describe("Util / format", () => { "nethermind.public.dappnode.eth": "Nethermind", "prysm-beacon-chain.public.dappnode.eth": "Prysm Beacon Chain", "bitcoin.dnp.dappnode.eth": "Bitcoin", - "package0-1-2.public.dappnode.eth": "Package0 1 2", + "package0-1-2.public.dappnode.eth": "Package0 1 2" }; for (const dnpName of Object.keys(cases)) { diff --git a/yarn.lock b/yarn.lock index f723454fc..d52942abd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2428,27 +2428,6 @@ __metadata: languageName: unknown linkType: soft -"@dappnode/dappnode@workspace:.": - version: 0.0.0-use.local - resolution: "@dappnode/dappnode@workspace:." - dependencies: - "@types/chai": "npm:^4.3.11" - "@types/mocha": "npm:^10.0.6" - "@types/node": "npm:^22.2.0" - "@typescript-eslint/eslint-plugin": "npm:^5.61.0" - "@typescript-eslint/parser": "npm:^5.61.0" - chai: "npm:^4.3.10" - depcheck: "npm:^1.4.7" - eslint: "npm:^8.44.0" - eslint-config-react-app: "npm:^7.0.1" - mocha: "npm:^10.2.0" - nodemon: "npm:^3.0.2" - rimraf: "npm:^3.0.2" - tsx: "npm:^4.17.0" - typescript: "npm:^5.5.4" - languageName: unknown - linkType: soft - "@dappnode/db@workspace:^0.1.0, @dappnode/db@workspace:packages/db": version: 0.0.0-use.local resolution: "@dappnode/db@workspace:packages/db" @@ -2716,10 +2695,6 @@ __metadata: "@types/mocha": "npm:^10" "@types/node": "npm:^20.14.10" "@types/semver": "npm:^7.3.13" - "@typescript-eslint/eslint-plugin": "npm:^5.59.2" - "@typescript-eslint/parser": "npm:^5.59.5" - eslint: "npm:^8.38.0" - eslint-plugin-import: "npm:^2.27.5" esm: "npm:^3.2.25" ethers: "npm:^6.10.0" graphql: "npm:^16.6.0" @@ -2729,7 +2704,6 @@ __metadata: kubo-rpc-client: "npm:^4.1.1" mocha: "npm:^10.7.0" multiformats: "npm:^13.2.2" - prettier: "npm:^2.8.7" rimraf: "npm:^5.0.0" semver: "npm:^7.5.0" truffle: "npm:^5.9.0" @@ -3195,7 +3169,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" dependencies: @@ -3206,58 +3180,59 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.11.0": + version: 4.11.0 + resolution: "@eslint-community/regexpp@npm:4.11.0" + checksum: 10c0/0f6328869b2741e2794da4ad80beac55cba7de2d3b44f796a60955b0586212ec75e6b0253291fd4aad2100ad471d1480d8895f2b54f1605439ba4c875e05e523 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.4.0": version: 4.6.2 resolution: "@eslint-community/regexpp@npm:4.6.2" checksum: 10c0/da800788298f8419f4c4e04eaa4e3c97e7f57537e822e7b150de662e420e3d437816b863e490807bd0b00e715b0989f9d8864bf54357cbcfa84e4255b910789d languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.1": - version: 2.1.1 - resolution: "@eslint/eslintrc@npm:2.1.1" +"@eslint/config-array@npm:^0.18.0": + version: 0.18.0 + resolution: "@eslint/config-array@npm:0.18.0" dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^9.6.0" - globals: "npm:^13.19.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" + "@eslint/object-schema": "npm:^2.1.4" + debug: "npm:^4.3.1" minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/104ec8997206eabc87de84b87a2852efce0ff98730d377061734da2554c79c9b6d417fbe66248ef5566a0501ef41fddec3a00f79b77731102903586a63b2ed34 + checksum: 10c0/0234aeb3e6b052ad2402a647d0b4f8a6aa71524bafe1adad0b8db1dfe94d7f5f26d67c80f79bb37ac61361a1d4b14bb8fb475efe501de37263cf55eabb79868f languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.3": - version: 2.1.3 - resolution: "@eslint/eslintrc@npm:2.1.3" +"@eslint/eslintrc@npm:^3.1.0": + version: 3.1.0 + resolution: "@eslint/eslintrc@npm:3.1.0" dependencies: ajv: "npm:^6.12.4" debug: "npm:^4.3.2" - espree: "npm:^9.6.0" - globals: "npm:^13.19.0" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" ignore: "npm:^5.2.0" import-fresh: "npm:^3.2.1" js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: 10c0/f4103f4346126292eb15581c5a1d12bef03410fd3719dedbdb92e1f7031d46a5a2d60de8566790445d5d4b70b75ba050876799a11f5fff8265a91ee3fa77dab0 + checksum: 10c0/5b7332ed781edcfc98caa8dedbbb843abfb9bda2e86538529c843473f580e40c69eb894410eddc6702f487e9ee8f8cfa8df83213d43a8fdb549f23ce06699167 languageName: node linkType: hard -"@eslint/js@npm:8.54.0": - version: 8.54.0 - resolution: "@eslint/js@npm:8.54.0" - checksum: 10c0/d61fb4a0be6af2d8cb290121c329697664a75d6255a29926d5454fb02aeb02b87112f67fdf218d10abac42f90c570ac366126751baefc5405d0e017ed0c946c5 +"@eslint/js@npm:9.9.1": + version: 9.9.1 + resolution: "@eslint/js@npm:9.9.1" + checksum: 10c0/a3a91de2ce78469f7c4eee78c1eba77360706e1d0fa0ace2e19102079bcf237b851217c85ea501dc92c4c3719d60d9df966977abc8554d4c38e3638c1f53dcb2 languageName: node linkType: hard -"@eslint/js@npm:^8.46.0": - version: 8.46.0 - resolution: "@eslint/js@npm:8.46.0" - checksum: 10c0/674c5800e4e9829322aa84195b23c59db326cb42190ac0284bdfe70b2442d544837f3006d8d8c166afaa86ab7072df1b77f7fdb43a60aa2bb1ede90d82e38540 +"@eslint/object-schema@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/object-schema@npm:2.1.4" + checksum: 10c0/e9885532ea70e483fb007bf1275968b05bb15ebaa506d98560c41a41220d33d342e19023d5f2939fed6eb59676c1bda5c847c284b4b55fce521d282004da4dda languageName: node linkType: hard @@ -3841,28 +3816,6 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.10": - version: 0.11.10 - resolution: "@humanwhocodes/config-array@npm:0.11.10" - dependencies: - "@humanwhocodes/object-schema": "npm:^1.2.1" - debug: "npm:^4.1.1" - minimatch: "npm:^3.0.5" - checksum: 10c0/9e307a49a5baa28beb243d2c14c145f288fccd6885f4c92a9055707057ec40980242256b2a07c976cfa6c75f7081da111a40a9844d1ca8daeff2302f8b640e76 - languageName: node - linkType: hard - -"@humanwhocodes/config-array@npm:^0.11.13": - version: 0.11.13 - resolution: "@humanwhocodes/config-array@npm:0.11.13" - dependencies: - "@humanwhocodes/object-schema": "npm:^2.0.1" - debug: "npm:^4.1.1" - minimatch: "npm:^3.0.5" - checksum: 10c0/d76ca802d853366094d0e98ff0d0994117fc8eff96649cd357b15e469e428228f597cd2e929d54ab089051684949955f16ee905bb19f7b2f0446fb377157be7a - languageName: node - linkType: hard - "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -3870,17 +3823,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: 10c0/c3c35fdb70c04a569278351c75553e293ae339684ed75895edc79facc7276e351115786946658d78133130c0cca80e57e2203bc07f8fa7fe7980300e8deef7db - languageName: node - linkType: hard - -"@humanwhocodes/object-schema@npm:^2.0.1": - version: 2.0.1 - resolution: "@humanwhocodes/object-schema@npm:2.0.1" - checksum: 10c0/9dba24e59fdb4041829d92b693aacb778add3b6f612aaa9c0774f3b650c11a378cc64f042a59da85c11dae33df456580a3c36837b953541aed6ff94294f97fac +"@humanwhocodes/retry@npm:^0.3.0": + version: 0.3.0 + resolution: "@humanwhocodes/retry@npm:0.3.0" + checksum: 10c0/7111ec4e098b1a428459b4e3be5a5d2a13b02905f805a2468f4fa628d072f0de2da26a27d04f65ea2846f73ba51f4204661709f05bfccff645e3cedef8781bb6 languageName: node linkType: hard @@ -4472,6 +4418,13 @@ __metadata: languageName: node linkType: hard +"@pkgr/core@npm:^0.1.0": + version: 0.1.1 + resolution: "@pkgr/core@npm:0.1.1" + checksum: 10c0/3f7536bc7f57320ab2cf96f8973664bef624710c403357429fbf680a5c3b4843c1dbd389bb43daa6b1f6f1f007bb082f5abcb76bb2b5dc9f421647743b71d3d8 + languageName: node + linkType: hard + "@popperjs/core@npm:^2.11.6": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -6122,7 +6075,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.5.0, @typescript-eslint/eslint-plugin@npm:^5.59.2, @typescript-eslint/eslint-plugin@npm:^5.61.0": +"@typescript-eslint/eslint-plugin@npm:^5.5.0": version: 5.62.0 resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" dependencies: @@ -6146,6 +6099,29 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:^8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.3.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.3.0" + "@typescript-eslint/type-utils": "npm:8.3.0" + "@typescript-eslint/utils": "npm:8.3.0" + "@typescript-eslint/visitor-keys": "npm:8.3.0" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/d5242b16b8602ab5817cf04b35ac7208b6bee530730eeed6eab886667d1f2c5fac1537b3e33c453393090a1c6fcd50f727c07f5168985a00e7d23d1f99576988 + languageName: node + linkType: hard + "@typescript-eslint/experimental-utils@npm:^5.0.0": version: 5.62.0 resolution: "@typescript-eslint/experimental-utils@npm:5.62.0" @@ -6157,7 +6133,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.5.0, @typescript-eslint/parser@npm:^5.59.5, @typescript-eslint/parser@npm:^5.61.0": +"@typescript-eslint/parser@npm:^5.5.0": version: 5.62.0 resolution: "@typescript-eslint/parser@npm:5.62.0" dependencies: @@ -6174,6 +6150,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:^8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/parser@npm:8.3.0" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.3.0" + "@typescript-eslint/types": "npm:8.3.0" + "@typescript-eslint/typescript-estree": "npm:8.3.0" + "@typescript-eslint/visitor-keys": "npm:8.3.0" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/8185e7f1f570cded8719cfb1e8147fcbbc5b8796de628d68024d2929ce6fb02d1f6101b741161229e877be1c30c720701e1e1f7c4313dba33d4bb1190a85f705 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/scope-manager@npm:5.62.0" @@ -6184,6 +6178,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/scope-manager@npm:8.3.0" + dependencies: + "@typescript-eslint/types": "npm:8.3.0" + "@typescript-eslint/visitor-keys": "npm:8.3.0" + checksum: 10c0/24d093505d444a07db88f9ab44af04eb738ce523ac3f98b0a641cf3a3ee38d18aff9f72bbf2b2e2d9f45e57c973f31016f1e224cd8ab773f6e7c3477c5a09ad3 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/type-utils@npm:5.62.0" @@ -6201,6 +6205,21 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/type-utils@npm:8.3.0" + dependencies: + "@typescript-eslint/typescript-estree": "npm:8.3.0" + "@typescript-eslint/utils": "npm:8.3.0" + debug: "npm:^4.3.4" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0e4b42ff2bfcd1727893bb7fe5fcf1aa808b45b5f690c249c68ce7aff68ddfba3d8b1565de2f08972915df23fa7ab114c09f507668e9b0b63faf1e34a5091706 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/types@npm:5.62.0" @@ -6208,6 +6227,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/types@npm:8.3.0" + checksum: 10c0/5cd733af7ffa0cdaa5842f6c5e275b3a5c9b98dc49bf1bb9df1f0b51d346bef2a10a827d886f60492d502218a272e935cef50b4f7c69100217d5b10a2499c7b1 + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" @@ -6226,6 +6252,25 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.3.0" + dependencies: + "@typescript-eslint/types": "npm:8.3.0" + "@typescript-eslint/visitor-keys": "npm:8.3.0" + debug: "npm:^4.3.4" + fast-glob: "npm:^3.3.2" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/dd73aa1a9d7b5c7e6238e766e6ecdb6d87a9b28a24815258b7bbdc59c49fb525d3fe15d9b7c672e2220678f9d5fabdd9615e4cd5ee97a102fd46023ec0735d50 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.58.0": version: 5.62.0 resolution: "@typescript-eslint/utils@npm:5.62.0" @@ -6244,6 +6289,20 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/utils@npm:8.3.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.3.0" + "@typescript-eslint/types": "npm:8.3.0" + "@typescript-eslint/typescript-estree": "npm:8.3.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + checksum: 10c0/e4e9e820cf4b4775bb66b2293a2a827897edaba88577b63df317b50752a01d542be521cc4842976fbbd93e08b9e273ce9d20e23768d06de68a83d68cc0f68a93 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" @@ -6254,10 +6313,13 @@ __metadata: languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.2.0": - version: 1.2.0 - resolution: "@ungap/structured-clone@npm:1.2.0" - checksum: 10c0/8209c937cb39119f44eb63cf90c0b73e7c754209a6411c707be08e50e29ee81356dca1a848a405c8bdeebfe2f5e4f831ad310ae1689eeef65e7445c090c6657d +"@typescript-eslint/visitor-keys@npm:8.3.0": + version: 8.3.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.3.0" + dependencies: + "@typescript-eslint/types": "npm:8.3.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10c0/4c19216636f2cc25026fe20d2832d857f05c262eba78bc4159121c696199e44cac68443565959f9336372f7686a14b452867300cf4deb3c0507b8dbde88ac0e6 languageName: node linkType: hard @@ -6488,7 +6550,16 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.4.1, acorn@npm:^8.9.0": +"acorn@npm:^8.12.0": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" + bin: + acorn: bin/acorn + checksum: 10c0/51fb26cd678f914e13287e886da2d7021f8c2bc0ccc95e03d3e0447ee278dd3b40b9c57dc222acd5881adcf26f3edc40901a4953403232129e3876793cd17386 + languageName: node + linkType: hard + +"acorn@npm:^8.4.1": version: 8.10.0 resolution: "acorn@npm:8.10.0" bin: @@ -9157,15 +9228,6 @@ __metadata: languageName: node linkType: hard -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 - languageName: node - linkType: hard - "dom-helpers@npm:^3.4.0": version: 3.4.0 resolution: "dom-helpers@npm:3.4.0" @@ -9839,6 +9901,17 @@ __metadata: languageName: node linkType: hard +"eslint-config-prettier@npm:^9.1.0": + version: 9.1.0 + resolution: "eslint-config-prettier@npm:9.1.0" + peerDependencies: + eslint: ">=7.0.0" + bin: + eslint-config-prettier: bin/cli.js + checksum: 10c0/6d332694b36bc9ac6fdb18d3ca2f6ac42afa2ad61f0493e89226950a7091e38981b66bac2b47ba39d15b73fff2cd32c78b850a9cf9eed9ca9a96bfb2f3a2f10d + languageName: node + linkType: hard + "eslint-config-react-app@npm:^7.0.1": version: 7.0.1 resolution: "eslint-config-react-app@npm:7.0.1" @@ -9897,6 +9970,18 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-es@npm:^3.0.0": + version: 3.0.1 + resolution: "eslint-plugin-es@npm:3.0.1" + dependencies: + eslint-utils: "npm:^2.0.0" + regexpp: "npm:^3.0.0" + peerDependencies: + eslint: ">=4.19.1" + checksum: 10c0/12ae730aa9603e680af048e1653aac15e529411b68b8d0da6e290700b17c695485af7c3f5360f531f80970786cab7288c2c1d4a58c35ec1bb89649897c016c4a + languageName: node + linkType: hard + "eslint-plugin-flowtype@npm:^8.0.3": version: 8.0.3 resolution: "eslint-plugin-flowtype@npm:8.0.3" @@ -9939,9 +10024,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.27.5": - version: 2.29.0 - resolution: "eslint-plugin-import@npm:2.29.0" +"eslint-plugin-import@npm:^2.29.1": + version: 2.29.1 + resolution: "eslint-plugin-import@npm:2.29.1" dependencies: array-includes: "npm:^3.1.7" array.prototype.findlastindex: "npm:^1.2.3" @@ -9959,10 +10044,10 @@ __metadata: object.groupby: "npm:^1.0.1" object.values: "npm:^1.1.7" semver: "npm:^6.3.1" - tsconfig-paths: "npm:^3.14.2" + tsconfig-paths: "npm:^3.15.0" peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: 10c0/761a4e1fbc2cd318e62350bed4c448f8b11ed83091d6bb7776f096556363a09debd9922b39fd2714c895edc9aaea82e08e684eb632283f880c58a91e4bae6733 + checksum: 10c0/5f35dfbf4e8e67f741f396987de9504ad125c49f4144508a93282b4ea0127e052bde65ab6def1f31b6ace6d5d430be698333f75bdd7dca3bc14226c92a083196 languageName: node linkType: hard @@ -10009,6 +10094,51 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-node@npm:^11.1.0": + version: 11.1.0 + resolution: "eslint-plugin-node@npm:11.1.0" + dependencies: + eslint-plugin-es: "npm:^3.0.0" + eslint-utils: "npm:^2.0.0" + ignore: "npm:^5.1.1" + minimatch: "npm:^3.0.4" + resolve: "npm:^1.10.1" + semver: "npm:^6.1.0" + peerDependencies: + eslint: ">=5.16.0" + checksum: 10c0/c7716adac4020cb852fd2410dcd8bdb13a227004de77f96d7f9806d0cf2274f24e0920a7ca73bcd72d90003696c1f17fdd9fe3ca218e64ee03dc2b840e4416fa + languageName: node + linkType: hard + +"eslint-plugin-prettier@npm:^5.2.1": + version: 5.2.1 + resolution: "eslint-plugin-prettier@npm:5.2.1" + dependencies: + prettier-linter-helpers: "npm:^1.0.0" + synckit: "npm:^0.9.1" + peerDependencies: + "@types/eslint": ">=8.0.0" + eslint: ">=8.0.0" + eslint-config-prettier: "*" + prettier: ">=3.0.0" + peerDependenciesMeta: + "@types/eslint": + optional: true + eslint-config-prettier: + optional: true + checksum: 10c0/4bc8bbaf5bb556c9c501dcdff369137763c49ccaf544f9fa91400360ed5e3a3f1234ab59690e06beca5b1b7e6f6356978cdd3b02af6aba3edea2ffe69ca6e8b2 + languageName: node + linkType: hard + +"eslint-plugin-promise@npm:^7.1.0": + version: 7.1.0 + resolution: "eslint-plugin-promise@npm:7.1.0" + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + checksum: 10c0/bbc3406139715dfa5f48d04f6d5b5e82f68929d954b0fa3821eb8cd6dc381b210512cedd2d874e5de5381005d316566f4ae046a4750ce3f5f5cbf28a14cc0ab2 + languageName: node + linkType: hard + "eslint-plugin-react-hooks@npm:^4.3.0": version: 4.6.0 resolution: "eslint-plugin-react-hooks@npm:4.6.0" @@ -10064,13 +10194,29 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.2.2": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" +"eslint-scope@npm:^8.0.2": + version: 8.0.2 + resolution: "eslint-scope@npm:8.0.2" dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" - checksum: 10c0/613c267aea34b5a6d6c00514e8545ef1f1433108097e857225fed40d397dd6b1809dffd11c2fde23b37ca53d7bf935fe04d2a18e6fc932b31837b6ad67e1c116 + checksum: 10c0/477f820647c8755229da913025b4567347fd1f0bf7cbdf3a256efff26a7e2e130433df052bd9e3d014025423dc00489bea47eb341002b15553673379c1a7dc36 + languageName: node + linkType: hard + +"eslint-utils@npm:^2.0.0": + version: 2.1.0 + resolution: "eslint-utils@npm:2.1.0" + dependencies: + eslint-visitor-keys: "npm:^1.1.0" + checksum: 10c0/69521c5d6569384b24093125d037ba238d3d6e54367f7143af9928f5286369e912c26cad5016d730c0ffb9797ac9e83831059d7f1d863f7dc84330eb02414611 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^1.1.0": + version: 1.3.0 + resolution: "eslint-visitor-keys@npm:1.3.0" + checksum: 10c0/10c91fdbbe36810dd4308e57f9a8bc7177188b2a70247e54e3af1fa05ebc66414ae6fd4ce3c6c6821591f43a556e9037bc6b071122e099b5f8b7d2f76df553e3 languageName: node linkType: hard @@ -10081,7 +10227,7 @@ __metadata: languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.2": +"eslint-visitor-keys@npm:^3.3.0": version: 3.4.2 resolution: "eslint-visitor-keys@npm:3.4.2" checksum: 10c0/4521d1d470490c89fb613aec6fb2f0814b496a4618619ec8dfcc985640fe33c9c64f3dab882f50ebb401b4613f35f2601a9ef9a72b57739af5b0150fecdaf1f1 @@ -10095,87 +10241,43 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.38.0": - version: 8.54.0 - resolution: "eslint@npm:8.54.0" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.2.0" - "@eslint-community/regexpp": "npm:^4.6.1" - "@eslint/eslintrc": "npm:^2.1.3" - "@eslint/js": "npm:8.54.0" - "@humanwhocodes/config-array": "npm:^0.11.13" - "@humanwhocodes/module-importer": "npm:^1.0.1" - "@nodelib/fs.walk": "npm:^1.2.8" - "@ungap/structured-clone": "npm:^1.2.0" - ajv: "npm:^6.12.4" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.2" - debug: "npm:^4.3.2" - doctrine: "npm:^3.0.0" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^7.2.2" - eslint-visitor-keys: "npm:^3.4.3" - espree: "npm:^9.6.1" - esquery: "npm:^1.4.2" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" - find-up: "npm:^5.0.0" - glob-parent: "npm:^6.0.2" - globals: "npm:^13.19.0" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - is-path-inside: "npm:^3.0.3" - js-yaml: "npm:^4.1.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.3" - strip-ansi: "npm:^6.0.1" - text-table: "npm:^0.2.0" - bin: - eslint: bin/eslint.js - checksum: 10c0/4f205f832bdbd0218cde374b067791f4f76d7abe8de86b2dc849c273899051126d912ebf71531ee49b8eeaa22cad77febdc8f2876698dc2a76e84a8cb976af22 +"eslint-visitor-keys@npm:^4.0.0": + version: 4.0.0 + resolution: "eslint-visitor-keys@npm:4.0.0" + checksum: 10c0/76619f42cf162705a1515a6868e6fc7567e185c7063a05621a8ac4c3b850d022661262c21d9f1fc1d144ecf0d5d64d70a3f43c15c3fc969a61ace0fb25698cf5 languageName: node linkType: hard -"eslint@npm:^8.44.0": - version: 8.46.0 - resolution: "eslint@npm:8.46.0" +"eslint@npm:^9.9.1": + version: 9.9.1 + resolution: "eslint@npm:9.9.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" - "@eslint-community/regexpp": "npm:^4.6.1" - "@eslint/eslintrc": "npm:^2.1.1" - "@eslint/js": "npm:^8.46.0" - "@humanwhocodes/config-array": "npm:^0.11.10" + "@eslint-community/regexpp": "npm:^4.11.0" + "@eslint/config-array": "npm:^0.18.0" + "@eslint/eslintrc": "npm:^3.1.0" + "@eslint/js": "npm:9.9.1" "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.3.0" "@nodelib/fs.walk": "npm:^1.2.8" ajv: "npm:^6.12.4" chalk: "npm:^4.0.0" cross-spawn: "npm:^7.0.2" debug: "npm:^4.3.2" - doctrine: "npm:^3.0.0" escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^7.2.2" - eslint-visitor-keys: "npm:^3.4.2" - espree: "npm:^9.6.1" - esquery: "npm:^1.4.2" + eslint-scope: "npm:^8.0.2" + eslint-visitor-keys: "npm:^4.0.0" + espree: "npm:^10.1.0" + esquery: "npm:^1.5.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" + file-entry-cache: "npm:^8.0.0" find-up: "npm:^5.0.0" glob-parent: "npm:^6.0.2" - globals: "npm:^13.19.0" - graphemer: "npm:^1.4.0" ignore: "npm:^5.2.0" imurmurhash: "npm:^0.1.4" is-glob: "npm:^4.0.0" is-path-inside: "npm:^3.0.3" - js-yaml: "npm:^4.1.0" json-stable-stringify-without-jsonify: "npm:^1.0.1" levn: "npm:^0.4.1" lodash.merge: "npm:^4.6.2" @@ -10184,9 +10286,14 @@ __metadata: optionator: "npm:^0.9.3" strip-ansi: "npm:^6.0.1" text-table: "npm:^0.2.0" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true bin: eslint: bin/eslint.js - checksum: 10c0/81abddb21e540dcd509ba08fdf524b494cbda69a62ffce2a61b5adfcdeb3cbf713f72c6cbb42932333decb4b067ae7a89e4cb5e908e0d42e4287d4f357576a72 + checksum: 10c0/5e71efda7c0a14ee95436d5cdfed04ee61dfb1d89d7a32b50a424de2e680af82849628ea6581950c2e0726491f786a3cfd0032ce013c1c5093786e475cfdfb33 languageName: node linkType: hard @@ -10197,14 +10304,14 @@ __metadata: languageName: node linkType: hard -"espree@npm:^9.6.0, espree@npm:^9.6.1": - version: 9.6.1 - resolution: "espree@npm:9.6.1" +"espree@npm:^10.0.1, espree@npm:^10.1.0": + version: 10.1.0 + resolution: "espree@npm:10.1.0" dependencies: - acorn: "npm:^8.9.0" + acorn: "npm:^8.12.0" acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10c0/1a2e9b4699b715347f62330bcc76aee224390c28bb02b31a3752e9d07549c473f5f986720483c6469cf3cfb3c9d05df612ffc69eb1ee94b54b739e67de9bb460 + eslint-visitor-keys: "npm:^4.0.0" + checksum: 10c0/52e6feaa77a31a6038f0c0e3fce93010a4625701925b0715cd54a2ae190b3275053a0717db698697b32653788ac04845e489d6773b508d6c2e8752f3c57470a0 languageName: node linkType: hard @@ -10218,12 +10325,12 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.2": - version: 1.5.0 - resolution: "esquery@npm:1.5.0" +"esquery@npm:^1.5.0": + version: 1.6.0 + resolution: "esquery@npm:1.6.0" dependencies: estraverse: "npm:^5.1.0" - checksum: 10c0/a084bd049d954cc88ac69df30534043fb2aee5555b56246493f42f27d1e168f00d9e5d4192e46f10290d312dc30dc7d58994d61a609c579c1219d636996f9213 + checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 languageName: node linkType: hard @@ -10648,6 +10755,13 @@ __metadata: languageName: node linkType: hard +"fast-diff@npm:^1.1.2": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 + languageName: node + linkType: hard + "fast-fifo@npm:^1.0.0": version: 1.3.0 resolution: "fast-fifo@npm:1.3.0" @@ -10668,6 +10782,19 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:^3.3.2": + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10c0/42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845 + languageName: node + linkType: hard + "fast-json-stable-stringify@npm:^2.0.0, fast-json-stable-stringify@npm:^2.1.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" @@ -10710,12 +10837,12 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10c0/58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd + flat-cache: "npm:^4.0.0" + checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 languageName: node linkType: hard @@ -10800,13 +10927,13 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" dependencies: - flatted: "npm:^3.1.0" - rimraf: "npm:^3.0.2" - checksum: 10c0/f274dcbadb09ad8d7b6edf2ee9b034bc40bf0c12638f6c4084e9f1d39208cb104a5ebbb24b398880ef048200eaa116852f73d2d8b72e8c9627aba8c3e27ca057 + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.4" + checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc languageName: node linkType: hard @@ -10819,10 +10946,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.1.0": - version: 3.2.7 - resolution: "flatted@npm:3.2.7" - checksum: 10c0/207a87c7abfc1ea6928ea16bac84f9eaa6d44d365620ece419e5c41cf44a5e9902b4c1f59c9605771b10e4565a0cb46e99d78e0464e8aabb42c97de880642257 +"flatted@npm:^3.2.9": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf languageName: node linkType: hard @@ -11392,12 +11519,10 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10c0/9a028f136f1e7a3574689f430f7d57faa0d699c4c7e92ade00b02882a892be31c314d50dff07b48e607283013117bb8a997406d03a1f7ab4a33a005eb16efd6c +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d languageName: node linkType: hard @@ -11893,6 +12018,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.1.1, ignore@npm:^5.3.1": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + "ignore@npm:^5.2.0": version: 5.2.4 resolution: "ignore@npm:5.2.4" @@ -13240,7 +13372,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.0.0": +"keyv@npm:^4.0.0, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -14369,7 +14501,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -16245,6 +16377,15 @@ __metadata: languageName: node linkType: hard +"prettier-linter-helpers@npm:^1.0.0": + version: 1.0.0 + resolution: "prettier-linter-helpers@npm:1.0.0" + dependencies: + fast-diff: "npm:^1.1.2" + checksum: 10c0/81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab + languageName: node + linkType: hard + "prettier@npm:^1.16.4": version: 1.19.1 resolution: "prettier@npm:1.19.1" @@ -16254,7 +16395,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.3.2, prettier@npm:^2.8.7": +"prettier@npm:^2.3.2": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -16263,6 +16404,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.3.3": + version: 3.3.3 + resolution: "prettier@npm:3.3.3" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/b85828b08e7505716324e4245549b9205c0cacb25342a030ba8885aba2039a115dbcf75a0b7ca3b37bc9d101ee61fab8113fc69ca3359f2a226f1ecc07ad2e26 + languageName: node + linkType: hard + "pretty-bytes@npm:^5.3.0": version: 5.6.0 resolution: "pretty-bytes@npm:5.6.0" @@ -17090,6 +17240,13 @@ __metadata: languageName: node linkType: hard +"regexpp@npm:^3.0.0": + version: 3.2.0 + resolution: "regexpp@npm:3.2.0" + checksum: 10c0/d1da82385c8754a1681416b90b9cca0e21b4a2babef159099b88f640637d789c69011d0bc94705dacab85b81133e929d027d85210e8b8b03f8035164dbc14710 + languageName: node + linkType: hard + "regexpu-core@npm:^5.3.1": version: 5.3.2 resolution: "regexpu-core@npm:5.3.2" @@ -17288,29 +17445,29 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.22.3": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" +"resolve@npm:^1.10.1, resolve@npm:^1.22.4": + version: 1.22.8 + resolution: "resolve@npm:1.22.8" dependencies: - is-core-module: "npm:^2.12.0" + is-core-module: "npm:^2.13.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10c0/5ebd90dc08467e7d9af8f89a67f127c90d77e58d3bfc65da5221699cc15679c5bae5e410e6795ee4b9f717cd711c495a52a3b650ce6720b0626de46e5074e796 + checksum: 10c0/07e179f4375e1fd072cfb72ad66d78547f86e6196c4014b31cb0b8bb1db5f7ca871f922d08da0fbc05b94e9fd42206f819648fa3b5b873ebbc8e1dc68fec433a languageName: node linkType: hard -"resolve@npm:^1.22.4": - version: 1.22.8 - resolution: "resolve@npm:1.22.8" +"resolve@npm:^1.22.3": + version: 1.22.3 + resolution: "resolve@npm:1.22.3" dependencies: - is-core-module: "npm:^2.13.0" + is-core-module: "npm:^2.12.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10c0/07e179f4375e1fd072cfb72ad66d78547f86e6196c4014b31cb0b8bb1db5f7ca871f922d08da0fbc05b94e9fd42206f819648fa3b5b873ebbc8e1dc68fec433a + checksum: 10c0/5ebd90dc08467e7d9af8f89a67f127c90d77e58d3bfc65da5221699cc15679c5bae5e410e6795ee4b9f717cd711c495a52a3b650ce6720b0626de46e5074e796 languageName: node linkType: hard @@ -17340,29 +17497,29 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.22.3#optional!builtin<compat/resolve>": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#optional!builtin<compat/resolve>::version=1.22.3&hash=c3c19d" +"resolve@patch:resolve@npm%3A^1.10.1#optional!builtin<compat/resolve>, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d" dependencies: - is-core-module: "npm:^2.12.0" + is-core-module: "npm:^2.13.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10c0/6267bdbbbb1da23975463e979dadf5135fcc40c4b9281c5af4581afa848ced98090ab4e2dbc9085e58f8ea48c0eb7c4fe94b1e8f55ebdd17a725d86982eb5288 + checksum: 10c0/0446f024439cd2e50c6c8fa8ba77eaa8370b4180f401a96abf3d1ebc770ac51c1955e12764cde449fde3fff480a61f84388e3505ecdbab778f4bef5f8212c729 languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin<compat/resolve>": - version: 1.22.8 - resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d" +"resolve@patch:resolve@npm%3A^1.22.3#optional!builtin<compat/resolve>": + version: 1.22.3 + resolution: "resolve@patch:resolve@npm%3A1.22.3#optional!builtin<compat/resolve>::version=1.22.3&hash=c3c19d" dependencies: - is-core-module: "npm:^2.13.0" + is-core-module: "npm:^2.12.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10c0/0446f024439cd2e50c6c8fa8ba77eaa8370b4180f401a96abf3d1ebc770ac51c1955e12764cde449fde3fff480a61f84388e3505ecdbab778f4bef5f8212c729 + checksum: 10c0/6267bdbbbb1da23975463e979dadf5135fcc40c4b9281c5af4581afa848ced98090ab4e2dbc9085e58f8ea48c0eb7c4fe94b1e8f55ebdd17a725d86982eb5288 languageName: node linkType: hard @@ -17582,6 +17739,34 @@ __metadata: languageName: node linkType: hard +"root@workspace:.": + version: 0.0.0-use.local + resolution: "root@workspace:." + dependencies: + "@eslint/eslintrc": "npm:^3.1.0" + "@types/chai": "npm:^4.3.11" + "@types/mocha": "npm:^10.0.6" + "@types/node": "npm:^22.2.0" + "@typescript-eslint/eslint-plugin": "npm:^8.3.0" + "@typescript-eslint/parser": "npm:^8.3.0" + chai: "npm:^4.3.10" + depcheck: "npm:^1.4.7" + eslint: "npm:^9.9.1" + eslint-config-prettier: "npm:^9.1.0" + eslint-config-react-app: "npm:^7.0.1" + eslint-plugin-import: "npm:^2.29.1" + eslint-plugin-node: "npm:^11.1.0" + eslint-plugin-prettier: "npm:^5.2.1" + eslint-plugin-promise: "npm:^7.1.0" + mocha: "npm:^10.2.0" + nodemon: "npm:^3.0.2" + prettier: "npm:^3.3.3" + rimraf: "npm:^3.0.2" + tsx: "npm:^4.17.0" + typescript: "npm:^5.5.4" + languageName: unknown + linkType: soft + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -17752,7 +17937,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.3.0, semver@npm:^6.3.1": +"semver@npm:^6.1.0, semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -17772,6 +17957,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.6.0": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf + languageName: node + linkType: hard + "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -18724,6 +18918,16 @@ __metadata: languageName: node linkType: hard +"synckit@npm:^0.9.1": + version: 0.9.1 + resolution: "synckit@npm:0.9.1" + dependencies: + "@pkgr/core": "npm:^0.1.0" + tslib: "npm:^2.6.2" + checksum: 10c0/d8b89e1bf30ba3ffb469d8418c836ad9c0c062bf47028406b4d06548bc66af97155ea2303b96c93bf5c7c0f0d66153a6fbd6924c76521b434e6a9898982abc2e + languageName: node + linkType: hard + "systeminformation@npm:*, systeminformation@npm:^5.21.24": version: 5.21.24 resolution: "systeminformation@npm:5.21.24" @@ -19032,6 +19236,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^1.3.0": + version: 1.3.0 + resolution: "ts-api-utils@npm:1.3.0" + peerDependencies: + typescript: ">=4.2.0" + checksum: 10c0/f54a0ba9ed56ce66baea90a3fa087a484002e807f28a8ccb2d070c75e76bde64bd0f6dce98b3802834156306050871b67eec325cb4e918015a360a3f0868c77c + languageName: node + linkType: hard + "ts-loader@npm:^9.4.2": version: 9.5.1 resolution: "ts-loader@npm:9.5.1" @@ -19150,6 +19363,18 @@ __metadata: languageName: node linkType: hard +"tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" + dependencies: + "@types/json5": "npm:^0.0.29" + json5: "npm:^1.0.2" + minimist: "npm:^1.2.6" + strip-bom: "npm:^3.0.0" + checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 + languageName: node + linkType: hard + "tsconfig-paths@npm:^4.2.0": version: 4.2.0 resolution: "tsconfig-paths@npm:4.2.0" @@ -19182,6 +19407,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.6.2": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 + languageName: node + linkType: hard + "tslib@npm:~2.4.0": version: 2.4.1 resolution: "tslib@npm:2.4.1" @@ -19262,13 +19494,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 10c0/dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3 - languageName: node - linkType: hard - "type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18"