ssh-client-wrapper 2.12.4 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,29 @@
1
+ name: Release and Publish
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ test:
10
+ uses: ./.github/workflows/run_test.yml
11
+
12
+ release:
13
+ needs: test
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: write
17
+ issues: write
18
+ pull-requests: write
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: actions/setup-node@v4
22
+ with:
23
+ node-version: 20
24
+ - run: npm ci
25
+ - name: Semantic Release
26
+ uses: cycjimmy/semantic-release-action@v4
27
+ env:
28
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,11 +1,8 @@
1
1
  name: run UT
2
2
  on:
3
- push:
4
- tags-ignore:
5
- - 'v*'
3
+ pull_request:
6
4
  branches:
7
- - '*'
8
- - '!main'
5
+ - main
9
6
  workflow_call:
10
7
  concurrency:
11
8
  group: ${{ github.workflow }}-${{ github.ref }}
@@ -0,0 +1 @@
1
+ npx lint-staged
package/.husky/pre-commit CHANGED
@@ -1,4 +1 @@
1
- #!/usr/bin/env sh
2
- . "$(dirname -- "$0")/_/husky.sh"
3
-
4
1
  npx lint-staged
@@ -0,0 +1,16 @@
1
+ {
2
+ "branches": ["main"],
3
+ "plugins": [
4
+ "@semantic-release/commit-analyzer",
5
+ "@semantic-release/release-notes-generator",
6
+ "@semantic-release/changelog",
7
+ ["@semantic-release/npm", {
8
+ "npmPublish": true
9
+ }],
10
+ ["@semantic-release/git", {
11
+ "assets": ["package.json", "package-lock.json", "CHANGELOG.md"],
12
+ "message": "chore(release): ${nextRelease.version} [skip ci]\\n\\n${nextRelease.notes}"
13
+ }],
14
+ "@semantic-release/github"
15
+ ]
16
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # [2.13.0](https://github.com/so5/ssh-client-wrapper/compare/v2.12.4...v2.13.0) (2025-08-20)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * upgrade debug from 4.4.0 to 4.4.1 ([35f966a](https://github.com/so5/ssh-client-wrapper/commit/35f966a7212d6bb9677964688bb94ae06f869ada))
7
+
8
+
9
+ ### Features
10
+
11
+ * Improve DX and automate releases ([805f2ea](https://github.com/so5/ssh-client-wrapper/commit/805f2ea7756f6ad61238a4a21d86575a17e748d9))
12
+ * Rewrite in ESM ([c5a95c1](https://github.com/so5/ssh-client-wrapper/commit/c5a95c18401e7b373249d3707609f2a9576f7400))
13
+ * Rewrite in ESM ([71ed6f5](https://github.com/so5/ssh-client-wrapper/commit/71ed6f56af43cac1471cbf4a4ed3016f7e55ab4d))
package/README.md CHANGED
@@ -4,3 +4,102 @@
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/8f3c0ea00e755ae31081/maintainability)](https://codeclimate.com/github/so5/ssh-client-wrapper/maintainability)
5
5
  # ssh-client-wrapper
6
6
  open ssh client wrapper library for nodejs
7
+
8
+ ## Installation
9
+ ```bash
10
+ npm install ssh-client-wrapper
11
+ ```
12
+
13
+ ## Usage
14
+ Here is a simple example of how to use `ssh-client-wrapper` to execute a command on a remote server.
15
+
16
+ ```javascript
17
+ import SshClientWrapper from 'ssh-client-wrapper';
18
+
19
+ const hostInfo = {
20
+ host: 'remote.server.com',
21
+ port: 22,
22
+ user: 'username',
23
+ password: 'password'
24
+ };
25
+
26
+ const ssh = new SshClientWrapper(hostInfo);
27
+
28
+ async function run() {
29
+ try {
30
+ await ssh.canConnect();
31
+ console.log('Connection successful!');
32
+
33
+ const { output, rt } = await ssh.execAndGetOutput('ls -l /home');
34
+ if (rt === 0) {
35
+ console.log('Directory listing:');
36
+ output.forEach(line => console.log(line));
37
+ } else {
38
+ console.error('Error executing command');
39
+ }
40
+ } catch (err) {
41
+ console.error('Connection or command failed:', err);
42
+ } finally {
43
+ ssh.disconnect();
44
+ }
45
+ }
46
+
47
+ run();
48
+ ```
49
+
50
+ ## API Guide
51
+
52
+ ### `new SshClientWrapper(hostInfo)`
53
+ Creates a new SSH client instance.
54
+
55
+ * `hostInfo` (Object): Connection details for the remote host.
56
+ * `host` (string): The hostname or IP address of the server.
57
+ * `user` (string): The username for authentication.
58
+ * `port` (number, optional): The port number. Defaults to 22.
59
+ * `password` (string | Function, optional): The password for authentication, or a function that returns the password.
60
+ * `keyFile` (string, optional): The path to the private key file for key-based authentication.
61
+ * `passphrase` (string | Function, optional): The passphrase for the private key, or a function that returns it.
62
+ * `noStrictHostKeyChecking` (boolean, optional): If `true`, bypasses strict host key checking.
63
+ * And more... see `lib/index.js` for all available options.
64
+
65
+ ### `.exec(cmd, [timeout], [outputCallback], [rcfile], [prependCmd])`
66
+ Executes a command on the remote host.
67
+
68
+ * Returns: `Promise<number>` - The return code of the command.
69
+
70
+ ### `.execAndGetOutput(cmd, [timeout], [rcfile], [prependCmd])`
71
+ Executes a command and returns its standard output.
72
+
73
+ * Returns: `Promise<{output: string[], rt: number}>` - An object containing the output as an array of strings and the return code.
74
+
75
+ ### `.ls(target, [lsOpt], [timeout])`
76
+ Executes the `ls` command on the remote host.
77
+
78
+ * Returns: `Promise<string[]>` - The output of the `ls` command as an array of strings.
79
+
80
+ ### `.expect(cmd, expects, [timeout])`
81
+ Executes a command and interacts with it, similar to the `expect` tool.
82
+
83
+ * Returns: `Promise<number>` - The return code of the command.
84
+
85
+ ### `.send(src, dst, [opt], [timeout])`
86
+ Uploads files or directories to the remote host using `rsync`.
87
+
88
+ * `src` (string[]): An array of local paths to send.
89
+ * `dst` (string): The remote destination path.
90
+ * Returns: `Promise<void>`
91
+
92
+ ### `.recv(src, dst, [opt], [timeout])`
93
+ Downloads files or directories from the remote host using `rsync`.
94
+
95
+ * `src` (string[]): An array of remote paths to receive.
96
+ * `dst` (string): The local destination path.
97
+ * Returns: `Promise<void>`
98
+
99
+ ### `.canConnect([timeout])`
100
+ Checks if a connection to the remote host can be established.
101
+
102
+ * Returns: `Promise<boolean>` - Resolves with `true` on success.
103
+
104
+ ### `.disconnect()`
105
+ Closes the master SSH connection to the remote host.
package/eslint.config.mjs CHANGED
@@ -1,39 +1,25 @@
1
- "use strict";
2
1
  import js from "@eslint/js";
3
2
  import globals from "globals";
4
3
  import stylistic from "@stylistic/eslint-plugin";
5
4
  import jsdoc from "eslint-plugin-jsdoc";
6
- import node from "eslint-plugin-node";
7
- import chaiFriendly from "eslint-plugin-chai-friendly";
8
-
9
- const jsdocRules = {
10
- "jsdoc/require-jsdoc": ["warn", { enableFixer: false }],
11
- "jsdoc/require-param": ["warn", { enableFixer: false }],
12
- "jsdoc/require-param-description": "warn",
13
- "jsdoc/require-param-name": "warn",
14
- "jsdoc/require-param-type": "warn",
15
- "jsdoc/require-hyphen-before-param-description": [
16
- "warn",
17
- "always",
18
- ],
19
- "jsdoc/require-returns": "warn",
20
- "jsdoc/require-returns-check": "error",
21
- };
5
+ import eslintPluginChaiFriendly from "eslint-plugin-chai-friendly";
6
+ import eslintPluginChaiExpect from "eslint-plugin-chai-expect";
22
7
 
23
8
  const styleRules = {
9
+ "arrow-body-style": ["error", "always"],
24
10
  "@stylistic/arrow-spacing": [
25
11
  "error",
26
12
  {
27
13
  after: false,
28
- before: false,
14
+ before: false
29
15
  }],
30
16
  "@stylistic/comma-dangle": [
31
17
  "error",
32
- "never",
18
+ "never"
33
19
  ],
34
20
  "@stylistic/spaced-comment": [
35
21
  "error",
36
- "never",
22
+ "never"
37
23
  ],
38
24
  "@stylistic/lines-around-comment": [
39
25
  "error",
@@ -42,32 +28,32 @@ const styleRules = {
42
28
  afterBlockComment: false,
43
29
  beforeLineComment: false,
44
30
  afterLineComment: false,
45
- allowBlockStart: true,
46
- },
31
+ allowBlockStart: true
32
+ }
47
33
  ],
48
34
  "@stylistic/lines-between-class-members": [
49
35
  "error",
50
36
  "always",
51
37
  {
52
- exceptAfterSingleLine: true,
53
- },
38
+ exceptAfterSingleLine: true
39
+ }
54
40
  ],
55
41
  "@stylistic/newline-per-chained-call": [
56
42
  "error",
57
43
  {
58
- ignoreChainWithDepth: 2,
59
- },
44
+ ignoreChainWithDepth: 2
45
+ }
60
46
  ],
61
47
  "@stylistic/padded-blocks": [
62
48
  "error",
63
- "never",
49
+ "never"
64
50
  ],
65
51
  "@stylistic/brace-style": [
66
52
  "error",
67
53
  "1tbs",
68
54
  {
69
- allowSingleLine: true,
70
- },
55
+ allowSingleLine: true
56
+ }
71
57
  ],
72
58
  "@stylistic/padding-line-between-statements": [
73
59
  "error",
@@ -76,9 +62,9 @@ const styleRules = {
76
62
  prev: [
77
63
  "const",
78
64
  "let",
79
- "var",
65
+ "var"
80
66
  ],
81
- next: "*",
67
+ next: "*"
82
68
  },
83
69
  {
84
70
  blankLine: "always",
@@ -90,8 +76,8 @@ const styleRules = {
90
76
  "function",
91
77
  "switch",
92
78
  "try",
93
- "while",
94
- ],
79
+ "while"
80
+ ]
95
81
  },
96
82
  {
97
83
  blankLine: "any",
@@ -103,7 +89,7 @@ const styleRules = {
103
89
  "while",
104
90
  "do",
105
91
  "block-like",
106
- "multiline-block-like",
92
+ "multiline-block-like"
107
93
  ],
108
94
  next: [
109
95
  "block-like",
@@ -112,95 +98,84 @@ const styleRules = {
112
98
  "multiline-block-like",
113
99
  "switch",
114
100
  "try",
115
- "while",
116
- ],
117
- },
101
+ "while"
102
+ ]
103
+ }
118
104
  ],
105
+ "@stylistic/quotes": [
106
+ "error",
107
+ "double"
108
+ ],
109
+ "@stylistic/semi": [
110
+ "error",
111
+ "always"
112
+ ]
113
+ };
114
+
115
+ const jsdocRules = {
116
+ "jsdoc/require-jsdoc": ["warn", { enableFixer: false }],
117
+ "jsdoc/require-param": ["warn", { enableFixer: false }],
118
+ "jsdoc/require-param-description": "warn",
119
+ "jsdoc/require-param-name": "warn",
120
+ "jsdoc/require-param-type": "warn",
121
+ "jsdoc/require-hyphen-before-param-description": [
122
+ "warn",
123
+ "always"
124
+ ],
125
+ "jsdoc/require-returns": "warn",
126
+ "jsdoc/require-returns-check": "error"
119
127
  };
