core/adapters/shell.adapter.ts
core/adapters/shell.adapter.ts is a file in Bane's Lab Deploy. 59 lines of code and 8 definitions.
import type { ByteStep, Secrets, Shell, TransferOptions } from "#types/deployment.types";
import { NOT_CONNECTED } from "#configuration/strings/deployment.strings";
import { NodeSSH } from "node-ssh";
import { SSH_FOLDER } from "#configuration/constants/ssh.constants";
import { homedir } from "node:os";
import { join } from "node:path";
import { readFileSync } from "node:fs";
const transferOf = function transferOf(step: ByteStep | undefined): TransferOptions | null {
return step === undefined
? null
: {
step: (transferred: number, _chunk: number, size: number) => {
step(transferred, size);
},
};
};
const privateKey = function privateKey(keyFile: string): string {
return readFileSync(join(homedir(), SSH_FOLDER, keyFile), "utf8");
};
export const createShell = function createShell(secrets: Secrets): Shell {
const ssh = new NodeSSH();
let connected = false;
const guard = function guard(): void {
if (!connected) {
throw new Error(NOT_CONNECTED);
}
};
const connect = async function connect(): Promise<void> {
await ssh.connect({
host: secrets.host,
privateKey: privateKey(secrets.keyFile),
username: secrets.user,
...(secrets.passphrase === null ? {} : { passphrase: secrets.passphrase }),
});
connected = true;
};
return {
connect,
dispose: () => {
if (connected) {
ssh.dispose();
connected = false;
}
},
download: async (localPath, remotePath, step) => {
guard();
await ssh.getFile(localPath, remotePath, null, transferOf(step));
},
run: async (command) => {
guard();
const result = await ssh.execCommand(command);
return { code: result.code, stderr: result.stderr, stdout: result.stdout };
},
upload: async (localPath, remotePath, step) => {
guard();
await ssh.putFile(localPath, remotePath, null, transferOf(step));
},
};
};