diff --git a/build/build.js b/build/build.js new file mode 100644 index 00000000..c84c7bb2 --- /dev/null +++ b/build/build.js @@ -0,0 +1,123 @@ +// @ts-check +import builder from "electron-builder" +import { notarize } from "./notarize.js" + +const args = process.argv.slice(2) + +// Detect channel + +if (!args.includes("--stable") && !args.includes("--prerelease")) { + throw new TypeError(`Missing channel argument (either "--stable" or "--prerelease")`) +} + +const isPrerelease = args.includes("--prerelease") + +console.log(`Detected channel: ${isPrerelease ? "prerelease" : "stable"}`) + +// Detect OS + +let osKey +let osName + +if (process.argv.includes("--linux") || process.platform === "linux") { + osKey = /** @type {const} */ ("LINUX") + osName = "Linux" +} else if (process.argv.includes("--mac") || process.platform === "darwin") { + osKey = /** @type {const} */ ("MAC") + osName = "macOS" +} else if (process.argv.includes("--win") || process.platform === "win32") { + osKey = /** @type {const} */ ("WINDOWS") + osName = "Windows" +} else { + throw new TypeError(`The target operating system cannot be inferred from the environment.`) +} + +console.log(`Detected operating system: ${osName}`) + +// Prepare electron-builder configuration + +/** + * @type {import("electron-builder").Configuration} + */ +const config = { + appId: isPrerelease ? "com.lukasobermann.optolithinsider" : "com.lukasobermann.optolith", + productName: isPrerelease ? "Optolith Insider" : "Optolith", + copyright: + "© 2017–present Lukas Obermann. This product was created under a license. Das Schwarze Auge and its logo as well as Aventuria, Dere, Myranor, Riesland, Tharun and Uthuria and their logos are trademarks of Significant GbR. The title and contents of this book are protected under the copyright laws of the United States of America. No part of this publication may be reproduced, stored in retrieval systems or transmitted, in any form or by any means, whether electronic, mechanical, photocopy, recording, or otherwise, without prior written consent by Ulisses Spiele GmbH, Waldems. This publication includes material that is protected under copyright laws by Ulisses Spiele and/or other authors. Such material is used under the Community Content Agreement for the SCRIPTORIUM AVENTURIS. All other original materials in this work is copyright 2017-present by Lukas Obermann and published under the Community Content Agreement for the SCRIPTORIUM AVENTURIS.", + files: [ + ".webpack/**", + "LICENSE", + "node_modules/optolith-database-schema/schema/**", + "src/database/contents/cache/**", + "src/database/contents/Compatibility/**", + "src/database/contents/Data/**", + ], + asar: false, // otherwise optolith-database-schema package is not properly resolved + asarUnpack: [ + "node_modules/optolith-character-schema/**", + "node_modules/optolith-database-schema/**", + "src/database/contents/**", + ], + directories: { + output: isPrerelease ? "dist/insider" : "dist", + }, + win: { + target: [ + { + target: "nsis", + arch: ["x64", "ia32"], + }, + ], + icon: isPrerelease ? "src/assets/icon/AppList.targetsize-512.pre.png" : "src/assets/icon/icon.ico", + artifactName: isPrerelease ? "OptolithInsiderSetup_${version}.${ext}" : "OptolithSetup_${version}.${ext}", + }, + nsis: { + perMachine: true, + differentialPackage: true, + deleteAppDataOnUninstall: false, + }, + linux: { + category: "RolePlaying", + target: [ + { + target: "AppImage", + arch: ["x64"], + }, + { + target: "tar.gz", + arch: ["x64"], + }, + ], + executableName: isPrerelease ? "OptolithInsider" : "Optolith", + icon: isPrerelease ? "src/assets/icon/icon.pre.png" : "src/assets/icon/AppList.targetsize-512.png", + artifactName: isPrerelease ? "OptolithInsider_${version}.${ext}" : "Optolith_${version}.${ext}", + }, + mac: { + category: "public.app-category.role-playing-games", + type: "distribution", + target: [ + { + target: "default", + arch: "universal", + }, + ], + icon: isPrerelease ? "src/assets/icon/AppIcon.pre.icns" : "src/assets/icon/AppIcon.icns", + artifactName: isPrerelease ? "OptolithInsider_${version}.${ext}" : "Optolith_${version}.${ext}", + mergeASARs: false, + darkModeSupport: true, + gatekeeperAssess: true, + }, + publish: { + provider: "generic", + url: isPrerelease ? `${process.env.UPDATE_URL}/insider/\${os}` : `${process.env.UPDATE_URL}/\${os}`, + channel: "latest", + }, + afterSign: osKey === "MAC" ? notarize : undefined, +} + +await builder.build({ + config, + targets: builder.Platform[osKey].createTarget(), +}) + +console.log(`Build finished successfully.`) diff --git a/deploy/entitlements.mac.plist b/build/entitlements.mac.inherit.plist similarity index 100% rename from deploy/entitlements.mac.plist rename to build/entitlements.mac.inherit.plist diff --git a/build/entitlements.mac.plist b/build/entitlements.mac.plist new file mode 100644 index 00000000..9b6c3eb6 --- /dev/null +++ b/build/entitlements.mac.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.debugger + + + diff --git a/deploy/notarize.js b/build/notarize.js similarity index 60% rename from deploy/notarize.js rename to build/notarize.js index 02e9980c..9dc32c89 100644 --- a/deploy/notarize.js +++ b/build/notarize.js @@ -1,16 +1,22 @@ // @ts-check -import { notarize as electronNotarize } from '@electron/notarize' +import { notarize as electronNotarize } from "@electron/notarize" /** + * Notarizes the app package after it has been built. It detects the + * authentication method from the environment variables. * @param context {import("electron-builder").AfterPackContext} */ -export const notarize = async (context) => { +export const notarize = async context => { const { electronPlatformName, appOutDir } = context - if (electronPlatformName === 'darwin') { + if (electronPlatformName === "darwin") { const appName = context.packager.appInfo.productFilename - if (typeof process.env.APPLEID === "string" && typeof process.env.APPLEIDPASS === "string" && typeof process.env.TEAMID === "string") { + if ( + typeof process.env.APPLEID === "string" && + typeof process.env.APPLEIDPASS === "string" && + typeof process.env.TEAMID === "string" + ) { console.log(`Notarizing "${appName}.app" via Apple ID ...`) await electronNotarize({ tool: "notarytool", @@ -20,7 +26,11 @@ export const notarize = async (context) => { teamId: process.env.TEAMID, }) console.log(`Notarization successful`) - } else if (typeof process.env.APPLEAPIKEY === "string" && typeof process.env.APPLEAPIKEYID === "string" && typeof process.env.APPLEAPIISSUER === "string") { + } else if ( + typeof process.env.APPLEAPIKEY === "string" && + typeof process.env.APPLEAPIKEYID === "string" && + typeof process.env.APPLEAPIISSUER === "string" + ) { console.log(`Notarizing "${appName}.app" via App Store Connect API ...`) await electronNotarize({ tool: "notarytool", @@ -40,7 +50,9 @@ export const notarize = async (context) => { }) console.log(`Notarization successful`) } else { - throw new Error(`Notarization failed: No valid authentication method found in environment. Please provide either APPLEID and APPLEIDPASS, or APPLEAPIKEY, APPLEAPIKEYID and APPLEAPIISSUER, or (optional) KEYCHAIN and KEYCHAINPROFILE.`) + throw new Error( + `Notarization failed: No valid authentication method found in environment. Please provide either APPLEID and APPLEIDPASS, or APPLEAPIKEY, APPLEAPIKEYID and APPLEAPIISSUER, or (optional) KEYCHAIN and KEYCHAINPROFILE.`, + ) } } } diff --git a/deploy/assetNames.js b/deploy/assetNames.js deleted file mode 100644 index 0305c502..00000000 --- a/deploy/assetNames.js +++ /dev/null @@ -1,52 +0,0 @@ -// @ts-check -/** - * @param {"prerelease" | "stable"} channel - */ -const channelSuffix = channel => { - switch (channel) { - case "prerelease": return "Insider" - case "stable": return "" - } -} - -/** - * @param {import("./platform.js").System} os - * @param {"prerelease" | "stable"} channel - */ -const prefix = (os, channel) => { - switch (os) { - case "win": return `Optolith${channelSuffix(channel)}Setup` - case "linux": - case "mac": return `Optolith${channelSuffix(channel)}` - } -} - -/** - * @param {import("./platform.js").System} os - */ -const extensions = os => { - switch (os) { - case "win": return [".exe", ".exe.blockmap"] - case "linux": return [".AppImage", ".tar.gz"] - case "mac": return [".dmg", ".dmg.blockmap", ".zip", ".zip.blockmap"] - } -} - -/** - * @param {import("./platform.js").System} os - * @param {"prerelease" | "stable"} channel - * @param {string} version - */ -export const getApplicationFileNames = (os, channel, version) => - extensions(os).map(ext => `${prefix(os, channel)}_${version}${ext}`) - -/** - * @param {"win" | "mac" | "linux"} os - */ -export const getUpdateFileName = os => { - switch (os) { - case "win": return "latest.yml" - case "linux": return "latest-linux.yml" - default: return "latest-mac.yml" - } -} diff --git a/deploy/build.base.config.js b/deploy/build.base.config.js deleted file mode 100644 index 9cb008e6..00000000 --- a/deploy/build.base.config.js +++ /dev/null @@ -1,70 +0,0 @@ -// @ts-check -import { notarize } from "./notarize.js" - -/** - * @type {import("electron-builder").Configuration} - */ -export const baseConfig = { - copyright: - "© 2017–present Lukas Obermann. This product was created under a license. Das Schwarze Auge and its logo as well as Aventuria, Dere, Myranor, Riesland, Tharun and Uthuria and their logos are trademarks of Significant GbR. The title and contents of this book are protected under the copyright laws of the United States of America. No part of this publication may be reproduced, stored in retrieval systems or transmitted, in any form or by any means, whether electronic, mechanical, photocopy, recording, or otherwise, without prior written consent by Ulisses Spiele GmbH, Waldems. This publication includes material that is protected under copyright laws by Ulisses Spiele and/or other authors. Such material is used under the Community Content Agreement for the SCRIPTORIUM AVENTURIS. All other original materials in this work is copyright 2017-present by Lukas Obermann and published under the Community Content Agreement for the SCRIPTORIUM AVENTURIS.", - files: [ - ".webpack/**", - "LICENSE", - "node_modules/optolith-database-schema/schema/**", - "src/database/contents/cache/**", - "src/database/contents/Compatibility/**", - "src/database/contents/Data/**", - ], - asar: false, // otherwise optolith-database-schema package is not properly resolved - asarUnpack: [ - "node_modules/optolith-character-schema/**", - "node_modules/optolith-database-schema/**", - "src/database/contents/**", - ], - win: { - target: [ - { - target: "nsis", - arch: ["x64", "ia32"], - }, - ], - }, - nsis: { - perMachine: true, - differentialPackage: true, - deleteAppDataOnUninstall: false, - }, - linux: { - category: "RolePlaying", - target: [ - { - target: "AppImage", - arch: ["x64"], - }, - { - target: "tar.gz", - arch: ["x64"], - }, - ], - }, - mac: { - category: "public.app-category.role-playing-games", - type: "distribution", - target: [ - { - target: "default", - arch: "universal", - }, - ], - entitlements: "deploy/entitlements.mac.plist", - entitlementsInherit: "deploy/entitlements.mac.plist", - mergeASARs: false, - darkModeSupport: true, - gatekeeperAssess: true, - }, - afterSign: async context => { - if (context.electronPlatformName === "darwin") { - await notarize(context) - } - }, -} diff --git a/deploy/build.js b/deploy/build.js deleted file mode 100644 index 80d6fb8d..00000000 --- a/deploy/build.js +++ /dev/null @@ -1,26 +0,0 @@ -// @ts-check -import builder from "electron-builder" -import { getSystem } from "./platform.js" - -const args = process.argv.slice(2) - -if (!args.includes("--stable") && !args.includes("--prerelease")) { - throw new TypeError(`build requires a specified channel ("--stable" or "--prerelease")`) -} - -const config = args.includes("--prerelease") - ? (await import("./build.prerelease.config.js")).prereleaseConfig - : (await import("./build.stable.config.js")).stableConfig - -process.on("unhandledRejection", error => { - throw new Error(`Unhandled promise rejection: ${/** @type {Error} */ (error).toString()}`) -}) - -const os = getSystem() - -const plaformKey = os === "linux" ? "LINUX" : os === "mac" ? "MAC" : "WINDOWS" - -await builder.build({ - config, - targets: builder.Platform[plaformKey].createTarget(), -}) diff --git a/deploy/build.prerelease.config.js b/deploy/build.prerelease.config.js deleted file mode 100644 index 371faeac..00000000 --- a/deploy/build.prerelease.config.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check -import { baseConfig } from "./build.base.config.js" - -/** - * @type {import("electron-builder").Configuration} - */ -export const prereleaseConfig = { - ...baseConfig, - appId: "com.lukasobermann.optolithinsider", - productName: "Optolith Insider", - directories: { - output: "dist/insider", - }, - win: { - ...baseConfig.win, - icon: "src/assets/icon/AppList.targetsize-512.pre.png", - artifactName: "OptolithInsiderSetup_${version}.${ext}", - }, - linux: { - ...baseConfig.linux, - executableName: "OptolithInsider", - icon: "src/assets/icon/icon.pre.png", - artifactName: "OptolithInsider_${version}.${ext}", - }, - mac: { - ...baseConfig.mac, - icon: "src/assets/icon/AppIcon.pre.icns", - artifactName: "OptolithInsider_${version}.${ext}", - }, - publish: { - provider: "generic", - url: `${process.env.UPDATE_URL}/insider/\${os}`, - channel: "latest", - }, -} diff --git a/deploy/build.stable.config.js b/deploy/build.stable.config.js deleted file mode 100644 index 11f470da..00000000 --- a/deploy/build.stable.config.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check -import { baseConfig } from "./build.base.config.js" - -/** - * @type {import("electron-builder").Configuration} - */ -export const stableConfig = { - ...baseConfig, - appId: "com.lukasobermann.optolith", - productName: "Optolith", - directories: { - output: "dist", - }, - win: { - ...baseConfig.win, - icon: "src/assets/icon/icon.ico", - artifactName: "OptolithSetup_${version}.${ext}", - }, - linux: { - ...baseConfig.linux, - executableName: "Optolith", - icon: "src/assets/icon/AppList.targetsize-512.png", - artifactName: "Optolith_${version}.${ext}", - }, - mac: { - ...baseConfig.mac, - icon: "src/assets/icon/AppIcon.icns", - artifactName: "Optolith_${version}.${ext}", - }, - publish: { - provider: "generic", - url: `${process.env.UPDATE_URL}/\${os}`, - channel: "latest", - }, -} diff --git a/deploy/deploy.js b/deploy/deploy.js index b0f9613c..197ccb66 100644 --- a/deploy/deploy.js +++ b/deploy/deploy.js @@ -1,10 +1,7 @@ // @ts-check +import { join } from "node:path" import packageJson from "../package.json" assert { type: "json" } -import { getApplicationFileNames, getUpdateFileName } from "./assetNames.js" -import { getLocalPath } from "./localPath.js" -import { getSystem, getSystemName } from "./platform.js" -import { run, upload } from "./remoteConnection.js" -import { getRemotePath } from "./remotePath.js" +import { run, upload } from "./uploader.js" /** * Needed env variables: @@ -16,40 +13,81 @@ import { getRemotePath } from "./remotePath.js" * Optional env variables: * - `CI` */ -const { - HOST, - USERNAME, - PASSWORD, - ROOT = "/", - CI, -} = process.env +const { HOST, USERNAME, PASSWORD, ROOT = "/", CI } = process.env const args = process.argv.slice(2) -const os = getSystem() +// Detect channel if (!args.includes("--stable") && !args.includes("--prerelease")) { - throw new TypeError(`publishToServer requires a specified channel ("--stable" or "--prerelease")`) + throw new TypeError(`Missing channel argument (either "--stable" or "--prerelease")`) } -const channel = args.includes("--prerelease") ? "prerelease" : "stable" +const isPrerelease = args.includes("--prerelease") -console.log(`Preparing to upload update files for "${getSystemName(os)}" on "${channel}" channel...`) +console.log(`Detected channel: ${isPrerelease ? "prerelease" : "stable"}`) -const localDir = getLocalPath(channel) -const remoteDir = getRemotePath(ROOT, channel, os) +// Detect OS -const updateFileName = getUpdateFileName(os) -const applicationFileNames = getApplicationFileNames(os, channel, packageJson.version) +let os +let osName -console.log(`Files to upload: ${[updateFileName, ...applicationFileNames] .join (", ")}.`) +if (process.argv.includes("--linux") || process.platform === "linux") { + os = /** @type {const} */ ("linux") + osName = "Linux" +} else if (process.argv.includes("--mac") || process.platform === "darwin") { + os = /** @type {const} */ ("mac") + osName = "macOS" +} else if (process.argv.includes("--win") || process.platform === "win32") { + os = /** @type {const} */ ("win") + osName = "Windows" +} else { + throw new TypeError(`The target operating system cannot be inferred from the environment.`) +} + +console.log(`Detected operating system: ${osName}`) + +// Infer files to upload + +let fileExtensions +let updateInfoFileName + +switch (os) { + case "win": + fileExtensions = [".exe", ".exe.blockmap"] + updateInfoFileName = "latest.yml" + break + case "linux": + fileExtensions = [".AppImage", ".tar.gz"] + updateInfoFileName = "latest-linux.yml" + break + case "mac": + fileExtensions = [".dmg", ".dmg.blockmap", ".zip", ".zip.blockmap"] + updateInfoFileName = "latest-mac.yml" + break +} + +const fileNames = [ + ...fileExtensions.map(ext => { + const chPart = isPrerelease ? "Insider" : "" + const osPart = os === "win" ? "Setup" : "" + return `Optolith${chPart}${osPart}_${packageJson.version}${ext}` + }), + updateInfoFileName, +] + +console.log(`Files to upload: ${fileNames.join(", ")}.`) + +// Upload files + +const localDir = isPrerelease ? join("dist", "insider") : join("dist") +const remoteDir = join(ROOT, isPrerelease ? "insider" : ".", os) await run({ host: HOST, username: USERNAME, password: PASSWORD }, async client => { - for (const applicationFileName of applicationFileNames) { - await upload(client, localDir, remoteDir, applicationFileName) + for (const fileName of fileNames) { + console.log(`Uploading ${fileName} ...`) + await upload(client, localDir, remoteDir, fileName) } - - await upload(client, localDir, remoteDir, updateFileName) }) console.log(`Uploading files finished successfully.`) diff --git a/deploy/localPath.js b/deploy/localPath.js deleted file mode 100644 index ce1981d6..00000000 --- a/deploy/localPath.js +++ /dev/null @@ -1,12 +0,0 @@ -// @ts-check -import { join } from "path" - -/** - * @param {"prerelease" | "stable"} channel - */ -export const getLocalPath = channel => { - switch (channel) { - case "prerelease": return join("dist", "insider") - case "stable": return join("dist") - } -} diff --git a/deploy/platform.js b/deploy/platform.js deleted file mode 100644 index 563fa24e..00000000 --- a/deploy/platform.js +++ /dev/null @@ -1,35 +0,0 @@ -// @ts-check -import { platform } from "os" - -const [_channel, ...args] = process.argv.slice(2) - -/** - * @typedef {"win" | "mac" | "linux"} System - * @returns {System} - */ -export const getSystem = () => { - if (args.includes("--linux")) { - return "linux" - } else if (args.includes("--mac")) { - return "mac" - } else if (args.includes("--win")) { - return "win" - } - - switch (platform()) { - case "win32": return "win" - case "darwin": return "mac" - default: return "linux" - } -} - -/** - * @param {System} system - */ -export const getSystemName = system => { - switch (system) { - case "win": return "Windows" - case "mac": return "macOS" - case "linux": return "Linux" - } -} diff --git a/deploy/remoteConnection.js b/deploy/remoteConnection.js deleted file mode 100644 index cdd0a7ad..00000000 --- a/deploy/remoteConnection.js +++ /dev/null @@ -1,41 +0,0 @@ -// @ts-check -import { join } from "path" -import { join as joinPosix } from "path/posix" -import Client from "ssh2-sftp-client" - -/** - * @param {Client.ConnectOptions} options - * @param {(client: Client) => Promise} action - */ -export const run = async (options, action) => { - const client = new Client() - console.log("Connecting to server ...") - await client.connect(options) - console.log(`Server connection established.`) - await action(client) - await client.end () - console.log("Closed server connection.") -} - -/** - * @param {Client} client - * @param {string} localDir - * @param {string} remoteDir - * @param {string} fileName - */ -export const upload = async (client, localDir, remoteDir, fileName) => { - console.log(`Uploading ${fileName} ...`); - - await client.fastPut ( - join (localDir, fileName), - joinPosix (remoteDir, fileName), - { - step: !process.env.CI ? (totalTransferred, _, total) => { - const percent = Math.floor (totalTransferred / total * 100) - console.log(`Progress: ${percent}%`); - } : undefined - } - ) - - console.log(`Upload done: ${fileName}.`); -} diff --git a/deploy/remotePath.js b/deploy/remotePath.js deleted file mode 100644 index 7c4c5ee1..00000000 --- a/deploy/remotePath.js +++ /dev/null @@ -1,31 +0,0 @@ -// @ts-check -import { join } from "path/posix" - -/** - * @param {"prerelease" | "stable"} channel - */ -const remoteChannelPath = channel => { - switch (channel) { - case "prerelease": return "insider" - case "stable": return "." - } -} - -/** - * @param {import("./platform.js").System} os - */ -const remoteOsPath = os => { - switch (os) { - case "win": return "win" - case "linux": return "linux" - default: return "mac" - } -} - -/** - * @param {string} root - * @param {"prerelease" | "stable"} channel - * @param {import("./platform.js").System} os - */ -export const getRemotePath = (root, channel, os) => - join(root, remoteChannelPath(channel), remoteOsPath(os)) diff --git a/deploy/uploader.js b/deploy/uploader.js new file mode 100644 index 00000000..60315808 --- /dev/null +++ b/deploy/uploader.js @@ -0,0 +1,51 @@ +// @ts-check +import { join } from "path" +import { join as joinPosix } from "path/posix" +import Client from "ssh2-sftp-client" + +/** + * Create a new sftp/ssh client and use it for the callback. The connection will + * be cleaned up afterwards. + * @param {Client.ConnectOptions} options + * @param {(client: Client) => Promise} action + */ +export const run = async (options, action) => { + const client = new Client() + console.log("Connecting to server ...") + await client.connect(options) + console.log(`Server connection established.`) + await action(client) + await client.end() + console.log("Closed server connection.") +} + +/** + * Uploads a file from a local directory to a remote directory using the given + * client. + * @param {Client} client + * @param {string} localDir + * @param {string} remoteDir + * @param {string} fileName + */ +export const upload = async (client, localDir, remoteDir, fileName) => { + console.log(`Uploading ${fileName} ...`) + + let didStep = false + + await client.fastPut(join(localDir, fileName), joinPosix(remoteDir, fileName), { + step: !process.env.CI + ? (totalTransferred, _, total) => { + if (didStep) { + process.stdout.clearLine(0) + process.stdout.cursorTo(0) + } else { + didStep = true + } + const percent = Math.floor((totalTransferred / total) * 100) + process.stdout.write(`Progress: ${percent}%`) + } + : undefined, + }) + + console.log(`Upload done: ${fileName}`) +} diff --git a/package-lock.json b/package-lock.json index 2c1a4e2b..a57f19df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "@types/react-dom": "^18.2.14", "@types/react-redux": "^7.1.28", "@types/semver": "^7.5.4", + "@types/ssh2-sftp-client": "^9.0.2", "@typescript-eslint/eslint-plugin": "^6.9.1", "@typescript-eslint/parser": "^6.9.1", "css-loader": "^6.8.1", @@ -1520,6 +1521,33 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "node_modules/@types/ssh2": { + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.11.15.tgz", + "integrity": "sha512-QFPpT9Gamh+oOKWH6uDUxe8izo8NaCJaN5HdYcbCIiS3hs7fB65KAfyGWBVXaXxXLj7IhFam5Q/ZxQ4eIPc/1Q==", + "dev": true, + "dependencies": { + "@types/node": "^18.11.18" + } + }, + "node_modules/@types/ssh2-sftp-client": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/ssh2-sftp-client/-/ssh2-sftp-client-9.0.2.tgz", + "integrity": "sha512-Ryi6McklD4aiNpRhYvWxPYFJHVGxrR3ojsTp4HBg/NFnmKOD0iShSKH1b10uO7/UTPS0MH9o5MjuHle2WQQtdQ==", + "dev": true, + "dependencies": { + "@types/ssh2": "*" + } + }, + "node_modules/@types/ssh2/node_modules/@types/node": { + "version": "18.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", + "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@types/unist": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", @@ -12959,6 +12987,35 @@ "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, + "@types/ssh2": { + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.11.15.tgz", + "integrity": "sha512-QFPpT9Gamh+oOKWH6uDUxe8izo8NaCJaN5HdYcbCIiS3hs7fB65KAfyGWBVXaXxXLj7IhFam5Q/ZxQ4eIPc/1Q==", + "dev": true, + "requires": { + "@types/node": "^18.11.18" + }, + "dependencies": { + "@types/node": { + "version": "18.18.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.8.tgz", + "integrity": "sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + } + } + }, + "@types/ssh2-sftp-client": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@types/ssh2-sftp-client/-/ssh2-sftp-client-9.0.2.tgz", + "integrity": "sha512-Ryi6McklD4aiNpRhYvWxPYFJHVGxrR3ojsTp4HBg/NFnmKOD0iShSKH1b10uO7/UTPS0MH9o5MjuHle2WQQtdQ==", + "dev": true, + "requires": { + "@types/ssh2": "*" + } + }, "@types/unist": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", diff --git a/package.json b/package.json index ac1db5d0..e1f20bbc 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@types/react-dom": "^18.2.14", "@types/react-redux": "^7.1.28", "@types/semver": "^7.5.4", + "@types/ssh2-sftp-client": "^9.0.2", "@typescript-eslint/eslint-plugin": "^6.9.1", "@typescript-eslint/parser": "^6.9.1", "css-loader": "^6.8.1",