120
128
 
121
129
  export default [
130
+ // Global configuration
131
+ {
132
+ ignores: ["coverage-report.lcov", "node_modules/"]
133
+ },
122
134
  js.configs.recommended,
123
- jsdoc.configs["flat/recommended"],
124
- stylistic.configs["disable-legacy"],
125
- stylistic.configs.customize({
126
- indent: 2,
127
- quotes: "double",
128
- semi: true,
129
- arrowParens: true,
130
- }),
131
135
  {
132
- ignores: ["node_modules/"],
136
+ plugins: {
137
+ "@stylistic": stylistic
138
+ }
133
139
  },
140
+ // Lib configuration
134
141
  {
135
- files: ["test/**/*.js"],
142
+ files: ["lib/**/*.js"],
136
143
  plugins: {
137
- chaiFriendly,
144
+ jsdoc
138
145
  },
139
146
  languageOptions: {
147
+ ecmaVersion: "latest",
148
+ sourceType: "module",
140
149
  globals: {
141
- ...globals.nodeBuiltin,
142
- ...globals.node,
143
- it: "readonly",
144
- describe: "readonly",
145
- before: "readonly",
146
- after: "readonly",
147
- beforeEach: "readonly",
148
- afterEach: "readonly",
149
- },
150
+ ...globals.es2021,
151
+ ...globals.node
152
+ }
150
153
  },
154
+ rules: {
155
+ ...styleRules,
156
+ ...jsdocRules
157
+ }
151
158
  },
