Comparing version 5.1.2 to 6.0.0
@@ -0,1 +1,6 @@ | ||
#### 6.0.0 | ||
* Breaking upgrade to `ssh2` dependency | ||
* Internal cleanup / testing system overhaul | ||
#### 5.1.2 | ||
@@ -2,0 +7,0 @@ |
@@ -1,2 +0,2 @@ | ||
'use strict'; | ||
"use strict"; | ||
@@ -6,14 +6,63 @@ Object.defineProperty(exports, "__esModule", { | ||
}); | ||
exports.normalizeConfig = exports.mkdirSftp = exports.readdir = exports.stat = undefined; | ||
exports.exists = exists; | ||
exports.mkdirSftp = mkdirSftp; | ||
exports.normalizeConfig = normalizeConfig; | ||
exports.normalizePutFilesOptions = normalizePutFilesOptions; | ||
exports.normalizePutDirectoryOptions = normalizePutDirectoryOptions; | ||
exports.generateCallback = generateCallback; | ||
exports.readdir = exports.stat = void 0; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _fs = _interopRequireDefault(require("fs")); | ||
var mkdirSftp = exports.mkdirSftp = function () { | ||
var _ref = _asyncToGenerator(function* (path, sftp) { | ||
var stats = void 0; | ||
var _path = _interopRequireDefault(require("path")); | ||
var _sbPromisify = _interopRequireDefault(require("sb-promisify")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } | ||
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } | ||
const CODE_REGEXP = /Error: (E[\S]+): /; | ||
const DEFAULT_CONCURRENCY = 5; | ||
const readFile = (0, _sbPromisify.default)(_fs.default.readFile); | ||
const stat = (0, _sbPromisify.default)(_fs.default.stat); | ||
exports.stat = stat; | ||
const readdir = (0, _sbPromisify.default)(_fs.default.readdir); | ||
exports.readdir = readdir; | ||
function transformError(givenError) { | ||
const code = CODE_REGEXP.exec(givenError); | ||
if (code) { | ||
// eslint-disable-next-line no-param-reassign,prefer-destructuring | ||
givenError.code = code[1]; | ||
} | ||
return givenError; | ||
} | ||
function exists(filePath) { | ||
return new Promise(function (resolve) { | ||
_fs.default.access(filePath, _fs.default.R_OK, function (error) { | ||
resolve(!error); | ||
}); | ||
}); | ||
} | ||
function mkdirSftp(_x, _x2) { | ||
return _mkdirSftp.apply(this, arguments); | ||
} | ||
function _mkdirSftp() { | ||
_mkdirSftp = _asyncToGenerator(function* (path, sftp) { | ||
let stats; | ||
try { | ||
stats = yield (0, _sbPromisify2.default)(sftp.stat).call(sftp, path); | ||
stats = yield (0, _sbPromisify.default)(sftp.stat).call(sftp, path); | ||
} catch (_) { | ||
/* No Op */ | ||
} | ||
if (stats) { | ||
@@ -24,6 +73,8 @@ if (stats.isDirectory()) { | ||
} | ||
throw new Error('mkdir() failed, target already exists and is not a directory'); | ||
} | ||
try { | ||
yield (0, _sbPromisify2.default)(sftp.mkdir).call(sftp, path); | ||
yield (0, _sbPromisify.default)(sftp.mkdir).call(sftp, path); | ||
} catch (error) { | ||
@@ -33,14 +84,17 @@ throw transformError(error); | ||
}); | ||
return _mkdirSftp.apply(this, arguments); | ||
} | ||
return function mkdirSftp(_x, _x2) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}(); | ||
function normalizeConfig(_x3) { | ||
return _normalizeConfig.apply(this, arguments); | ||
} | ||
var normalizeConfig = exports.normalizeConfig = function () { | ||
var _ref2 = _asyncToGenerator(function* (givenConfig) { | ||
var config = Object.assign({}, givenConfig); | ||
function _normalizeConfig() { | ||
_normalizeConfig = _asyncToGenerator(function* (givenConfig) { | ||
const config = Object.assign({}, givenConfig); | ||
if (config.username && typeof config.username !== 'string') { | ||
throw new Error('config.username must be a valid string'); | ||
} | ||
if (typeof config.host !== 'undefined') { | ||
@@ -51,3 +105,3 @@ if (typeof config.host !== 'string' || !config.host) { | ||
} else if (typeof config.sock !== 'undefined') { | ||
if (!config.sock || _typeof(config.sock) !== 'object') { | ||
if (!config.sock || typeof config.sock !== 'object') { | ||
throw new Error('config.sock must be a valid object'); | ||
@@ -58,7 +112,10 @@ } | ||
} | ||
if (config.privateKey) { | ||
var privateKey = config.privateKey; | ||
const privateKey = config.privateKey; | ||
if (typeof privateKey !== 'string') { | ||
throw new Error('config.privateKey must be a string'); | ||
} | ||
if (!(privateKey.includes('BEGIN') && privateKey.includes('KEY'))) { | ||
@@ -69,4 +126,5 @@ try { | ||
if (error.code === 'ENOENT') { | ||
throw new Error('config.privateKey does not exist at ' + privateKey); | ||
throw new Error(`config.privateKey does not exist at ${privateKey}`); | ||
} | ||
throw error; | ||
@@ -76,3 +134,4 @@ } | ||
} else if (config.password) { | ||
var password = config.password; | ||
const password = config.password; | ||
if (typeof password !== 'string') { | ||
@@ -87,3 +146,3 @@ throw new Error('config.password must be a string'); | ||
if (typeof config.onKeyboardInteractive !== 'function') { | ||
config.onKeyboardInteractive = function (name, instructions, instructionsLang, prompts, finish) { | ||
config.onKeyboardInteractive = (name, instructions, instructionsLang, prompts, finish) => { | ||
if (prompts.length > 0 && prompts[0].prompt.toLowerCase().includes('password')) { | ||
@@ -100,62 +159,17 @@ finish([config.password]); | ||
}); | ||
return function normalizeConfig(_x3) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}(); | ||
exports.exists = exists; | ||
exports.normalizePutFilesOptions = normalizePutFilesOptions; | ||
exports.normalizePutDirectoryOptions = normalizePutDirectoryOptions; | ||
exports.generateCallback = generateCallback; | ||
var _fs = require('fs'); | ||
var _fs2 = _interopRequireDefault(_fs); | ||
var _path = require('path'); | ||
var _path2 = _interopRequireDefault(_path); | ||
var _sbPromisify = require('sb-promisify'); | ||
var _sbPromisify2 = _interopRequireDefault(_sbPromisify); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } | ||
var CODE_REGEXP = /Error: (E[\S]+): /; | ||
var DEFAULT_CONCURRENCY = 5; | ||
var readFile = (0, _sbPromisify2.default)(_fs2.default.readFile); | ||
var stat = exports.stat = (0, _sbPromisify2.default)(_fs2.default.stat); | ||
var readdir = exports.readdir = (0, _sbPromisify2.default)(_fs2.default.readdir); | ||
function transformError(givenError) { | ||
var code = CODE_REGEXP.exec(givenError); | ||
if (code) { | ||
// eslint-disable-next-line no-param-reassign | ||
givenError.code = code[1]; | ||
} | ||
return givenError; | ||
return _normalizeConfig.apply(this, arguments); | ||
} | ||
function exists(filePath) { | ||
return new Promise(function (resolve) { | ||
_fs2.default.access(filePath, _fs2.default.R_OK, function (error) { | ||
resolve(!error); | ||
}); | ||
}); | ||
} | ||
function normalizePutFilesOptions(givenConfig) { | ||
var config = {}; | ||
const config = {}; | ||
if (givenConfig.sftpOptions && _typeof(givenConfig.sftpOptions) === 'object') { | ||
if (givenConfig.sftpOptions && typeof givenConfig.sftpOptions === 'object') { | ||
config.sftpOptions = givenConfig.sftpOptions; | ||
} else config.sftpOptions = {}; | ||
if (typeof givenConfig.concurrency === 'number') { | ||
config.concurrency = givenConfig.concurrency; | ||
} else config.concurrency = DEFAULT_CONCURRENCY; | ||
if (_typeof(givenConfig.sftp) === 'object') { | ||
if (typeof givenConfig.sftp === 'object') { | ||
config.sftp = givenConfig.sftp; | ||
@@ -168,3 +182,3 @@ } else config.sftp = null; | ||
function normalizePutDirectoryOptions(givenConfig) { | ||
var config = normalizePutFilesOptions(givenConfig); | ||
const config = normalizePutFilesOptions(givenConfig); | ||
@@ -175,2 +189,3 @@ if (givenConfig.tick) { | ||
} | ||
config.tick = givenConfig.tick; | ||
@@ -180,2 +195,3 @@ } else { | ||
} | ||
if (givenConfig.validate) { | ||
@@ -185,8 +201,10 @@ if (typeof givenConfig.validate !== 'function') { | ||
} | ||
config.validate = givenConfig.validate; | ||
} else { | ||
config.validate = function (path) { | ||
return _path2.default.basename(path).substr(0, 1) !== '.'; | ||
return _path.default.basename(path).substr(0, 1) !== '.'; | ||
}; | ||
} | ||
config.recursive = {}.hasOwnProperty.call(givenConfig, 'recursive') ? !!givenConfig.recursive : true; | ||
@@ -193,0 +211,0 @@ return config; |
707
lib/index.js
@@ -1,478 +0,401 @@ | ||
'use strict'; | ||
"use strict"; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _path = _interopRequireDefault(require("path")); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _ssh = _interopRequireDefault(require("ssh2")); | ||
var _path = require('path'); | ||
var _pMap = _interopRequireDefault(require("p-map")); | ||
var _path2 = _interopRequireDefault(_path); | ||
var _assert = _interopRequireDefault(require("assert")); | ||
var _ssh = require('ssh2'); | ||
var _sbScandir = _interopRequireDefault(require("sb-scandir")); | ||
var _ssh2 = _interopRequireDefault(_ssh); | ||
var _shellEscape = _interopRequireDefault(require("shell-escape")); | ||
var _pMap = require('p-map'); | ||
var Helpers = _interopRequireWildcard(require("./helpers")); | ||
var _pMap2 = _interopRequireDefault(_pMap); | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } | ||
var _assert = require('assert'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var _assert2 = _interopRequireDefault(_assert); | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } | ||
var _sbScandir = require('sb-scandir'); | ||
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } | ||
var _sbScandir2 = _interopRequireDefault(_sbScandir); | ||
class SSH { | ||
constructor() { | ||
this.connection = null; | ||
} | ||
var _shellEscape = require('shell-escape'); | ||
connect(givenConfig) { | ||
const connection = new _ssh.default(); | ||
this.connection = connection; | ||
return new Promise(function (resolve) { | ||
resolve(Helpers.normalizeConfig(givenConfig)); | ||
}).then(config => new Promise((resolve, reject) => { | ||
connection.on('error', reject); | ||
var _shellEscape2 = _interopRequireDefault(_shellEscape); | ||
if (config.onKeyboardInteractive) { | ||
connection.on('keyboard-interactive', config.onKeyboardInteractive); | ||
} | ||
var _helpers = require('./helpers'); | ||
connection.on('ready', () => { | ||
connection.removeListener('error', reject); | ||
resolve(this); | ||
}); | ||
connection.on('end', () => { | ||
if (this.connection === connection) { | ||
this.connection = null; | ||
} | ||
}); | ||
connection.on('close', () => { | ||
if (this.connection === connection) { | ||
this.connection = null; | ||
} | ||
var Helpers = _interopRequireWildcard(_helpers); | ||
const error = new Error('No response from server'); // $FlowIgnore: Custom attribute | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | ||
error.code = 'ETIMEDOUT'; | ||
reject(error); | ||
}); | ||
connection.connect(config); | ||
})); | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
requestShell() { | ||
var _this = this; | ||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var SSH = function () { | ||
function SSH() { | ||
_classCallCheck(this, SSH); | ||
this.connection = null; | ||
return _asyncToGenerator(function* () { | ||
const connection = _this.connection; | ||
(0, _assert.default)(connection, 'Not connected to server'); | ||
return new Promise(function (resolve, reject) { | ||
connection.shell(Helpers.generateCallback(resolve, reject)); | ||
}); | ||
})(); | ||
} | ||
_createClass(SSH, [{ | ||
key: 'connect', | ||
value: function connect(givenConfig) { | ||
var _this = this; | ||
requestSFTP() { | ||
var _this2 = this; | ||
var connection = new _ssh2.default(); | ||
this.connection = connection; | ||
return new Promise(function (resolve) { | ||
resolve(Helpers.normalizeConfig(givenConfig)); | ||
}).then(function (config) { | ||
return new Promise(function (resolve, reject) { | ||
connection.on('error', reject); | ||
if (config.onKeyboardInteractive) { | ||
connection.on('keyboard-interactive', config.onKeyboardInteractive); | ||
} | ||
connection.on('ready', function () { | ||
connection.removeListener('error', reject); | ||
resolve(_this); | ||
}); | ||
connection.on('end', function () { | ||
if (_this.connection === connection) { | ||
_this.connection = null; | ||
} | ||
}); | ||
connection.on('close', function () { | ||
if (_this.connection === connection) { | ||
_this.connection = null; | ||
} | ||
var error = new Error('No response from server'); | ||
// $FlowIgnore: Custom attribute | ||
error.code = 'ETIMEDOUT'; | ||
reject(error); | ||
}); | ||
connection.connect(config); | ||
}); | ||
return _asyncToGenerator(function* () { | ||
const connection = _this2.connection; | ||
(0, _assert.default)(connection, 'Not connected to server'); | ||
return new Promise(function (resolve, reject) { | ||
connection.sftp(Helpers.generateCallback(resolve, reject)); | ||
}); | ||
} | ||
}, { | ||
key: 'requestShell', | ||
value: function () { | ||
var _ref = _asyncToGenerator(function* () { | ||
var connection = this.connection; | ||
(0, _assert2.default)(connection, 'Not connected to server'); | ||
return new Promise(function (resolve, reject) { | ||
connection.shell(Helpers.generateCallback(resolve, reject)); | ||
}); | ||
}); | ||
})(); | ||
} | ||
function requestShell() { | ||
return _ref.apply(this, arguments); | ||
} | ||
mkdir(path, type = 'sftp', givenSftp = null) { | ||
var _this3 = this; | ||
return requestShell; | ||
}() | ||
}, { | ||
key: 'requestSFTP', | ||
value: function () { | ||
var _ref2 = _asyncToGenerator(function* () { | ||
var connection = this.connection; | ||
(0, _assert2.default)(connection, 'Not connected to server'); | ||
return new Promise(function (resolve, reject) { | ||
connection.sftp(Helpers.generateCallback(resolve, reject)); | ||
}); | ||
}); | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this3.connection, 'Not connected to server'); | ||
(0, _assert.default)(type === 'exec' || type === 'sftp', 'Type should either be sftp or exec'); | ||
function requestSFTP() { | ||
return _ref2.apply(this, arguments); | ||
} | ||
if (type === 'exec') { | ||
const output = yield _this3.exec('mkdir', ['-p', path]); | ||
return requestSFTP; | ||
}() | ||
}, { | ||
key: 'mkdir', | ||
value: function () { | ||
var _ref3 = _asyncToGenerator(function* (path) { | ||
var _this2 = this; | ||
if (output.stdout) { | ||
throw new Error(output.stdout); | ||
} | ||
} else { | ||
(0, _assert.default)(!givenSftp || typeof givenSftp === 'object', 'sftp must be an object'); | ||
const sftp = givenSftp || (yield _this3.requestSFTP()); | ||
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'sftp'; | ||
var givenSftp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)(type === 'exec' || type === 'sftp', 'Type should either be sftp or exec'); | ||
if (type === 'exec') { | ||
var output = yield this.exec('mkdir', ['-p', path]); | ||
if (output.stdout) { | ||
throw new Error(output.stdout); | ||
const makeSftpDirectory = retry => Helpers.mkdirSftp(path, sftp).catch(error => { | ||
if (retry && error && (error.message === 'No such file' || error.code === 'ENOENT')) { | ||
return _this3.mkdir(_path.default.dirname(path), 'sftp', sftp).then(() => makeSftpDirectory(false)); | ||
} | ||
} else { | ||
(0, _assert2.default)(!givenSftp || (typeof givenSftp === 'undefined' ? 'undefined' : _typeof(givenSftp)) === 'object', 'sftp must be an object'); | ||
var sftp = givenSftp || (yield this.requestSFTP()); | ||
var makeSftpDirectory = function makeSftpDirectory(retry) { | ||
return Helpers.mkdirSftp(path, sftp).catch(function (error) { | ||
if (retry && error && (error.message === 'No such file' || error.code === 'ENOENT')) { | ||
return _this2.mkdir(_path2.default.dirname(path), 'sftp', sftp).then(function () { | ||
return makeSftpDirectory(false); | ||
}); | ||
} | ||
throw error; | ||
}); | ||
}; | ||
try { | ||
yield makeSftpDirectory(true); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
throw error; | ||
}); | ||
try { | ||
yield makeSftpDirectory(true); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
} | ||
}); | ||
function mkdir(_x) { | ||
return _ref3.apply(this, arguments); | ||
} | ||
})(); | ||
} | ||
return mkdir; | ||
}() | ||
}, { | ||
key: 'exec', | ||
value: function () { | ||
var _ref4 = _asyncToGenerator(function* (command) { | ||
var parameters = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
exec(command, parameters = [], options = {}) { | ||
var _this4 = this; | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' && options, 'options must be an Object'); | ||
(0, _assert2.default)(!options.cwd || typeof options.cwd === 'string', 'options.cwd must be a string'); | ||
(0, _assert2.default)(!options.stdin || typeof options.stdin === 'string', 'options.stdin must be a string'); | ||
(0, _assert2.default)(!options.stream || ['stdout', 'stderr', 'both'].indexOf(options.stream) !== -1, 'options.stream must be among "stdout", "stderr" and "both"'); | ||
(0, _assert2.default)(!options.options || _typeof(options.options) === 'object', 'options.options must be an object'); | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this4.connection, 'Not connected to server'); | ||
(0, _assert.default)(typeof options === 'object' && options, 'options must be an Object'); | ||
(0, _assert.default)(!options.cwd || typeof options.cwd === 'string', 'options.cwd must be a string'); | ||
(0, _assert.default)(!options.stdin || typeof options.stdin === 'string', 'options.stdin must be a string'); | ||
(0, _assert.default)(!options.stream || ['stdout', 'stderr', 'both'].indexOf(options.stream) !== -1, 'options.stream must be among "stdout", "stderr" and "both"'); | ||
(0, _assert.default)(!options.options || typeof options.options === 'object', 'options.options must be an object'); | ||
const output = yield _this4.execCommand([command].concat((0, _shellEscape.default)(parameters)).join(' '), options); | ||
var output = yield this.execCommand([command].concat((0, _shellEscape2.default)(parameters)).join(' '), options); | ||
if (!options.stream || options.stream === 'stdout') { | ||
if (output.stderr) { | ||
throw new Error(output.stderr); | ||
} | ||
return output.stdout; | ||
if (!options.stream || options.stream === 'stdout') { | ||
if (output.stderr) { | ||
throw new Error(output.stderr); | ||
} | ||
if (options.stream === 'stderr') { | ||
return output.stderr; | ||
} | ||
return output; | ||
}); | ||
function exec(_x4) { | ||
return _ref4.apply(this, arguments); | ||
return output.stdout; | ||
} | ||
return exec; | ||
}() | ||
}, { | ||
key: 'execCommand', | ||
value: function () { | ||
var _ref5 = _asyncToGenerator(function* (givenCommand) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
if (options.stream === 'stderr') { | ||
return output.stderr; | ||
} | ||
var command = givenCommand; | ||
var connection = this.connection; | ||
(0, _assert2.default)(connection, 'Not connected to server'); | ||
(0, _assert2.default)((typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' && options, 'options must be an Object'); | ||
(0, _assert2.default)(!options.cwd || typeof options.cwd === 'string', 'options.cwd must be a string'); | ||
(0, _assert2.default)(!options.stdin || typeof options.stdin === 'string', 'options.stdin must be a string'); | ||
(0, _assert2.default)(!options.options || _typeof(options.options) === 'object', 'options.options must be an object'); | ||
return output; | ||
})(); | ||
} | ||
if (options.cwd) { | ||
// NOTE: Output piping cd command to hide directory non-existent errors | ||
command = 'cd ' + (0, _shellEscape2.default)([options.cwd]) + ' 1> /dev/null 2> /dev/null; ' + command; | ||
} | ||
var output = { stdout: [], stderr: [] }; | ||
return new Promise(function (resolve, reject) { | ||
connection.exec(command, options.options || {}, Helpers.generateCallback(function (stream) { | ||
stream.on('data', function (chunk) { | ||
if (options.onStdout) options.onStdout(chunk); | ||
output.stdout.push(chunk); | ||
}); | ||
stream.stderr.on('data', function (chunk) { | ||
if (options.onStderr) options.onStderr(chunk); | ||
output.stderr.push(chunk); | ||
}); | ||
if (options.stdin) { | ||
stream.write(options.stdin); | ||
stream.end(); | ||
} | ||
stream.on('close', function (code, signal) { | ||
resolve({ code: code, signal: signal, stdout: output.stdout.join('').trim(), stderr: output.stderr.join('').trim() }); | ||
}); | ||
}, reject)); | ||
}); | ||
}); | ||
execCommand(givenCommand, options = {}) { | ||
var _this5 = this; | ||
function execCommand(_x7) { | ||
return _ref5.apply(this, arguments); | ||
return _asyncToGenerator(function* () { | ||
let command = givenCommand; | ||
const connection = _this5.connection; | ||
(0, _assert.default)(connection, 'Not connected to server'); | ||
(0, _assert.default)(typeof options === 'object' && options, 'options must be an Object'); | ||
(0, _assert.default)(!options.cwd || typeof options.cwd === 'string', 'options.cwd must be a string'); | ||
(0, _assert.default)(!options.stdin || typeof options.stdin === 'string', 'options.stdin must be a string'); | ||
(0, _assert.default)(!options.options || typeof options.options === 'object', 'options.options must be an object'); | ||
if (options.cwd) { | ||
// NOTE: Output piping cd command to hide directory non-existent errors | ||
command = `cd ${(0, _shellEscape.default)([options.cwd])} 1> /dev/null 2> /dev/null; ${command}`; | ||
} | ||
return execCommand; | ||
}() | ||
}, { | ||
key: 'getFile', | ||
value: function () { | ||
var _ref6 = _asyncToGenerator(function* (localFile, remoteFile) { | ||
var givenSftp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
var givenOpts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
const output = { | ||
stdout: [], | ||
stderr: [] | ||
}; | ||
return new Promise(function (resolve, reject) { | ||
connection.exec(command, options.options || {}, Helpers.generateCallback(function (stream) { | ||
stream.on('data', function (chunk) { | ||
if (options.onStdout) options.onStdout(chunk); | ||
output.stdout.push(chunk); | ||
}); | ||
stream.stderr.on('data', function (chunk) { | ||
if (options.onStderr) options.onStderr(chunk); | ||
output.stderr.push(chunk); | ||
}); | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)(typeof localFile === 'string' && localFile, 'localFile must be a string'); | ||
(0, _assert2.default)(typeof remoteFile === 'string' && remoteFile, 'remoteFile must be a string'); | ||
(0, _assert2.default)(!givenSftp || (typeof givenSftp === 'undefined' ? 'undefined' : _typeof(givenSftp)) === 'object', 'sftp must be an object'); | ||
(0, _assert2.default)(!givenOpts || (typeof givenOpts === 'undefined' ? 'undefined' : _typeof(givenOpts)) === 'object', 'opts must be an object'); | ||
if (options.stdin) { | ||
stream.write(options.stdin); | ||
stream.end(); | ||
} | ||
var opts = givenOpts || {}; | ||
var sftp = givenSftp || (yield this.requestSFTP()); | ||
try { | ||
yield new Promise(function (resolve, reject) { | ||
sftp.fastGet(remoteFile, localFile, opts, Helpers.generateCallback(resolve, reject)); | ||
stream.on('close', function (code, signal) { | ||
resolve({ | ||
code, | ||
signal, | ||
stdout: output.stdout.join('').trim(), | ||
stderr: output.stderr.join('').trim() | ||
}); | ||
}); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
} | ||
}, reject)); | ||
}); | ||
})(); | ||
} | ||
function getFile(_x9, _x10) { | ||
return _ref6.apply(this, arguments); | ||
getFile(localFile, remoteFile, givenSftp = null, givenOpts = null) { | ||
var _this6 = this; | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this6.connection, 'Not connected to server'); | ||
(0, _assert.default)(typeof localFile === 'string' && localFile, 'localFile must be a string'); | ||
(0, _assert.default)(typeof remoteFile === 'string' && remoteFile, 'remoteFile must be a string'); | ||
(0, _assert.default)(!givenSftp || typeof givenSftp === 'object', 'sftp must be an object'); | ||
(0, _assert.default)(!givenOpts || typeof givenOpts === 'object', 'opts must be an object'); | ||
const opts = givenOpts || {}; | ||
const sftp = givenSftp || (yield _this6.requestSFTP()); | ||
try { | ||
yield new Promise(function (resolve, reject) { | ||
sftp.fastGet(remoteFile, localFile, opts, Helpers.generateCallback(resolve, reject)); | ||
}); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
} | ||
})(); | ||
} | ||
return getFile; | ||
}() | ||
}, { | ||
key: 'putFile', | ||
value: function () { | ||
var _ref7 = _asyncToGenerator(function* (localFile, remoteFile) { | ||
var givenSftp = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
var givenOpts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null; | ||
putFile(localFile, remoteFile, givenSftp = null, givenOpts = null) { | ||
var _this7 = this; | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)(typeof localFile === 'string' && localFile, 'localFile must be a string'); | ||
(0, _assert2.default)(typeof remoteFile === 'string' && remoteFile, 'remoteFile must be a string'); | ||
(0, _assert2.default)(!givenSftp || (typeof givenSftp === 'undefined' ? 'undefined' : _typeof(givenSftp)) === 'object', 'sftp must be an object'); | ||
(0, _assert2.default)(!givenOpts || (typeof givenOpts === 'undefined' ? 'undefined' : _typeof(givenOpts)) === 'object', 'opts must be an object'); | ||
(0, _assert2.default)((yield Helpers.exists(localFile)), 'localFile does not exist at ' + localFile); | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this7.connection, 'Not connected to server'); | ||
(0, _assert.default)(typeof localFile === 'string' && localFile, 'localFile must be a string'); | ||
(0, _assert.default)(typeof remoteFile === 'string' && remoteFile, 'remoteFile must be a string'); | ||
(0, _assert.default)(!givenSftp || typeof givenSftp === 'object', 'sftp must be an object'); | ||
(0, _assert.default)(!givenOpts || typeof givenOpts === 'object', 'opts must be an object'); | ||
(0, _assert.default)((yield Helpers.exists(localFile)), `localFile does not exist at ${localFile}`); | ||
const that = _this7; | ||
const opts = givenOpts || {}; | ||
const sftp = givenSftp || (yield _this7.requestSFTP()); | ||
var that = this; | ||
var opts = givenOpts || {}; | ||
var sftp = givenSftp || (yield this.requestSFTP()); | ||
function putFile(retry) { | ||
return new Promise(function (resolve, reject) { | ||
sftp.fastPut(localFile, remoteFile, opts, Helpers.generateCallback(resolve, function (error) { | ||
if (error.message === 'No such file' && retry) { | ||
resolve(that.mkdir(_path.default.dirname(remoteFile), 'sftp', sftp).then(() => putFile(false))); | ||
} else { | ||
reject(error); | ||
} | ||
})); | ||
}); | ||
} | ||
function putFile(retry) { | ||
return new Promise(function (resolve, reject) { | ||
sftp.fastPut(localFile, remoteFile, opts, Helpers.generateCallback(resolve, function (error) { | ||
if (error.message === 'No such file' && retry) { | ||
resolve(that.mkdir(_path2.default.dirname(remoteFile), 'sftp', sftp).then(function () { | ||
return putFile(false); | ||
})); | ||
} else { | ||
reject(error); | ||
} | ||
})); | ||
}); | ||
try { | ||
yield putFile(true); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
} | ||
})(); | ||
} | ||
try { | ||
yield putFile(true); | ||
} finally { | ||
if (!givenSftp) { | ||
sftp.end(); | ||
} | ||
} | ||
}); | ||
putFiles(files, givenConfig = {}) { | ||
var _this8 = this; | ||
function putFile(_x13, _x14) { | ||
return _ref7.apply(this, arguments); | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this8.connection, 'Not connected to server'); | ||
(0, _assert.default)(Array.isArray(files), 'files must be an array'); | ||
for (let i = 0, length = files.length; i < length; ++i) { | ||
const file = files[i]; | ||
(0, _assert.default)(file, 'files items must be valid objects'); | ||
(0, _assert.default)(file.local && typeof file.local === 'string', `files[${i}].local must be a string`); | ||
(0, _assert.default)(file.remote && typeof file.remote === 'string', `files[${i}].remote must be a string`); | ||
} | ||
return putFile; | ||
}() | ||
}, { | ||
key: 'putFiles', | ||
value: function () { | ||
var _ref8 = _asyncToGenerator(function* (files) { | ||
var _this3 = this; | ||
const transferred = []; | ||
const config = Helpers.normalizePutFilesOptions(givenConfig); | ||
const sftp = config.sftp || (yield _this8.requestSFTP()); | ||
var givenConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
try { | ||
yield (0, _pMap.default)(files, | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref = _asyncToGenerator(function* (file) { | ||
yield _this8.putFile(file.local, file.remote, sftp, config.sftpOptions); | ||
transferred.push(file); | ||
}); | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)(Array.isArray(files), 'files must be an array'); | ||
for (var i = 0, length = files.length; i < length; ++i) { | ||
var file = files[i]; | ||
(0, _assert2.default)(file, 'files items must be valid objects'); | ||
(0, _assert2.default)(file.local && typeof file.local === 'string', 'files[' + i + '].local must be a string'); | ||
(0, _assert2.default)(file.remote && typeof file.remote === 'string', 'files[' + i + '].remote must be a string'); | ||
return function (_x) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
}()); | ||
} catch (error) { | ||
error.transferred = transferred; | ||
throw error; | ||
} finally { | ||
if (!sftp) { | ||
sftp.end(); | ||
} | ||
} | ||
})(); | ||
} | ||
var transferred = []; | ||
var config = Helpers.normalizePutFilesOptions(givenConfig); | ||
var sftp = config.sftp || (yield this.requestSFTP()); | ||
putDirectory(localDirectory, remoteDirectory, givenConfig = {}) { | ||
var _this9 = this; | ||
try { | ||
yield (0, _pMap2.default)(files, function () { | ||
var _ref9 = _asyncToGenerator(function* (file) { | ||
yield _this3.putFile(file.local, file.remote, sftp, config.sftpOptions); | ||
transferred.push(file); | ||
}); | ||
return _asyncToGenerator(function* () { | ||
(0, _assert.default)(_this9.connection, 'Not connected to server'); | ||
(0, _assert.default)(typeof localDirectory === 'string' && localDirectory, 'localDirectory must be a string'); | ||
(0, _assert.default)(typeof remoteDirectory === 'string' && remoteDirectory, 'remoteDirectory must be a string'); | ||
(0, _assert.default)((yield Helpers.exists(localDirectory)), `localDirectory does not exist at ${localDirectory}`); | ||
(0, _assert.default)((yield Helpers.stat(localDirectory)).isDirectory(), `localDirectory is not a directory at ${localDirectory}`); | ||
(0, _assert.default)(typeof givenConfig === 'object' && givenConfig, 'config must be an object'); | ||
const config = Helpers.normalizePutDirectoryOptions(givenConfig); | ||
const sftp = config.sftp || (yield _this9.requestSFTP()); | ||
const scanned = yield (0, _sbScandir.default)(localDirectory, config.recursive, config.validate); | ||
const files = scanned.files.map(i => _path.default.relative(localDirectory, i)); | ||
const directories = scanned.directories.map(i => _path.default.relative(localDirectory, i)); | ||
let failed = false; | ||
let directoriesQueue = Promise.resolve(); | ||
const directoriesCreated = new Set(); | ||
return function (_x19) { | ||
return _ref9.apply(this, arguments); | ||
}; | ||
}()); | ||
} catch (error) { | ||
error.transferred = transferred; | ||
throw error; | ||
} finally { | ||
if (!sftp) { | ||
sftp.end(); | ||
const createDirectory = | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref2 = _asyncToGenerator(function* (path) { | ||
if (!directoriesCreated.has(path)) { | ||
directoriesCreated.add(path); | ||
directoriesQueue = directoriesQueue.then(() => _this9.mkdir(path, 'sftp', sftp)); | ||
yield directoriesQueue; | ||
} | ||
} | ||
}); | ||
}); | ||
function putFiles(_x17) { | ||
return _ref8.apply(this, arguments); | ||
} | ||
return function createDirectory(_x2) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
}(); | ||
return putFiles; | ||
}() | ||
}, { | ||
key: 'putDirectory', | ||
value: function () { | ||
var _ref10 = _asyncToGenerator(function* (localDirectory, remoteDirectory) { | ||
var _this4 = this; | ||
try { | ||
yield (0, _pMap.default)(files, | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref3 = _asyncToGenerator(function* (file) { | ||
const localFile = _path.default.join(localDirectory, file); | ||
var givenConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
const remoteFile = _path.default.join(remoteDirectory, file).split(_path.default.sep).join('/'); | ||
(0, _assert2.default)(this.connection, 'Not connected to server'); | ||
(0, _assert2.default)(typeof localDirectory === 'string' && localDirectory, 'localDirectory must be a string'); | ||
(0, _assert2.default)(typeof remoteDirectory === 'string' && remoteDirectory, 'localDirectory must be a string'); | ||
(0, _assert2.default)((yield Helpers.exists(localDirectory)), 'localDirectory does not exist at ' + localDirectory); | ||
(0, _assert2.default)((yield Helpers.stat(localDirectory)).isDirectory(), 'localDirectory is not a directory at ' + localDirectory); | ||
(0, _assert2.default)((typeof givenConfig === 'undefined' ? 'undefined' : _typeof(givenConfig)) === 'object' && givenConfig, 'config must be an object'); | ||
const remoteFileDirectory = _path.default.dirname(remoteFile); | ||
var config = Helpers.normalizePutDirectoryOptions(givenConfig); | ||
var sftp = config.sftp || (yield this.requestSFTP()); | ||
yield createDirectory(remoteFileDirectory); | ||
var scanned = yield (0, _sbScandir2.default)(localDirectory, config.recursive, config.validate); | ||
var files = scanned.files.map(function (i) { | ||
return _path2.default.relative(localDirectory, i); | ||
}); | ||
var directories = scanned.directories.map(function (i) { | ||
return _path2.default.relative(localDirectory, i); | ||
}); | ||
var failed = false; | ||
var directoriesQueue = Promise.resolve(); | ||
var directoriesCreated = new Set(); | ||
var createDirectory = function () { | ||
var _ref11 = _asyncToGenerator(function* (path) { | ||
if (!directoriesCreated.has(path)) { | ||
directoriesCreated.add(path); | ||
directoriesQueue = directoriesQueue.then(function () { | ||
return _this4.mkdir(path, 'sftp', sftp); | ||
}); | ||
yield directoriesQueue; | ||
try { | ||
yield _this9.putFile(localFile, remoteFile, sftp, config.sftpOptions); | ||
config.tick(localFile, remoteFile, null); | ||
} catch (_) { | ||
failed = true; | ||
config.tick(localFile, remoteFile, _); | ||
} | ||
}); | ||
return function createDirectory(_x23) { | ||
return _ref11.apply(this, arguments); | ||
return function (_x3) { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
}(); | ||
}(), { | ||
concurrency: config.concurrency | ||
}); | ||
yield (0, _pMap.default)(directories, | ||
/*#__PURE__*/ | ||
function () { | ||
var _ref4 = _asyncToGenerator(function* (entry) { | ||
const remoteEntry = _path.default.join(remoteDirectory, entry).split(_path.default.sep).join('/'); | ||
try { | ||
yield (0, _pMap2.default)(files, function () { | ||
var _ref12 = _asyncToGenerator(function* (file) { | ||
var localFile = _path2.default.join(localDirectory, file); | ||
var remoteFile = _path2.default.join(remoteDirectory, file).split(_path2.default.sep).join('/'); | ||
var remoteFileDirectory = _path2.default.dirname(remoteFile); | ||
yield createDirectory(remoteFileDirectory); | ||
try { | ||
yield _this4.putFile(localFile, remoteFile, sftp, config.sftpOptions); | ||
config.tick(localFile, remoteFile, null); | ||
} catch (_) { | ||
failed = true; | ||
config.tick(localFile, remoteFile, _); | ||
} | ||
}); | ||
yield createDirectory(remoteEntry); | ||
}); | ||
return function (_x24) { | ||
return _ref12.apply(this, arguments); | ||
}; | ||
}(), { concurrency: config.concurrency }); | ||
yield (0, _pMap2.default)(directories, function () { | ||
var _ref13 = _asyncToGenerator(function* (entry) { | ||
var remoteEntry = _path2.default.join(remoteDirectory, entry).split(_path2.default.sep).join('/'); | ||
yield createDirectory(remoteEntry); | ||
}); | ||
return function (_x25) { | ||
return _ref13.apply(this, arguments); | ||
}; | ||
}(), { concurrency: config.concurrency }); | ||
} finally { | ||
if (!config.sftp) { | ||
sftp.end(); | ||
} | ||
return function (_x4) { | ||
return _ref4.apply(this, arguments); | ||
}; | ||
}(), { | ||
concurrency: config.concurrency | ||
}); | ||
} finally { | ||
if (!config.sftp) { | ||
sftp.end(); | ||
} | ||
} | ||
return !failed; | ||
}); | ||
return !failed; | ||
})(); | ||
} | ||
function putDirectory(_x20, _x21) { | ||
return _ref10.apply(this, arguments); | ||
} | ||
return putDirectory; | ||
}() | ||
}, { | ||
key: 'dispose', | ||
value: function dispose() { | ||
if (this.connection) { | ||
this.connection.end(); | ||
} | ||
dispose() { | ||
if (this.connection) { | ||
this.connection.end(); | ||
} | ||
}]); | ||
} | ||
return SSH; | ||
}(); | ||
} | ||
module.exports = SSH; |
{ | ||
"name": "node-ssh", | ||
"version": "5.1.2", | ||
"version": "6.0.0", | ||
"description": "SS2 with Promises", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "(apm test) && (flow check) && (eslint . ) && (prettier -l '{src,spec}/**/*.js')", | ||
"build": "sb-babel-cli -o lib src", | ||
"watch": "npm run build -- -w" | ||
"test:spec": "ava spec/*-spec.js", | ||
"test:flow": "flow check", | ||
"test:lint": "eslint .", | ||
"test:prettier": "prettier -l '{src,spec}/**/*.js'", | ||
"test": "(npm run test:spec) && (npm run test:flow) && (npm run test:lint) && (npm run test:prettier)", | ||
"prepare": "sb-babel-cli -o lib src", | ||
"watch": "npm run prepare -- -w" | ||
}, | ||
@@ -26,20 +30,29 @@ "repository": { | ||
"dependencies": { | ||
"p-map": "^1.2.0", | ||
"p-map": "^2.1.0", | ||
"sb-promisify": "^2.0.1", | ||
"sb-scandir": "^2.0.0", | ||
"shell-escape": "^0.2.0", | ||
"ssh2": "^0.5.0" | ||
"ssh2": "^0.8.2" | ||
}, | ||
"devDependencies": { | ||
"babel-core": "^6.26.0", | ||
"babel-preset-steelbrain": "^5.0.3", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-config-steelbrain": "^4.0.1", | ||
"flow-bin": "^0.63.1", | ||
"jasmine-fix": "^1.3.1", | ||
"prettier": "^1.10.2", | ||
"@babel/core": "^7.4.3", | ||
"@babel/preset-env": "^7.4.3", | ||
"@babel/preset-flow": "^7.0.0", | ||
"@babel/register": "^7.4.0", | ||
"ava": "^1.4.1", | ||
"eslint-config-steelbrain": "^7.0.0", | ||
"flow-bin": "^0.97.0", | ||
"prettier": "^1.17.0", | ||
"pty.js": "^0.3.1", | ||
"sb-babel-cli": "0.1.1", | ||
"ssh2-streams": "^0.1.20" | ||
"sb-babel-cli": "^1.2.1", | ||
"ssh2-streams": "^0.4.2" | ||
}, | ||
"ava": { | ||
"files": [ | ||
"spec/*.js" | ||
], | ||
"require": [ | ||
"@babel/register" | ||
] | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
13
33635
11
503
1
+ Addedbcrypt-pbkdf@1.0.2(transitive)
+ Addedp-map@2.1.0(transitive)
+ Addedssh2@0.8.9(transitive)
+ Addedssh2-streams@0.4.10(transitive)
+ Addedtweetnacl@0.14.5(transitive)
- Removedsemver@5.7.2(transitive)
- Removedssh2@0.5.5(transitive)
- Removedssh2-streams@0.1.20(transitive)
Updatedp-map@^2.1.0
Updatedssh2@^0.8.2