ssh2-sftp-client 5.3.1 → 7.0.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.
package/CHANGELOG.org CHANGED
@@ -1,38 +1,69 @@
1
1
  * Change Logging
2
2
 
3
- ** V5.3.1 (Prod Version)
3
+ ** V7.0.0
4
+ - New version based on new SSH2 version 1.1.0.
5
+ - Expand option handling for get() and put() methods *Breaking Change*
6
+ - Re-factored the retry code in the connect() method
7
+ - Improve error reporting for adding/removing listeners
8
+ - Extend localExists() method to also verify read or write access
9
+
10
+ ** V6.0.1
11
+ - Fix issue with connect retry not releasing 'ready' listeners
12
+ - Add finally clauses to all promises to ensure temporary listeners are deleted
13
+ - Add nyc module to report on code test coverage
14
+ - Add additional utils tests to increase test coverage
15
+ - Removed some dead code and unused utility functions to reduce download size
16
+ - Cleanup tests and reduce inter-test dependencies
17
+
18
+ ** V6.0.0.0
19
+ - Update connection retry code to use the promise-retry module instead of
20
+ plain rety module
21
+ - Added optional filter argument for uploadDir/downlDir to select which files
22
+ and directories are included
23
+ - Added an optional boolean argument to delete to turn off raising an error
24
+ when delete target does not exists
25
+ - Reduced/simplified argument verification code to reduce package size and
26
+ increase performance
27
+ - Refactored handling of events and add default close and error listeners to
28
+ catch connections closed abruptly without an error being raised.
29
+
30
+ ** V5.3.2
31
+ - Minor README typo fixes
32
+ - Fix error in local file path checks (#294)
33
+
34
+ ** V5.3.1
4
35
  - Fix bug in handling of relative local paths
5
36
  - Change handling of stream closures in ~get()~ and ~put()~ methods
6
37
 
7
- ** v5.3.0
38
+ ** v5.3.0
8
39
  - Refine event handler management
9
40
  - Fix path processing for win32 based sftp servers
10
- - Update documentation
11
- ** v5.2.2
41
+ - Update documentation
42
+ ** v5.2.2
12
43
  - Bug fix release. Add error code 4 check to stat() method.
13
44
  - bump Mocha version for tests
14
45
 
15
46
  ** v5.2.1
16
47
  - Move some dependencies into dev-Dependencies
17
- ** v5.2.0
18
- - Add new method posixRename() which uses the openSSH POSIX rename extension.
48
+ ** v5.2.0
49
+ - Add new method posixRename() which uses the openSSH POSIX rename extension.
19
50
  ** v5.1.3
20
51
  - Fix bug when writing to root directory and failure due to not being able to
21
52
  determine parent
22
53
  - Refactor some tests to eliminate need to have artificial delays between
23
54
  tests
24
55
  - Bumped some dependency versions to latest version
25
- ** v5.1.2
56
+ ** v5.1.2
26
57
  - Added back global close handler
27
58
  - Added dumpListeners() method
28
-
29
- ** v5.1.1
30
- - Added separate close handlers to each method.
59
+
60
+ ** v5.1.1
61
+ - Added separate close handlers to each method.
31
62
  - Added missing return statement in connect method
32
- - Added additional troubleshooting documentation for
63
+ - Added additional troubleshooting documentation for
33
64
  common errors.
34
65
 
35
- ** v5.1.0
66
+ ** v5.1.0
36
67
  - Fix bug in checkRemotePath() relating to handling of badly
37
68
  specified paths (issue #213)
38
69
  - Added additional debugging support
package/README.md CHANGED
@@ -1,22 +1,7 @@
1
1
  - [Overview](#sec-1)
2
2
  - [Installation](#sec-2)
3
3
  - [Basic Usage](#sec-3)
4
- - [Version 5.x](#sec-4)
5
- - [Breaking Changes in Version 5.x](#sec-4-1)
6
- - [Error Event Handling](#sec-4-1-1)
7
- - [Technical Details](#sec-4-1-2)
8
- - [New Methods](#sec-4-2)
9
- - [Version 5.0.1](#sec-4-3)
10
- - [Version 5.0.2](#sec-4-4)
11
- - [Version 5.1.0](#sec-4-5)
12
- - [Version 5.1.1](#sec-4-6)
13
- - [Version 5.1.2](#sec-4-7)
14
- - [Version 5.1.3](#sec-4-8)
15
- - [Version 5.2.0](#sec-4-9)
16
- - [Version 5.2.1](#sec-4-10)
17
- - [Version 5.2.2](#sec-4-11)
18
- - [Version 5.3.0](#sec-4-12)
19
- - [Version 5.3.1](#sec-4-13)
4
+ - [Version 7.x Changes](#sec-4)
20
5
  - [Documentation](#sec-5)
21
6
  - [Specifying Paths](#sec-5-1)
22
7
  - [Methods](#sec-5-2)
@@ -32,14 +17,14 @@
32
17
  - [append(input, remotePath, options) ==> string](#sec-5-2-10)
33
18
  - [mkdir(path, recursive) ==> string](#sec-5-2-11)
34
19
  - [rmdir(path, recursive) ==> string](#sec-5-2-12)
35
- - [delete(path) ==> string](#sec-5-2-13)
20
+ - [delete(path, noErrorOK) ==> string](#sec-5-2-13)
36
21
  - [rename(fromPath, toPath) ==> string](#sec-5-2-14)
37
22
  - [posixRename(fromPath, toPath) ==> string](#sec-5-2-15)
38
23
  - [chmod(path, mode) ==> string](#sec-5-2-16)
39
24
  - [realPath(path) ===> string](#sec-5-2-17)
40
25
  - [cwd() ==> string](#sec-5-2-18)
41
- - [uploadDir(srcDir, dstDir) ==> string](#sec-5-2-19)
42
- - [downloadDir(srcDir, dstDir) ==> string](#sec-5-2-20)
26
+ - [uploadDir(srcDir, dstDir, filter) ==> string](#sec-5-2-19)
27
+ - [downloadDir(srcDir, dstDir, filter) ==> string](#sec-5-2-20)
43
28
  - [end() ==> boolean](#sec-5-2-21)
44
29
  - [Add and Remove Listeners](#sec-5-2-22)
45
30
  - [Platform Quirks & Warnings](#sec-6)
@@ -60,6 +45,8 @@
60
45
  - [Not returning the promise in a `then()` block](#sec-9-1-1)
61
46
  - [Mixing Promise Chains and Async/Await](#sec-9-1-2)
62
47
  - [Try/catch and Error Handlers](#sec-9-1-3)
48
+ - [Server Differences](#sec-9-1-4)
49
+ - [Avoid Concurrent Operations](#sec-9-1-5)
63
50
  - [Debugging Support](#sec-9-2)
64
51
  - [Logging Issues](#sec-10)
65
52
  - [Pull Requests](#sec-11)
@@ -70,18 +57,14 @@
70
57
 
71
58
  an SFTP client for node.js, a wrapper around [SSH2](https://github.com/mscdex/ssh2) which provides a high level convenience abstraction as well as a Promise based API.
72
59
 
73
- Documentation on the methods and available options in the underlying modules can be found on the [SSH2](https://github.com/mscdex/ssh2) and [SSH2-STREAMS](https://github.com/mscdex/ssh2-streams/blob/master/SFTPStream.md) project pages.
60
+ Documentation on the methods and available options in the underlying modules can be found on the [SSH2](https://github.com/mscdex/ssh2) project pages.
74
61
 
75
- Current stable release is **v5.3.1**.
62
+ Current stable release is **v7.0.0**.
76
63
 
77
- Code has been tested against Node versions 12.18.2 and 13.14.0
64
+ Code has been tested against Node versions 12.22.1, 14.17.0 and 16.2.0
78
65
 
79
66
  Node versions < 10.x are not supported.
80
67
 
81
- <span class="underline">WARNING</span> There is currently a regression error with versions of node later than version 14.0. It appears that when using streams with chunk sizes which exceed the high water mark for the stream, a drain event is no longer emitted. As a result, streams with sufficient data will hang indefinitely. This appears to affect fastput, fastget, put and possibly get operations. Until this issue is resolved and a new version of ssh2/ssh2-streams is released, using node v14 is not recommended.
82
-
83
- A bug report hass been logged against the ssh2-streams library as [issue 156](https://github.com/mscdex/ssh2-streams/issues/156).
84
-
85
68
  # Installation<a id="sec-2"></a>
86
69
 
87
70
  ```shell
@@ -108,110 +91,13 @@ sftp.connect({
108
91
  });
109
92
  ```
110
93
 
111
- # Version 5.x<a id="sec-4"></a>
112
-
113
- ## Breaking Changes in Version 5.x<a id="sec-4-1"></a>
114
-
115
- - The auxList() method has been removed. This method was flagged as deprecated in version 4.x. The functionality provided by `auxList()` is available in `list()`, making `auxList()` unnecessary.
116
- - The realPath() method now returns `''` if the path does not exist rather than throwing an exception.
117
- - Improved error handling. The `ssh2` and `ssh2-streams` libraries use events to signal errors. Providing a clean Promise based API and managing these events can be challenging as an error event can fire at any time (including in-between the resolution of one promise and the commencement of another). As you cannot use `try/catch` blocks to reliably manage error events (for a similar reason - see Node's event documentation for details), a slightly more complex solution was required. See the section below on Error Event Handling for more details. In basic terms, a default handler is now used that will log the error and clear the SFTP connection if no Promise error handler has handled the error. This prevents the uncaughtException error and provides a reasonably clean way to deal with unexpected errors that fire in-between Promise execution activities.
118
- - Ignore Errors during `end()` processing. At least one SFTP server (Azure SFTP) seems to generate an error in response to the `end()` call. As `end()` has been called, we don't really care if an error occurs provided the connection is closed. Therefore, a new default error listener for the `end()` method has been added that will simply ignore any errors which occur during a call to end the connection.
119
-
120
- ### Error Event Handling<a id="sec-4-1-1"></a>
121
-
122
- Providing a clean Promise API for the SSH2 to manage basic SFTP functionality presents a couple of challenges for managing errors. The `SSH2` module uses events to communicate various state changes and error conditions. These events can fire at any time.
123
-
124
- On the client side, we wrap basic SFTP actions in Javascript Promises, allowing clients to use either the standard Promise API or async/await to model SFTP interactions. Creating an SFTP connection returns a promise, which resolves if a connection is successfully established and is rejected otherwise. Downloading a file using `get()` or `fastGet()` generates a new Promise which is either resolved, indicating file has been successfully downloaded or rejected, indicating the download failed. All pretty straight-forward.
125
-
126
- When the Promise is created, an error event handler is added to the SFTP object to catch any errors that fire during the execution of the promise. If an error event fires, the Promise is rejected and the error returned to the client as part of the rejection. After the Promise has resolved or rejected, the error listener is removed (the error listener is specific to each promise because it needs to call the reject method associated with that promise). As a promise can only be resolved or rejected once, after the Promise has completed, the error listener is of no further use.
127
-
128
- This all works fine when an error event fires during the execution of a Promise. However, what about outside promise execution? Consider the following flow;
129
-
130
- 1. You have an active SFTP connection which you use to download a file
131
- 2. When you make the download request, a new Promise is created which will resolve when the file is downloaded or be rejected if the download fails for some reason. The promise resolves successfully.
132
- 3. You start processing the data downloaded. At this point, you still have an open connection to the SFTP server, but you are not actively interacting with it. There is no active Promise in play.
133
- 4. The remote SFTP server resets the connection for some reason, generating a ECONNRESET error that is emitted as an error event.
134
-
135
- What happens at this point? There is no active promise executing, so no Promise specific error handler in play. Your script is off processing the data from the previously downloaded file, so there is no currently executing try/catch block around the SFTP client object. Basically, there is nothing listening of any errors at this point. What will happen?
136
-
137
- Well, basically, the error event will bubble up to the top level of the node process context and cause an uncaughtException error, display the error and dump a stack trace and cause the node process to exit. In basic terms, your process will crash. Not a great outcome.
138
-
139
- There are a number of things we can do to improve the situation. However, nearly all of them have some drawbacks. We could -
140
-
141
- - Add our own error handler. The `client.on()` method would allow you to add your own error handler. This would provide a way to manage error events, but you want to make sure you only handle error events not handled already by the Promise error handlers. Worse yet, you cannot know before hand the processing context of your script at the point the error event fires. This means your error handling is likely to be complex and difficult to manage. Worse yet, these types of errors are quite rare in most situations and your now being required to add significant additional complexity to deal with a rare edge case. However, sometimes, you just need to deal with this sort of complexity and the `client.on()` method does give you that option.
142
- - Another alternative is to just add an uncaughtException handler to your Node process object. This would also prevent node from dumping the error and exiting abruptly. However, now you need to think about ALL the possible uncaughtExceptions which might happen, not just those associated with the SFTP client. Again, things are getting complicated for something which only occurs occasionally. .
143
-
144
- What we really want is a solution which will be simple for the majority of clients, but provide additional power when needed. What we have done is add a default error handler which will only take action if no Promise error handler has fired. All the default error handler does is log the error to console.error() and set the SFTP connection to undefined so that any further attempts to use the connection will throw an error inside the Promise which attempts to use it.
145
-
146
- The advantage of this approach is that it stops the abrupt exiting of the node script due to an uncaught exception error and provides a reasonable outcome for most use cases. For example, in the scenario outlined above, if an error event fires while your script is processing the data already downloaded, it will not impact on your script immediately. An error will be logged to console.error(), but your script will continue to run. Once you have completed processing your data, if you attempt another SFTP call, it will fail with an error about no available SFTP connections. As this will occur within the context of interacting with the SFTP server, your script can take appropriate action to resolve the issue (such as re-connecting to the server). On the other hand, if after processing the file your done and just want to end, then you can just ignore the error, perform any necessary cleanup work and exit successfully.
147
-
148
- ### Technical Details<a id="sec-4-1-2"></a>
149
-
150
- The event handlers added by each Promise are added using the `prependListener()` function. This ensures the handler is fired before any other error handlers which may be defined. As part of the processing, these error handler set a flag property `this.errorHandled` to true, indicating the error has been handled.
151
-
152
- In addition to the Promise error handlers, there is a default error handler which will fire after any Promise error handler. The default error handler looks to see if the `this.errorHandler` flag is true. If it is, it knows the error has been handled and it just resets it to false, taking no other action (so taht we are ready for the next error). If the flag is false, the default handler knows it must handle the error. In this case, the handler will log the error to `console.error()`, will set the SFTP connection to undefined to prevent any further attempts to use it and finally, ensure the `this.errorHandler` flag is reset to false in preparation for the next error.
153
-
154
- ## New Methods<a id="sec-4-2"></a>
155
-
156
- - Added the method uploadDir(). This method will upload a directory (including any subdirectories) to the remote server. Only directories and regular files are uploaded (no symbolic links, FIFOs, socket FDs etc). Will overwrite existing files or directories, but will not delete any remote files or directories.
157
- - Added the method downloadDir(). This method will download a directory (including any subdirectories) to the local file system. Only directories and regular files are downloaded (no symbolic links, FIFOs, socket FDs etc).. Will overwrite existing files or directories, but will not delete any local files in the directories.
158
- - Added the method posixRename(). This method will use the POSIX atomic rename openSSH extension. As this is an extension to the SFTP protocol, not all servers will support this operation.
159
-
160
- ## Version 5.0.1<a id="sec-4-3"></a>
161
-
162
- - The error checking was a little too stringent. The use of exist() to test for file types had a problem when the user does not have read/execute rights on the directory. Replaced with stat() method, which should avoid this issue.
163
-
164
- ## Version 5.0.2<a id="sec-4-4"></a>
165
-
166
- - Fix error in local directory tests due to missing await statement.
167
- - Fix path handling under win32. Paths were not being parsed correctly due to the use of path.posix.parse() instead of path.parse().
168
-
169
- ## Version 5.1.0<a id="sec-4-5"></a>
170
-
171
- - Add missing connection check in end() method
172
- - Add debugging support. Now adding a debug property to the connection configuration object will enable debugging. The value of the debug property should be a function which accepts a single string argument. Typically, this function will send the value passed in to stderr or a file.
173
- - Fix bug in checkRemotePath() relating to poor path specifications where you cannot determine parent directory.
174
-
175
- ## Version 5.1.1<a id="sec-4-6"></a>
176
-
177
- - Bug fix for unexpected close of connections. It would seem that a connections can be unexpectedly closed without an accompanying error event. As methods only looked for error events, the method promise wold never fulfil and the method would appear to hang. Have now added close event handlers to each method that will reject the promise if the connection is closed unexpectedly.
178
- - Missing return statement in connect method would result in the connect method attempting to re-connect again after it had reached maximum connect retries. Added the missing return statement.
179
- - Added some more troubleshooting documentation. Numerous issues have been raised that turn out to be due to client code failing to return Promises inside promise chains. Common symptom is what appears to be truncated file upload/download. What is really happening is that the end method is being called before the transfer has completed.
94
+ # Version 7.x Changes<a id="sec-4"></a>
180
95
 
181
- ## Version 5.1.2<a id="sec-4-7"></a>
96
+ - This version is based on version 1.1.0 of `ssh2`. This version of `ssh2` is a complete re-write of the `ssh2` library. This re-write addresses issues encountered when using node v14 as well as some design weaknesses in the previous 0.8.x version.
182
97
 
183
- - Mainly a bug fix. We needed to add back a global close listener to ensure the sftp object is unset whenever a close event occurs. As close events can occur outside main method calls, only having method based listeners was not sufficient.
184
- - Also added a utils.dumpListeners() method, useful when debugging issues with listener 'leakage' due to failure to remove listeners when no longer required.
98
+ - **Breaking Change** Expanded option handling for `get()` and `put()` methods. A number of use cases were identified where setting specific options on the read and write streams and the pipe operation are necessary. For example, disabling `autoClose` on streams or the `end` event in pipes. The `options` argument for `get()` and `put()` calls now supports properties for `readStreamOptions`, `writeStreamOptions` and `pipeOptions`. Note that options are only applied to streams created by the `get()` and `put()` methods. Streams passed into these methods are under the control of the client code and therefore cannot have options supplied in arguments to those streams (you would apply such options when you create the streams). Options are typically only necessary in special use cases. Most of the time, no options are required. However, if you are currently using options to either `put()` or `get()`, you will need to update your code to map these options to the new structure.
185
99
 
186
- ## Version 5.1.3<a id="sec-4-8"></a>
187
-
188
- - Fix issue with permissions for writing to root directory
189
- - Cleanup tests to use less connections and eliminate need for test delays
190
- - Bumped some dependencies to latest versions
191
-
192
- ## Version 5.2.0<a id="sec-4-9"></a>
193
-
194
- - Add posixRename() method. This is an openssh extension added in openssh v4.8 and will only work on servers which support this extension.conflict
195
- - Bumped through2 dependency version to 4.0.2
196
-
197
- ## Version 5.2.1<a id="sec-4-10"></a>
198
-
199
- - Move some dev dependencies from dependencies to devDependencies.
200
-
201
- ## Version 5.2.2<a id="sec-4-11"></a>
202
-
203
- - Bug fix. Some servers appear to issue errors with code 4 instead of code 2 for file not found errors. This version adds checks for error code 4 to the stat() method. Thanks to teenangst for the fix.
204
-
205
- ## Version 5.3.0<a id="sec-4-12"></a>
206
-
207
- - Add code to only add connect() and end() event handlers if they are not already active. For connect(), remove event handlers as late as possible to help catch error events raised late on some platforms (like win32). don't remove end() error handler as some platforms, like win32, send an additional error event even after a successful and requested end() call.
208
- - Fix path handling when connecting to a remoe SFTP server running on win32 platform. Assume server honours 'nix' path convention rather than using native win32 path format.
209
- - Add additional documentation on events/promises, platform quirks and platform differences.
210
-
211
- ## Version 5.3.1<a id="sec-4-13"></a>
212
-
213
- - Fix bug in handling of relative local paths
214
- - Modified `get()` and `put()` methods to support special purpose streams which require `autoClose` to be `false`. These methods will now look for the `autoClose: false` property in the options object and if it is false, will issue a `destroy()` on the underlying stream just before the promise is resolved. The default is `autoClose: true` and this default should be used unless there is a known specific reason to change it to false.
100
+ - Improved event handling. A listener for a global error event is now defined to catch errors which occur in-between method calls i.e. connection lost in-between calls to the library methods. A new mechanism has also been added for removal of listeners when no longer required.
215
101
 
216
102
  # Documentation<a id="sec-5"></a>
217
103
 
@@ -221,7 +107,7 @@ All the methods will return a Promise, except for `on()` and `removeListener()`,
221
107
 
222
108
  ## Specifying Paths<a id="sec-5-1"></a>
223
109
 
224
- The convention with both FTP and SFTP is that paths are specified using a 'nix' style i.e. use '*' as the path separator. This means that even if your SFTP server is running on a win32 platform, you should use '*' instead of '\\' as the path separator. For example, for a win32 path of 'C:\Users\fred' you would actually use '/C:/Users/fred'. If your win32 server does not support the 'nix' path convention, you can try setting the `remotePathSep` property of the `SftpClient` object to the path separator of your remote server. This **might** work, but has not been tested. Please let me know if you need to do this and provide details of the SFTP server so that I can try to create an appropriate environment and adjust things as necessary. At this point, I'm not aware of any win32 based SFTP servers which do not support the 'nix' path convention.
110
+ The convention with both FTP and SFTP is that paths are specified using a 'nix' style i.e. use `/` as the path separator. This means that even if your SFTP server is running on a win32 platform, you should use `/` instead of `\` as the path separator. For example, for a win32 path of `C:\Users\fred` you would actually use `/C:/Users/fred`. If your win32 server does not support the 'nix' path convention, you can try setting the `remotePathSep` property of the `SftpClient` object to the path separator of your remote server. This **might** work, but has not been tested. Please let me know if you need to do this and provide details of the SFTP server so that I can try to create an appropriate environment and adjust things as necessary. At this point, I'm not aware of any win32 based SFTP servers which do not support the 'nix' path convention.
225
111
 
226
112
  All remote paths must either be absolute e.g. `/absolute/path/to/file` or they can be relative with a prefix of either `./` (relative to current remote directory) or `../` (relative to parent of current remote directory) e.g. `./relative/path/to/file` or `../relative/to/parent/file`. It is also possible to do things like `../../../file` to specify the parent of the parent of the parent of the current remote directory. The shell tilde (`~`) and common environment variables like `$HOME` are NOT supported.
227
113
 
@@ -309,7 +195,7 @@ Connect to an sftp server. Full documentation for connection options is availabl
309
195
  password: 'borsch', // string Password for password-based user authentication
310
196
  agent: process.env.SSH_AGENT, // string - Path to ssh-agent's UNIX socket
311
197
  privateKey: fs.readFileSync('/path/to/key'), // Buffer or string that contains
312
- passphrase; 'a pass phrase', // string - For an encrypted private key
198
+ passphrase: 'a pass phrase', // string - For an encrypted private key
313
199
  readyTimeout: 20000, // integer How long (in ms) to wait for the SSH handshake
314
200
  strictVendor: true // boolean - Performs a strict server vendor check
315
201
  debug: myDebug // function - Set this to a function that receives a single
@@ -510,16 +396,21 @@ In general, if your going to pass in a string as the destination, you are better
510
396
 
511
397
  1. Options
512
398
 
513
- The options object can be used to pass options to the underlying readStream used to read the data from the remote server.
399
+ The `options` argument can be used to pass options to the underlying streams and pipe call used by this method. The argument is an object with three possible properties, `readStreamOptions`, `writeStreamOptions` and `pipeOptions`. The values for each of these properties should be an object containing the required options. For example, possible read stream and pipe options could be defined as
514
400
 
515
401
  ```javascript
516
- {
517
- flags: 'r',
518
- encoding: null,
519
- handle: null,
520
- mode: 0o666,
521
- autoClose: true
522
- }
402
+ let options = {
403
+ readStreamOptions: {
404
+ flags: 'r',
405
+ encoding: null,
406
+ handle: null,
407
+ mode: 0o666,
408
+ autoClose: true
409
+ },
410
+ pipeOptions: {
411
+ end: false
412
+ }};
413
+
523
414
  ```
524
415
 
525
416
  Most of the time, you won't want to use any options. Sometimes, it may be useful to set the encoding. For example, to 'utf-8'. However, it is important not to do this for binary files to avoid data corruption.
@@ -592,19 +483,20 @@ Upload data from local system to remote server. If the `src` argument is a strin
592
483
 
593
484
  - **src:** string | buffer | readable stream. Data source for data to copy to the remote server.
594
485
  - **remotePath:** string. Path to the remote file to be created on the server.
595
- - **options:** object. Options which can be passed to adjust the write stream used in sending the data to the remote server (see below).
486
+ - **options:** object. Options which can be passed to adjust the read and write stream used in sending the data to the remote server or the pipe call used to make the data transfer (see below).
596
487
 
597
488
  1. Options
598
489
 
599
- The following options are supported;
490
+ The options object supports three properties, `readStreamOptions`, `writeStreamOptions` and `pipeOptions`. The value for each property should be an object with options as properties and their associated values representing the option value. For example, you might use the following to set `writeStream` options.
600
491
 
601
492
  ```javascript
602
493
  {
603
- flags: 'w', // w - write and a - append
604
- encoding: null, // use null for binary files
605
- mode: 0o666, // mode to use for created file (rwx)
606
- autoClose: true // automatically close the write stream when finished
607
- }
494
+ writeStreamOptions: {
495
+ flags: 'w', // w - write and a - append
496
+ encoding: null, // use null for binary files
497
+ mode: 0o666, // mode to use for created file (rwx)
498
+ autoClose: true // automatically close the write stream when finished
499
+ }}
608
500
  ```
609
501
 
610
502
  The most common options to use are mode and encoding. The values shown above are the defaults. You do not have to set encoding to utf-8 for text files, null is fine for all file types. However, using utf-8 encoding for binary files will often result in data corruption.
@@ -765,12 +657,14 @@ Remove a directory. If removing a directory and recursive flag is set to `true`,
765
657
  });
766
658
  ```
767
659
 
768
- ### delete(path) ==> string<a id="sec-5-2-13"></a>
660
+ ### delete(path, noErrorOK) ==> string<a id="sec-5-2-13"></a>
769
661
 
770
662
  Delete a file on the remote server.
771
663
 
772
664
  - **path:** string. Path to remote file to be deleted.
773
665
 
666
+ - **noErrorOK:** boolean. If true, no error is raised when you try to delete a non-existent file. Default is false.
667
+
774
668
  1. Example Use
775
669
 
776
670
  ```javascript
@@ -850,7 +744,7 @@ Change the mode (read, write or execute permissions) of a remote file or directo
850
744
 
851
745
  ```javascript
852
746
  let path = '/path/to/remote/file.txt';
853
- let ndwMode = 0o644; // rw-r-r
747
+ let newMode = 0o644; // rw-r-r
854
748
  let client = new Client();
855
749
 
856
750
  client.connect(config)
@@ -877,14 +771,17 @@ Converts a relative path to an absolute path on the remote server. This method i
877
771
 
878
772
  Returns what the server believes is the current remote working directory.
879
773
 
880
- ### uploadDir(srcDir, dstDir) ==> string<a id="sec-5-2-19"></a>
774
+ ### uploadDir(srcDir, dstDir, filter) ==> string<a id="sec-5-2-19"></a>
881
775
 
882
776
  Upload the directory specified by `srcDir` to the remote directory specified by `dstDir`. The `dstDir` will be created if necessary. Any sub directories within `srcDir` will also be uploaded. Any existing files in the remote path will be overwritten.
883
777
 
884
778
  The upload process also emits 'upload' events. These events are fired for each successfully uploaded file. The `upload` event calls listeners with 1 argument, an object which has properties source and destination. The source property is the path of the file uploaded and the destination property is the path to where the file was uploaded to. The purpose of this event is to provide some way for client code to get feedback on the upload progress. You can add your own lisener using the `on()` method.
885
779
 
780
+ The optionsl *filter* argument is a regular expression which can be used to select which files and directories to include in the upload.
781
+
886
782
  - **srcDir:** A local file path specified as a string
887
783
  - **dstDir:** A remote file path specified as a string
784
+ - **filter:** A regular expression used to filter which files and directories to include in the upload
888
785
 
889
786
  1. Example
890
787
 
@@ -934,14 +831,17 @@ The upload process also emits 'upload' events. These events are fired for each s
934
831
 
935
832
  ```
936
833
 
937
- ### downloadDir(srcDir, dstDir) ==> string<a id="sec-5-2-20"></a>
834
+ ### downloadDir(srcDir, dstDir, filter) ==> string<a id="sec-5-2-20"></a>
938
835
 
939
836
  Download the remote directory specified by `srcDir` to the local file system directory specified by `dstDir`. The `dstDir` directory will be created if required. All sub directories within `srcDir` will also be copied. Any existing files in the local path will be overwritten. No files in the local path will be deleted.
940
837
 
941
838
  The method also emites `download` events to provide a way to monitor download progress. The download event listener is called with one argument, an object with two properties, source and destination. The source property is the path to the remote file that has been downloaded and the destination is the local path to where the file was downloaded to. You can add a listener for this event using the `on()` method.
942
839
 
840
+ The optional *filter* argument is a regular expression which can be used to select which files and directories will be downloaded from the remote server.
841
+
943
842
  - **srcDir:** A remote file path specified as a string
944
843
  - **dstDir:** A local file path specified as a string
844
+ - **filter:** A regular expression used to match the files and directories to be downloaded
945
845
 
946
846
  1. Example
947
847
 
@@ -1032,7 +932,7 @@ Although normally not required, you can add and remove custom listeners on the s
1032
932
 
1033
933
  ## Server Capabilities<a id="sec-6-1"></a>
1034
934
 
1035
- All SFTP servers and platforms are not equal. Some facilities provided by `ssh2-sfto-client` either depend on capabilities of the remote server or the underlying capabilities of the remote server platform. As an example, consider `chmod()`. This command depends on a remote filesystem which implements the 'nix' concept of users and groups. The *win32* platform does not have the same concept of users and groups, so `chmod()` will not behave in the same way.
935
+ All SFTP servers and platforms are not equal. Some facilities provided by `ssh2-sftp-client` either depend on capabilities of the remote server or the underlying capabilities of the remote server platform. As an example, consider `chmod()`. This command depends on a remote filesystem which implements the 'nix' concept of users and groups. The *win32* platform does not have the same concept of users and groups, so `chmod()` will not behave in the same way.
1036
936
 
1037
937
  One way to determine whether an issue you are encountering is due to `ssh2-sftp-client` or due to the remote server or server platform is to use a simple CLI sftp program, such as openSSH's sftp command. If you observe the same behaviour using plain `sftp` on the command line, the issue is likely due to server or remote platform limitations. Note that you should not use a GUI sftp client, like `Filezilla` or `winSCP` as such GUI programs often attempt to hide these server and platform incompatibilities and will take additional steps to simulate missing functionality etc. You want to use a CLI program which does as little as possible.
1038
938
 
@@ -1248,7 +1148,7 @@ If you run into an issue which is not repeatable with just the `ssh2` and `ssh2-
1248
1148
 
1249
1149
  Note also that in the repository there are two useful directories. The first is the examples directory, which contain some examples of using `ssh2-sftp-client` to perform common tasks. A few minutes reviewing these examples can provide that additional bit of detail to help fix any problems you are encountering.
1250
1150
 
1251
- The second directory is the tools directory. I have some very basic simple scripts in this directory which perform basic tasks using only the `ssh2` and `ssh2-streams` modules (no ssh2-sftp-client module). These can be useful when trying to determine if the issue is with the underlying `ssh2` and `ssh2-streams` modules.
1151
+ The second directory is the validation directory. I have some very simple scripts in this directory which perform basic tasks using only the `ssh2` modules (no `ssh2-sftp-client` module). These can be useful when trying to determine if the issue is with the underlying `ssh2` module or the `ssh2-sftp-client` wrapper module.
1252
1152
 
1253
1153
  ## Common Errors<a id="sec-9-1"></a>
1254
1154
 
@@ -1256,7 +1156,7 @@ There are some common errors people tend to make when using Promises or Asyc/Awa
1256
1156
 
1257
1157
  ### Not returning the promise in a `then()` block<a id="sec-9-1-1"></a>
1258
1158
 
1259
- All methods in `ssh2-sftp-client` return a Promise. This means methods are executed *asynchrnously*. When you call a method inside the `then()` block of a promise chain, it is critical that you return the Promise that call generates. Failing to do this will result in the `then()` block completing and your code starting execution of the next `then()`, `catch()` or `finally()` block before your promise has been fulfilled. For exmaple, the following will not do what you expect
1159
+ All methods in `ssh2-sftp-client` return a Promise. This means methods are executed *asynchrnously*. When you call a method inside the `then()` block of a promise chain, it is critical that you return the Promise that call generates. Failing to do this will result in the `then()` block completing and your code starting execution of the next `then()`, `catch()` or `finally()` block before your promise has been fulfilled. For example, the following will not do what you expect
1260
1160
 
1261
1161
  ```javascript
1262
1162
  sftp.connect(config)
@@ -1270,7 +1170,7 @@ sftp.connect(config)
1270
1170
  });
1271
1171
  ```
1272
1172
 
1273
- In the above code, the `sftp.end()` method will almost certainly be called before `sftp.gastGet()` has been fulfilled (unless the *foo.txt* file is really small!). In fact, the whole promise chain will complete and exit even before the `sftp.end()` call has been fulfilled. The correct code would be something like
1173
+ In the above code, the `sftp.end()` method will almost certainly be called before `sftp.fastGet()` has been fulfilled (unless the *foo.txt* file is really small!). In fact, the whole promise chain will complete and exit even before the `sftp.end()` call has been fulfilled. The correct code would be something like
1274
1174
 
1275
1175
  ```javascript
1276
1176
  sftp.connect(config)
@@ -1353,6 +1253,16 @@ The basic problem is that the try/catch block will have completed execution befo
1353
1253
 
1354
1254
  Error events are essentially asynchronous code. You don't know when such events will fire. Therefore, you cannot use a try/catch block to catch such event errors. Even creating an error handler which then throws an exception won't help as the key problem is that your try/catch block has already executed. There are a number of alternative ways to deal with this situation. However, the key symptom is that you see occasional uncaught error exceptions that cause your script to exit abnormally despite having try/catch blocks in your script. What you need to do is look at your code and find where errors are raised asynchronously and use an event handler or some other mechanism to manage any errors raised.
1355
1255
 
1256
+ ### Server Differences<a id="sec-9-1-4"></a>
1257
+
1258
+ Not all SFTP servers are the same. Like most standards, the SFTP protocol has some level of interpretation and allows different levels of compliance. This means there can be differences in behaviour between different servers and code which works with one server will not work the same with another. For example, the value returned by *realpath* for non-existent objects can differ significantly. Some servers will throw an error for a particular operation while others will just return null, some servers support concurrent operations (such as used by fastGet/fastPut) while others will not and of course, the text of error messages can vary significantly. In particular, we have noticed significant differences across different platforms. It is therefore advisable to do comprehensive testing when the SFTP server is moved to a new platform. This includes moving from to a cloud based service even if the underlying platform remains the same. I have noticed that some cloud platforms can generate unexpected events, possibly related to additional functionality or features associated with the cloud implementation. For example, it appears SFTP servers running under Azure will generate an error event when the connection is closed even when the client has requested the connection be terminated. The same SFTP server running natively on Windows does not appear to exhibit such behaviour.
1259
+
1260
+ ### Avoid Concurrent Operations<a id="sec-9-1-5"></a>
1261
+
1262
+ Technically, SFTP should be able to perform multiple operations concurrently. As node is single threaded, what we a really talking about is running multiple execution contexts as a pool where node will switch contexts when each context is blocked due to things like waiting on network data etc. However, I have found this to be extremely unreliable and of very little benefit from a performance perspective. My recommendation is to therefore avoid executing multiple requests over the same connection in parallel (for example, generating multiple `get()` promises and using something like `Promise.all()` to resolve them.
1263
+
1264
+ If you are going to try and perform concurrent operations, you need to test extensively and ensure you are using data which is large enough that context switching does occur (i.e. the request is not completed in a single run). Some SFTP servers will handle concurrent operations better than others.
1265
+
1356
1266
  ## Debugging Support<a id="sec-9-2"></a>
1357
1267
 
1358
1268
  You can add a `debug` property to the config object passed in to `connect()` to turn on debugging. This will generate quite a lot of output. The value of the property should be a function which accepts a single string argument. For example;
@@ -1393,7 +1303,7 @@ I am happy to try and help diagnose and fix any issues you encounter while using
1393
1303
  - Version of ssh2-sftp-client you are using
1394
1304
  - Platform your client is running on (Linux, macOS, Windows)
1395
1305
  - Platform and software for the remote SFTP server when possible
1396
- - Example of your code. By far, the most common issue is incorrect use of the module API. Example code can usually result in such issues being resolved very quickly.
1306
+ - Example of your code or a minimal script which reproduces the issue you are encountering. By far, the most common issue is incorrect use of the module API. Example code can usually result in such issues being resolved very quickly.
1397
1307
 
1398
1308
  Perhaps the best assistance is a minimal reproducible example of the issue. Once the issue can be readily reproduced, it can usually be fixed very quickly.
1399
1309
 
@@ -1421,3 +1331,4 @@ Thanks to the following for their contributions -
1421
1331
  - **jhorbulyk:** Contributed posixRename() functionality
1422
1332
  - **teenangst:** Contributed fix for error code 4 in stat() method
1423
1333
  - **kennylbj:** Contributed example of using a throttle stream to limit upload/download bandwidth.
1334
+ - **anton-erofeev:** Documentation fix