159
+ // Test configuration
152
160
  {
153
- files: ["**/*.js"],
161
+ files: ["test/**/*.js"],
154
162
  plugins: {
155
- node,
156
- "@stylistic": stylistic,
157
- jsdoc,
163
+ "chai-friendly": eslintPluginChaiFriendly,
164
+ "chai-expect": eslintPluginChaiExpect
158
165
  },
159
166
  languageOptions: {
167
+ ecmaVersion: "latest",
168
+ sourceType: "module",
160
169
  globals: {
161
- ...globals.nodeBuiltin,
170
+ ...globals.es2021,
162
171
  ...globals.node,
163
- },
164
- sourceType: "commonjs",
172
+ ...globals.mocha
173
+ }
165
174
  },
166
175
  rules: {
167
176
  ...styleRules,
168
- ...jsdocRules,
169
- "node/exports-style": [
170
- "error",
171
- "module.exports",
172
- ],
173
- "no-nested-ternary": "off",
174
- "no-param-reassign": "warn",
175
- "camelcase": [
176
- "error",
177
- {
178
- properties: "never",
179
- },
180
- ],
181
- "eqeqeq": [
182
- "error",
183
- "always",
184
- {
185
- null: "ignore",
186
- },
187
- ],
188
- "func-style": [
189
- "error",
190
- "declaration",
191
- {
192
- allowArrowFunctions: true,
193
- },
194
- ],
195
- "no-use-before-define": [
196
- "error",
197
- {
198
- functions: false,
199
- },
200
- ],
201
- "no-warning-comments": "warn",
202
- "require-unicode-regexp": "off",
203
-
204
- },
205
- },
177
+ "no-unused-expressions": "off",
178
+ "chai-friendly/no-unused-expressions": "error"
179
+ }
180
+ }
206
181
  ];
package/lib/fork.js CHANGED
@@ -1,17 +1,18 @@
1
- "use strict";
2
- const debug = require("debug")("sshClientWrapper:debug:fork");
3
- const debugVerbose = require("debug")("sshClientWrapper:verbose:fork");
4
- const debugSendPty = require("debug")("sshClientWrapper:insecure:fork");
5
- const { spawn } = require("node-pty");
1
+ import Debug from "debug";
2
+ import { spawn } from "node-pty-prebuilt-multiarch";
6
3
 
7
- const { rePwPrompt, rePhPrompt, reNewHostPrompt, reRemoteHostIdentificationHasChanged, buff2String, sendPty, watchDogTimer } = require("./util.js");
4
+ import { rePwPrompt, rePhPrompt, reNewHostPrompt, reRemoteHostIdentificationHasChanged, buff2String, sendPty, watchDogTimer } from "./util.js";
5
+
6
+ const debug = Debug("sshClientWrapper:debug:fork");
7
+ const debugVerbose = Debug("sshClientWrapper:verbose:fork");
8
+ const debugSendPty = Debug("sshClientWrapper:insecure:fork");
8
9
 
9
10
  const nodePtyOpt = {
10
11
  shell: process.platform === "win32" ? process.env.ComSpec : process.env.SHELL,
11
12
  windowsHide: true
12
13
  };
13
14
 
14
- function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
15
+ export function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
15
16
  return new Promise((resolve, reject)=>{
16
17
  if (reRemoteHostIdentificationHasChanged.test(output)) {
17
18
  debug("REMOTE HOST IDENTIFICATION HAS CHANGED");
@@ -70,7 +71,7 @@ function sshLoginCallback(output, ptyProcess, pw, ph, logger = debugSendPty) {
70
71
  /**
71
72
  * create pty for master ssh session and store to hostInfo.masterPty
72
73
  */
73
- function createMasterPty(hostInfo) {
74
+ export function createMasterPty(hostInfo) {
74
75
  debug("fork pty for master connection");
75
76
 
76
77
  if (hostInfo.masterPty) {
@@ -81,7 +82,7 @@ function createMasterPty(hostInfo) {
81
82
  hostInfo.masterPty = ptyProcess;
82
83
  }
83
84
 
84
- async function fork(hostInfo, cmd, args, timeout, outputCallback, retryableExitCodes = [], expects = []) {
85
+ export async function fork(hostInfo, cmd, args, timeout, outputCallback, retryableExitCodes = [], expects = []) {
85
86
  return new Promise((resolve, reject)=>{
86
87
  debug(`cmd=${cmd}: args=${args}`);
87
88
  const ptyProcess = spawn(cmd, args, nodePtyOpt);
@@ -150,8 +151,3 @@ async function fork(hostInfo, cmd, args, timeout, outputCallback, retryableExitC
150
151
  });
151
152
  });
152
153
  }
153
- module.exports = {
154
- fork,
155
- createMasterPty,
156
- sshLoginCallback
157
- };
package/lib/index.js CHANGED
@@ -1,11 +1,12 @@
1
- "use strict";
2
- const fs = require("fs");
3
- const path = require("path");
4
- const debug = require("debug")("sshClientWrapper:debug:interface");
5
- const debugVerbose = require("debug")("sshClientWrapper:verbose:interface");
6
- const { sshExec, canConnect, disconnect, expect } = require("./sshExec.js");
7
- const { send, recv } = require("./rsyncExec.js");
8
- const { isArrayOfString, sanityCheck } = require("./util.js");
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import Debug from "debug";
4
+ import * as sshExecModule from "./sshExec.js";
5
+ import * as rsyncExecModule from "./rsyncExec.js";
6
+ import { isArrayOfString, sanityCheck } from "./util.js";
7
+
8
+ const debug = Debug("sshClientWrapper:debug:interface");
9
+ const debugVerbose = Debug("sshClientWrapper:verbose:interface");
9
10
 
10
11
  /**
11
12
  * Integer means integer number but it is defined as Object for now
@@ -25,10 +26,10 @@ const { isArrayOfString, sanityCheck } = require("./util.js");
25
26
  * @param {string | Function} hostInfo.passphrase - passphrase or function which return passphrase of private key
26
27
  * @param {string} hostInfo.keyFile - private key filename
27
28
  * @param {boolean} hostInfo.noStrictHostKeyChecking - bypass host key checking if true
28
- * @param {Integer} hostInfo.ControlPersist=180 - how long keep master connection after last client connection has been closed (sec).
29
- * @param {Integer} hostInfo.ConnectTimeout=60 - timeout used when connectiong to ths SSH server
30
- * @param {Integer} hostInfo.maxRetry=3 - max number of retry
31
- * @param {Integer} hostInfo.retryDuration=1000 - duration time (msec) between each retry
29
+ * @param {Integer} hostInfo.ControlPersist - how long keep master connection after last client connection has been closed (sec).
30
+ * @param {Integer} hostInfo.ConnectTimeout - timeout used when connectiong to ths SSH server
31
+ * @param {Integer} hostInfo.maxRetry - max number of retry
32
+ * @param {Integer} hostInfo.retryDuration - duration time (msec) between each retry
32
33
  * @param {string} hostInfo.rcfile - rcfile path which will be sourced before executing actual command
33
34
  * @param {string} hostInfo.prependCmd - command string which will be executed before executing actual command
34
35
  * @param {string[]} hostInfo.sshOpt - additional options for ssh
@@ -44,13 +45,14 @@ const logAndReject = (message)=>{
44
45
  * @class
45
46
  */
46
47
  class SshClientWrapper {
47
- constructor(hostInfo) {
48
+ constructor(hostInfo, deps = { ...sshExecModule, ...rsyncExecModule }) {
48
49
  debug("constructor called for", hostInfo.host);
49
50
  debugVerbose("hostInfo=", hostInfo);
50
51
  this.hostInfo = { ...hostInfo };
51
52
  sanityCheck(this.hostInfo);
52
53
  this.hostInfo.masterPty = null;
53
54
  this.hostInfo.rsyncVersion = null;
55
+ this.deps = deps;
54
56
 
55
57
  if (process.env.HOME) {
56
58
  try {
@@ -80,7 +82,7 @@ class SshClientWrapper {
80
82
  if (typeof cmd !== "string" || cmd === "") {
81
83
  return logAndReject("cmd must be string");
82
84
  }
83
- return sshExec(this.hostInfo, cmd, timeout, outputCallback, rcfile, prependCmd);
85
+ return this.deps.sshExec(this.hostInfo, cmd, timeout, outputCallback, rcfile, prependCmd);
84
86
  }
85
87
 
86
88
  /**
@@ -99,7 +101,7 @@ class SshClientWrapper {
99
101
  };
100
102
  let rt = null;
101
103
  try {
102
- rt = await sshExec(this.hostInfo, cmd, timeout, cb, rcfile, prependCmd);
104
+ rt = await this.deps.sshExec(this.hostInfo, cmd, timeout, cb, rcfile, prependCmd);
103
105
  } catch (e) {
104
106
  //non-zero retrun should be allowed
105
107
  if (typeof e.rt === "undefined" || e.rt < 0) {
@@ -138,7 +140,7 @@ class SshClientWrapper {
138
140
  */
139
141
  async expect(cmd, expects, timeout = 180) {
140
142
  debug("expect called", expects);
141
- return expect(this.hostInfo, cmd, expects, timeout);
143
+ return this.deps.expect(this.hostInfo, cmd, expects, timeout);
142
144
  }
143
145
 
144
146
  /**
@@ -169,7 +171,7 @@ class SshClientWrapper {
169
171
  if (typeof opt !== "undefined" && !isArrayOfString(opt)) {
170
172
  return logAndReject("opt must be array of string");
171
173
  }
172
- return send(this.hostInfo, src, dst, opt, timeout);
174
+ return this.deps.send(this.hostInfo, src, dst, opt, timeout);
173
175
  }
174
176
 
175
177
  /**
@@ -200,7 +202,7 @@ class SshClientWrapper {
200
202
  if (typeof opt !== "undefined" && !isArrayOfString(opt)) {
201
203
  return logAndReject("opt must be array of string");
202
204
  }
203
- return recv(this.hostInfo, src, dst, opt, timeout);
205
+ return this.deps.recv(this.hostInfo, src, dst, opt, timeout);
204
206
  }
205
207
 
206
208
  /**
@@ -215,7 +217,7 @@ class SshClientWrapper {
215
217
  if (!Number.isInteger(timeout) || timeout <= 0) {
216
218
  return logAndReject("timeout must be positive integer");
217
219
  }
218
- return canConnect(this.hostInfo, timeout);
220
+ return this.deps.canConnect(this.hostInfo, timeout);
219
221
  }
220
222
 
221
223
  /**
@@ -223,8 +225,8 @@ class SshClientWrapper {
223
225
  */
224
226
  async disconnect() {
225
227
  debug(`disconnect from ${this.hostInfo.host} called`);
226
- disconnect(this.hostInfo);
228
+ this.deps.disconnect(this.hostInfo);
227
229
  }
228
230
  }
229
231
 
230
- module.exports = SshClientWrapper;
232
+ export default SshClientWrapper;