ssh2-sftp-client 5.2.1 → 5.3.2

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- - [SSH2 SFTP Client](#sec-1)
1
+ - [Overview](#sec-1)
2
2
  - [Installation](#sec-2)
3
3
  - [Basic Usage](#sec-3)
4
4
  - [Version 5.x](#sec-4)
@@ -14,6 +14,10 @@
14
14
  - [Version 5.1.3](#sec-4-8)
15
15
  - [Version 5.2.0](#sec-4-9)
16
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)
20
+ - [Version 5.3.2](#sec-4-14)
17
21
  - [Documentation](#sec-5)
18
22
  - [Specifying Paths](#sec-5-1)
19
23
  - [Methods](#sec-5-2)
@@ -39,49 +43,19 @@
39
43
  - [downloadDir(srcDir, dstDir) ==> string](#sec-5-2-20)
40
44
  - [end() ==> boolean](#sec-5-2-21)
41
45
  - [Add and Remove Listeners](#sec-5-2-22)
42
- - [FAQ](#sec-6)
43
- - [Remote server drops connections with only an end event](#sec-6-1)
44
- - [How can you pass writable stream as dst for get method?](#sec-6-2)
45
- - [How can I upload files without having to specify a password?](#sec-6-3)
46
- - [How can I connect through a Socks Proxy](#sec-6-4)
47
- - [Timeout while waiting for handshake or handshake errors](#sec-6-5)
48
- - [Examples](#sec-7)
49
- - [Change Log](#sec-8)
50
- - [v5.2.1 (Prod Version)](#sec-8-1)
51
- - [v5.2.0](#sec-8-2)
52
- - [v5.1.3](#sec-8-3)
53
- - [v5.1.2](#sec-8-4)
54
- - [v5.1.1](#sec-8-5)
55
- - [v5.1.0](#sec-8-6)
56
- - [v5.0.2](#sec-8-7)
57
- - [v5.0.1](#sec-8-8)
58
- - [v5.0.0](#sec-8-9)
59
- - [v4.3.1](#sec-8-10)
60
- - [v4.3.0](#sec-8-11)
61
- - [v4.2.4](#sec-8-12)
62
- - [v4.2.3](#sec-8-13)
63
- - [v4.2.2](#sec-8-14)
64
- - [v4.2.1](#sec-8-15)
65
- - [v4.2.0](#sec-8-16)
66
- - [v4.1.0](#sec-8-17)
67
- - [v4.0.4](#sec-8-18)
68
- - [v4.0.3](#sec-8-19)
69
- - [v4.0.2](#sec-8-20)
70
- - [v4.0.0](#sec-8-21)
71
- - [Older Versions](#sec-8-22)
72
- - [v2.5.2](#sec-8-22-1)
73
- - [v2.5.1](#sec-8-22-2)
74
- - [v2.5.0](#sec-8-22-3)
75
- - [v2.4.3](#sec-8-22-4)
76
- - [v2.4.2](#sec-8-22-5)
77
- - [v2.4.1](#sec-8-22-6)
78
- - [v2.4.0](#sec-8-22-7)
79
- - [v2.3.0](#sec-8-22-8)
80
- - [v3.0.0 – deprecate this version](#sec-8-22-9)
81
- - [v2.1.1](#sec-8-22-10)
82
- - [v2.0.1](#sec-8-22-11)
83
- - [v1.1.0](#sec-8-22-12)
84
- - [v1.0.5:](#sec-8-22-13)
46
+ - [Platform Quirks & Warnings](#sec-6)
47
+ - [Server Capabilities](#sec-6-1)
48
+ - [Promises & Events](#sec-6-2)
49
+ - [Windows Based Servers](#sec-6-3)
50
+ - [Don't Re-use SftpClient Objects](#sec-6-4)
51
+ - [FAQ](#sec-7)
52
+ - [Remote server drops connections with only an end event](#sec-7-1)
53
+ - [How can I pass writable stream as dst for get method?](#sec-7-2)
54
+ - [How can I upload files without having to specify a password?](#sec-7-3)
55
+ - [How can I connect through a Socks Proxy](#sec-7-4)
56
+ - [Timeout while waiting for handshake or handshake errors](#sec-7-5)
57
+ - [How can I limit upload/download speed](#sec-7-6)
58
+ - [Examples](#sec-8)
85
59
  - [Troubleshooting](#sec-9)
86
60
  - [Common Errors](#sec-9-1)
87
61
  - [Not returning the promise in a `then()` block](#sec-9-1-1)
@@ -92,19 +66,28 @@
92
66
  - [Pull Requests](#sec-11)
93
67
  - [Contributors](#sec-12)
94
68
 
95
- # SSH2 SFTP Client<a id="sec-1"></a>
69
+
70
+ # Overview<a id="sec-1"></a>
96
71
 
97
72
  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.
98
73
 
99
74
  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.
100
75
 
101
- Current stable release is **v5.2.1**.
76
+ Current stable release is **v5.3.2**.
102
77
 
103
78
  Code has been tested against Node versions 12.18.2 and 13.14.0
104
79
 
105
80
  Node versions < 10.x are not supported.
106
81
 
107
- <span class="underline">WARNING</span> There is currently an issue with both the fastPut() and fastGet() methods when using Node versions greater than 14.0.0. This is a bug in the underlying ssh2-streams library and needs to be fixed upstream. The issue appears to be related to the concurrency operations of these two functions. A workaround is to set concurrency to 1 using the options object. Alternatively, use get() or put(), which do not use concurrency and which will provide the same performance as fastGet() or fastPut() when they are set to use a concurrency of 1. A bug report has been logged against the ssh2-streams library as [issue 156](https://github.com/mscdex/ssh2-streams/issues/156).
82
+ <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.
83
+
84
+ A bug report hass been logged against the ssh2-streams library as [issue 156](https://github.com/mscdex/ssh2-streams/issues/156).
85
+
86
+ <span class="underline">UPDATE</span>: The author of the upstream ssh2 and ssh2-streams module has decided on a re-write of the ssh2 module to address the above issues as well as some other design limitations and to allow the module to better fit in with newer versions of node. As part of that process, the functionality of ssh2-streams is being incorporated into the main ssh2 module and the ssh2-streams module is being deprecated. This will require a significant update to this module and may result in some API changes, depending on what changes in the re-write of ssh2.
87
+
88
+ To support these changes, a new branch called *version-6* has been created. This branch will use the newest version of ssh2 and for now is very much experimental and subject to change.
89
+
90
+ <span class="underline">UPDATE</span>: Apparently the change in core node which cause the issue with ssh2 has been rolled back in node version 15.3.0. Testing seems to indicate the above issue does not exist in that version of node.
108
91
 
109
92
  # Installation<a id="sec-2"></a>
110
93
 
@@ -222,6 +205,26 @@ In addition to the Promise error handlers, there is a default error handler whic
222
205
 
223
206
  - Move some dev dependencies from dependencies to devDependencies.
224
207
 
208
+ ## Version 5.2.2<a id="sec-4-11"></a>
209
+
210
+ - 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.
211
+
212
+ ## Version 5.3.0<a id="sec-4-12"></a>
213
+
214
+ - 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.
215
+ - 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.
216
+ - Add additional documentation on events/promises, platform quirks and platform differences.
217
+
218
+ ## Version 5.3.1<a id="sec-4-13"></a>
219
+
220
+ - Fix bug in handling of relative local paths
221
+ - 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.
222
+
223
+ ## Version 5.3.2<a id="sec-4-14"></a>
224
+
225
+ - Minor README typo fixes
226
+ - Fix error in local file path checks (#294)
227
+
225
228
  # Documentation<a id="sec-5"></a>
226
229
 
227
230
  The connection options are the same as those offered by the underlying SSH2 module. For full details, please see [SSH2 client methods](https://github.com/mscdex/ssh2#user-content-client-methods)
@@ -230,6 +233,8 @@ All the methods will return a Promise, except for `on()` and `removeListener()`,
230
233
 
231
234
  ## Specifying Paths<a id="sec-5-1"></a>
232
235
 
236
+ 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.
237
+
233
238
  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.
234
239
 
235
240
  It is important to recognise that the current remote directory may not always be what you may expect. A lot will depend on the remote platform of the SFTP server and how the SFTP server has been configured. When things don't seem to be working as expected, it is often a good idea to verify your assumptions regarding the remote directory and remote paths. One way to do this is to login using a command line program like `sftp` or `lftp`.
@@ -270,17 +275,17 @@ Constructor to create a new `ssh2-sftp-client` object. An optional `name` string
270
275
 
271
276
  ```javascript
272
277
  'use strict';
273
-
278
+
274
279
  const Client = require('ssh2-sftp-client');
275
-
280
+
276
281
  const config = {
277
282
  host: 'example.com',
278
283
  username: 'donald',
279
284
  password: 'my-secret'
280
285
  };
281
-
286
+
282
287
  const sftp = new Client('example-client');
283
-
288
+
284
289
  sftp.connect(config)
285
290
  .then(() => {
286
291
  return sftp.cwd();
@@ -301,12 +306,12 @@ Connect to an sftp server. Full documentation for connection options is availabl
301
306
  1. Connection Options
302
307
 
303
308
  This module is based on the excellent [SSH2](https://github.com/mscdex/ssh2#client) module. That module is a general SSH2 client and server library and provides much more functionality than just SFTP connectivity. Many of the connect options provided by that module are less relevant for SFTP connections. It is recommended you keep the config options to the minimum needed and stick to the options listed in the `commonOpts` below.
304
-
309
+
305
310
  The `retries`, `retry_factor` and `retry_minTimeout` options are not part of the SSH2 module. These are part of the configuration for the [retry](https://www.npmjs.com/package/retry) package and what is used to enable retrying of sftp connection attempts. See the documentation for that package for an explanation of these values.
306
-
311
+
307
312
  ```javascript
308
313
  // common options
309
-
314
+
310
315
  let commonOpts {
311
316
  host: 'localhost', // string Hostname or IP of server.
312
317
  port: 22, // Port number of the server.
@@ -316,7 +321,7 @@ Connect to an sftp server. Full documentation for connection options is availabl
316
321
  password: 'borsch', // string Password for password-based user authentication
317
322
  agent: process.env.SSH_AGENT, // string - Path to ssh-agent's UNIX socket
318
323
  privateKey: fs.readFileSync('/path/to/key'), // Buffer or string that contains
319
- passphrase; 'a pass phrase', // string - For an encrypted private key
324
+ passphrase: 'a pass phrase', // string - For an encrypted private key
320
325
  readyTimeout: 20000, // integer How long (in ms) to wait for the SSH handshake
321
326
  strictVendor: true // boolean - Performs a strict server vendor check
322
327
  debug: myDebug // function - Set this to a function that receives a single
@@ -325,9 +330,9 @@ Connect to an sftp server. Full documentation for connection options is availabl
325
330
  retry_factor: 2 // integer. Time factor used to calculate time between retries
326
331
  retry_minTimeout: 2000 // integer. Minimum timeout between attempts
327
332
  };
328
-
333
+
329
334
  // rarely used options
330
-
335
+
331
336
  let advancedOpts {
332
337
  localAddress,
333
338
  localPort,
@@ -368,16 +373,16 @@ Retrieves a directory listing. This method returns a Promise, which once realise
368
373
 
369
374
  ```javascript
370
375
  const Client = require('ssh2-sftp-client');
371
-
376
+
372
377
  const config = {
373
378
  host: 'example.com',
374
379
  port: 22,
375
380
  username: 'red-don',
376
381
  password: 'my-secret'
377
382
  };
378
-
383
+
379
384
  let sftp = new Client;
380
-
385
+
381
386
  sftp.connect(config)
382
387
  .then(() => {
383
388
  return sftp.list('/path/to/remote/dir');
@@ -396,7 +401,7 @@ Retrieves a directory listing. This method returns a Promise, which once realise
396
401
  2. Return Objects
397
402
 
398
403
  The objects in the array returned by `list()` have the following properties;
399
-
404
+
400
405
  ```javascript
401
406
  {
402
407
  type: // file type(-, d, l)
@@ -417,11 +422,11 @@ Retrieves a directory listing. This method returns a Promise, which once realise
417
422
  3. Pattern Filter
418
423
 
419
424
  The filter options can be a regular expression (most powerful option) or a simple *glob*-like string where \* will match any number of characters, e.g.
420
-
425
+
421
426
  foo* => foo, foobar, foobaz
422
427
  *bar => bar, foobar, tabbar
423
428
  *oo* => foo, foobar, look, book
424
-
429
+
425
430
  The *glob*-style matching is very simple. In most cases, you are best off using a real regular expression which will allow you to do more powerful matching and anchor matches to the beginning/end of the string etc.
426
431
 
427
432
  ### exists(path) ==> boolean<a id="sec-5-2-4"></a>
@@ -432,16 +437,16 @@ Tests to see if remote file or directory exists. Returns type of remote object i
432
437
 
433
438
  ```javascript
434
439
  const Client = require('ssh2-sftp-client');
435
-
440
+
436
441
  const config = {
437
442
  host: 'example.com',
438
443
  port: 22,
439
444
  username: 'red-don',
440
445
  password: 'my-secret'
441
446
  };
442
-
447
+
443
448
  let sftp = new Client;
444
-
449
+
445
450
  sftp.connect(config)
446
451
  .then(() => {
447
452
  return sftp.exists('/path/to/remote/dir');
@@ -466,7 +471,7 @@ Returns the attributes associated with the object pointed to by `path`.
466
471
  1. Attributes
467
472
 
468
473
  The `stat()` method returns an object with the following properties;
469
-
474
+
470
475
  ```javascript
471
476
  let stats = {
472
477
  mode: 33279, // integer representing type and permissions
@@ -489,7 +494,7 @@ Returns the attributes associated with the object pointed to by `path`.
489
494
 
490
495
  ```javascript
491
496
  let client = new Client();
492
-
497
+
493
498
  client.connect(config)
494
499
  .then(() => {
495
500
  return client.stat('/path/to/remote/file');
@@ -518,7 +523,7 @@ In general, if your going to pass in a string as the destination, you are better
518
523
  1. Options
519
524
 
520
525
  The options object can be used to pass options to the underlying readStream used to read the data from the remote server.
521
-
526
+
522
527
  ```javascript
523
528
  {
524
529
  flags: 'r',
@@ -528,17 +533,17 @@ In general, if your going to pass in a string as the destination, you are better
528
533
  autoClose: true
529
534
  }
530
535
  ```
531
-
536
+
532
537
  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.
533
538
 
534
539
  2. Example Use
535
540
 
536
541
  ```javascript
537
542
  let client = new Client();
538
-
543
+
539
544
  let remotePath = '/remote/server/path/file.txt';
540
545
  let dst = fs.createWriteStream('/local/file/path/copy.txt');
541
-
546
+
542
547
  client.connect(config)
543
548
  .then(() => {
544
549
  return client.get(remotePath, dst);
@@ -550,7 +555,7 @@ In general, if your going to pass in a string as the destination, you are better
550
555
  console.error(err.message);
551
556
  });
552
557
  ```
553
-
558
+
554
559
  - **Tip:** See examples file in the Git repository for more examples. You can pass any writeable stream in as the destination. For example, if you pass in `zlib.createGunzip()` writeable stream, you can both download and decompress a gzip file 'on the fly'.
555
560
 
556
561
  ### fastGet(remotePath, localPath, options) ===> string<a id="sec-5-2-7"></a>
@@ -571,7 +576,7 @@ Downloads a file at remotePath to localPath using parallel reads for faster thro
571
576
  // chunk is transferred
572
577
  }
573
578
  ```
574
-
579
+
575
580
  - **Warning:** Some servers do not respond correctly to requests to alter chunk size. This can result in lost or corrupted data.
576
581
 
577
582
  2. Sample Use
@@ -580,7 +585,7 @@ Downloads a file at remotePath to localPath using parallel reads for faster thro
580
585
  let client = new Client();
581
586
  let remotePath = '/server/path/file.txt';
582
587
  let localPath = '/local/path/file.txt';
583
-
588
+
584
589
  client.connect(config)
585
590
  .then(() => {
586
591
  client.fastGet(remotePath, localPath);
@@ -604,7 +609,7 @@ Upload data from local system to remote server. If the `src` argument is a strin
604
609
  1. Options
605
610
 
606
611
  The following options are supported;
607
-
612
+
608
613
  ```javascript
609
614
  {
610
615
  flags: 'w', // w - write and a - append
@@ -613,17 +618,17 @@ Upload data from local system to remote server. If the `src` argument is a strin
613
618
  autoClose: true // automatically close the write stream when finished
614
619
  }
615
620
  ```
616
-
621
+
617
622
  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.
618
623
 
619
624
  2. Example Use
620
625
 
621
626
  ```javascript
622
627
  let client = new Client();
623
-
628
+
624
629
  let data = fs.createReadStream('/path/to/local/file.txt');
625
630
  let remote = '/path/to/remote/file.txt';
626
-
631
+
627
632
  client.connect(config)
628
633
  .then(() => {
629
634
  return client.put(data, remote);
@@ -635,7 +640,7 @@ Upload data from local system to remote server. If the `src` argument is a strin
635
640
  console.error(err.message);
636
641
  });
637
642
  ```
638
-
643
+
639
644
  - **Tip:** If the src argument is a path string, consider just using `fastPut()`.
640
645
 
641
646
  ### fastPut(localPath, remotePath, options) ==> string<a id="sec-5-2-9"></a>
@@ -657,7 +662,7 @@ Uploads the data in file at `localPath` to a new file on remote server at `remot
657
662
  // a part of a file was transferred
658
663
  }
659
664
  ```
660
-
665
+
661
666
  - **Warning:** There have been reports that some SFTP servers will not honour requests for non-default chunk sizes. This can result in data loss or corruption.
662
667
 
663
668
  2. Example Use
@@ -666,7 +671,7 @@ Uploads the data in file at `localPath` to a new file on remote server at `remot
666
671
  let localFile = '/path/to/file.txt';
667
672
  let remoteFile = '/path/to/remote/file.txt';
668
673
  let client = new Client();
669
-
674
+
670
675
  client.connect(config)
671
676
  .then(() => {
672
677
  client.fastPut(localFile, remoteFile);
@@ -690,7 +695,7 @@ Append the `input` data to an existing remote file. There is no integrity checki
690
695
  1. Options
691
696
 
692
697
  The following options are supported;
693
-
698
+
694
699
  ```javascript
695
700
  {
696
701
  flags: 'a', // w - write and a - append
@@ -699,7 +704,7 @@ Append the `input` data to an existing remote file. There is no integrity checki
699
704
  autoClose: true // automatically close the write stream when finished
700
705
  }
701
706
  ```
702
-
707
+
703
708
  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. Generally, I would not attempt to append binary files.
704
709
 
705
710
  2. Example Use
@@ -707,7 +712,7 @@ Append the `input` data to an existing remote file. There is no integrity checki
707
712
  ```javascript
708
713
  let remotePath = '/path/to/remote/file.txt';
709
714
  let client = new Client();
710
-
715
+
711
716
  client.connect(config)
712
717
  .then(() => {
713
718
  return client.append(Buffer.from('Hello world'), remotePath);
@@ -732,7 +737,7 @@ Create a new directory. If the recursive flag is set to true, the method will cr
732
737
  ```javascript
733
738
  let remoteDir = '/path/to/new/dir';
734
739
  let client = new Client();
735
-
740
+
736
741
  client.connect(config)
737
742
  .then(() => {
738
743
  return client.mkdir(remoteDir, true);
@@ -752,12 +757,14 @@ Remove a directory. If removing a directory and recursive flag is set to `true`,
752
757
  - **path:** string. Path to remote directory
753
758
  - **recursive:** boolean. If true, remove all files and directories in target directory. Defaults to false
754
759
 
760
+ **Note**: There has been at least one report that some SFTP servers will allow non-empty directories to be removed even without the recursive flag being set to true. While this is not standard behaviour, it is recommended that users verify the behaviour of rmdir if there are plans to rely on the recursive flag to prevent removal of non-empty directories.
761
+
755
762
  1. Example Use
756
763
 
757
764
  ```javascript
758
765
  let remoteDir = '/path/to/remote/dir';
759
766
  let client = new Client();
760
-
767
+
761
768
  client.connect(config)
762
769
  .then(() => {
763
770
  return client.rmdir(remoteDir, true);
@@ -781,7 +788,7 @@ Delete a file on the remote server.
781
788
  ```javascript
782
789
  let remoteFile = '/path/to/remote/file.txt';
783
790
  let client = new Client();
784
-
791
+
785
792
  client.connect(config)
786
793
  .then(() => {
787
794
  return client.delete(remoteFile);
@@ -807,7 +814,7 @@ Rename a file or directory from `fromPath` to `toPath`. You must have the necess
807
814
  let from = '/remote/path/to/old.txt';
808
815
  let to = '/remote/path/to/new.txt';
809
816
  let client = new Client();
810
-
817
+
811
818
  client.connect(config)
812
819
  .then(() => {
813
820
  return client.rename(from, to);
@@ -855,9 +862,9 @@ Change the mode (read, write or execute permissions) of a remote file or directo
855
862
 
856
863
  ```javascript
857
864
  let path = '/path/to/remote/file.txt';
858
- let ndwMode = 0o644; // rw-r-r
865
+ let newMode = 0o644; // rw-r-r
859
866
  let client = new Client();
860
-
867
+
861
868
  client.connect(config)
862
869
  .then(() => {
863
870
  return client.chmod(path, newMode);
@@ -872,7 +879,9 @@ Change the mode (read, write or execute permissions) of a remote file or directo
872
879
 
873
880
  ### realPath(path) ===> string<a id="sec-5-2-17"></a>
874
881
 
875
- Converts a relative path to an absolute path on the remote server. This method is mainly used internally to resolve remote path names. Returns '' if the path is not valid.
882
+ Converts a relative path to an absolute path on the remote server. This method is mainly used internally to resolve remote path names.
883
+
884
+ **Warning**: Currently, there is a platform inconsistency with this method on win32 platforms. For servers running on non-win32 platforms, providing a path which does not exist on the remote server will result in an empty e.g. '', absolute path being returned. On servers running on win32 platforms, a normalised path will be returned even if the path does not exist on the remote server. It is therefore advised not to use this method to also verify a path exists. instead, use the `exist()` method.
876
885
 
877
886
  - **path:** A file path, either relative or absolute. Can handle '.' and '..', but does not expand '~'.
878
887
 
@@ -893,28 +902,28 @@ The upload process also emits 'upload' events. These events are fired for each s
893
902
 
894
903
  ```javascript
895
904
  'use strict';
896
-
905
+
897
906
  // Example of using the uploadDir() method to upload a directory
898
907
  // to a remote SFTP server
899
-
908
+
900
909
  const path = require('path');
901
910
  const SftpClient = require('../src/index');
902
-
911
+
903
912
  const dotenvPath = path.join(__dirname, '..', '.env');
904
913
  require('dotenv').config({path: dotenvPath});
905
-
914
+
906
915
  const config = {
907
916
  host: process.env.SFTP_SERVER,
908
917
  username: process.env.SFTP_USER,
909
918
  password: process.env.SFTP_PASSWORD,
910
919
  port: process.env.SFTP_PORT || 22
911
920
  };
912
-
921
+
913
922
  async function main() {
914
923
  const client = new SftpClient('upload-test');
915
924
  const src = path.join(__dirname, '..', 'test', 'testData', 'upload-src');
916
925
  const dst = '/home/tim/upload-test';
917
-
926
+
918
927
  try {
919
928
  await client.connect(config);
920
929
  client.on('upload', info => {
@@ -926,7 +935,7 @@ The upload process also emits 'upload' events. These events are fired for each s
926
935
  client.end();
927
936
  }
928
937
  }
929
-
938
+
930
939
  main()
931
940
  .then(msg => {
932
941
  console.log(msg);
@@ -934,7 +943,7 @@ The upload process also emits 'upload' events. These events are fired for each s
934
943
  .catch(err => {
935
944
  console.log(`main error: ${err.message}`);
936
945
  });
937
-
946
+
938
947
  ```
939
948
 
940
949
  ### downloadDir(srcDir, dstDir) ==> string<a id="sec-5-2-20"></a>
@@ -950,28 +959,28 @@ The method also emites `download` events to provide a way to monitor download pr
950
959
 
951
960
  ```javascript
952
961
  'use strict';
953
-
962
+
954
963
  // Example of using the downloadDir() method to upload a directory
955
964
  // to a remote SFTP server
956
-
965
+
957
966
  const path = require('path');
958
967
  const SftpClient = require('../src/index');
959
-
968
+
960
969
  const dotenvPath = path.join(__dirname, '..', '.env');
961
970
  require('dotenv').config({path: dotenvPath});
962
-
971
+
963
972
  const config = {
964
973
  host: process.env.SFTP_SERVER,
965
974
  username: process.env.SFTP_USER,
966
975
  password: process.env.SFTP_PASSWORD,
967
976
  port: process.env.SFTP_PORT || 22
968
977
  };
969
-
978
+
970
979
  async function main() {
971
980
  const client = new SftpClient('upload-test');
972
981
  const dst = '/tmp';
973
982
  const src = '/home/tim/upload-test';
974
-
983
+
975
984
  try {
976
985
  await client.connect(config);
977
986
  client.on('download', info => {
@@ -983,7 +992,7 @@ The method also emites `download` events to provide a way to monitor download pr
983
992
  client.end();
984
993
  }
985
994
  }
986
-
995
+
987
996
  main()
988
997
  .then(msg => {
989
998
  console.log(msg);
@@ -991,7 +1000,7 @@ The method also emites `download` events to provide a way to monitor download pr
991
1000
  .catch(err => {
992
1001
  console.log(`main error: ${err.message}`);
993
1002
  });
994
-
1003
+
995
1004
  ```
996
1005
 
997
1006
  ### end() ==> boolean<a id="sec-5-2-21"></a>
@@ -1002,7 +1011,7 @@ Ends the current client session, releasing the client socket and associated reso
1002
1011
 
1003
1012
  ```javascript
1004
1013
  let client = new Client();
1005
-
1014
+
1006
1015
  client.connect(config)
1007
1016
  .then(() => {
1008
1017
  // do some sftp stuff
@@ -1031,9 +1040,43 @@ Although normally not required, you can add and remove custom listeners on the s
1031
1040
 
1032
1041
  Removes the specified listener from the event specified in eventType. Note that the `end()` method automatically removes all listeners from the client object.
1033
1042
 
1034
- # FAQ<a id="sec-6"></a>
1043
+ # Platform Quirks & Warnings<a id="sec-6"></a>
1044
+
1045
+ ## Server Capabilities<a id="sec-6-1"></a>
1046
+
1047
+ 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.
1048
+
1049
+ 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.
1050
+
1051
+ 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.
1052
+
1053
+ ## Promises & Events<a id="sec-6-2"></a>
1054
+
1055
+ The reality of the current Node environment is that Promises and Events don't play nicely together. Part of the problem is that events are asynchronous in nature and can occur at any time. It is very difficult to ensure an event is captured inside a Promise and handled appropriately. More information can be found in the Node documentation for Events.
1056
+
1057
+ Node v12 has introduced some experimental features to make working with Events and Promises a little easier. At this stage, we are not using these features because they are experimental and because it would mean you cannot use this module with Node v10. Use of these features will likely be examined more closely once they become stable and non-experimental.
1058
+
1059
+ So, what does this mean for this module? The `ssh2-sftp-client` module works hard to ensure things work as expected. In most cases, events are handled appropriately. However, there are some edge cases where events may not be handled and you may see an uncaught error exception. The most common place to see this is when you keep an SFTP connection open, but don't use it for some time. When the connection is open, but no methods are active (running), there are no error handlers defined. Should an error event be emitted (for exmaple, because the network connection has been lost), there is no handler and you will get an uncaught error exception.
1035
1060
 
1036
- ## Remote server drops connections with only an end event<a id="sec-6-1"></a>
1061
+ One way to handle this is to add your own error handler using the on() method. Note however, you need to be careful how many times your error handler is added. If you begin to see a warning about a possible memory leak, it is an indication your error handler is being added multiple times (Node will generate this warning if it finds more than 11 listeners attached to an event emitter).
1062
+
1063
+ The other issue that can occur is that in some rare cases, the error message you get will be potentially misleading. For example, SFTP servers running on Windows appear to emit an *ECONNRESET* error in addition to the main error (for example, for failed authentication). This can result in an error which looks like a connection was reset by the remote host when in fact the real error was due to bad authentication (bad password or bad username). This situation can be made even worse by some platforms which deliberately hide the real error for security reasons e.g. does not report an error indicating a bad username because that information can be used to try and identify legitimate usernames. While this module attempts to provide meaningful error messages which can assist developers track down problems, it is a good idea to consider these errors with a grain of salt and verify the error when possible.
1064
+
1065
+ ## Windows Based Servers<a id="sec-6-3"></a>
1066
+
1067
+ It appears that when the sftp server is running on Windows, a *ECONNRESET* error signal is raised when the end() method is called. Unfortunately, this signal is raised after a considerable delay. This means we cannot remove the error handler used in the end() promise as otherwise you will get an uncaught exception error. Leaving the handler in place, even though we will ignore this error, solves that issue, but unfortunately introduces a new problem. Because we are not removing the listener, if you re-use the client object for subsequent connections, an additional error handler will be added. If this happens more than 11 times, you will eventually see the Node warning about a possible memory leak. This is because node monitors the number of error handlers and if it sees more than 11 added to an object, it assumes there is a problem and generates the warning.
1068
+
1069
+ The best way to avoid this issue is to not re-use client objects. Always generate a new sftp client object for each new connection.
1070
+
1071
+ ## Don't Re-use SftpClient Objects<a id="sec-6-4"></a>
1072
+
1073
+ Due to an issue with *ECONNRESET* error signals when connecting to Windows based SFTP servers, it is not possible to remove the error handler in the end() method. This means that if you re-use the SftpClient object for multiple connections e.g. calling connect(), then end(), then connect() etc, you run the risk of multiple error handlers being added to the SftpClient object. After 11 handlers have been added, Node will generate a possible memory leak warning.
1074
+
1075
+ To avoid this problem, don't re-use SftpClient objects. Generate a new SftpClient object for each connection. You can perform multiple actions with a single connection e.g. upload multiple files, download multiple files etc, but after you have called end(), you should not try to re-use the object with a further connect() call. Create a new object instead.
1076
+
1077
+ # FAQ<a id="sec-7"></a>
1078
+
1079
+ ## Remote server drops connections with only an end event<a id="sec-7-1"></a>
1037
1080
 
1038
1081
  Many SFTP servers have rate limiting protection which will drop connections once a limit has been reached. In particular, openSSH has the setting `MaxStartups`, which can be a tuple of the form `max:drop:full` where `max` is the maximum allowed unauthenticated connections, `drop` is a percentage value which specifies percentage of connections to be dropped once `max` connections has been reached and `full` is the number of connections at which point all subsequent connections will be dropped. e.g. `10:30:60` means allow up to 10 unauthenticated connections after which drop 30% of connection attempts until reaching 60 unauthenticated connections, at which time, drop all attempts.
1039
1082
 
@@ -1041,7 +1084,7 @@ Clients first make an unauthenticated connection to the SFTP server to begin neg
1041
1084
 
1042
1085
  One way to avoid this type of issue is to add a delay between connection attempts. It does not need to be a very long delay - just sufficient to permit the previous connection to be authenticated. In fact, the default setting for openSSH is `10:30:60`, so you really just need to have enough delay to ensure that the 1st connection has completed authentication before the 11th connection is attempted.
1043
1086
 
1044
- ## How can you pass writable stream as dst for get method?<a id="sec-6-2"></a>
1087
+ ## How can I pass writable stream as dst for get method?<a id="sec-7-2"></a>
1045
1088
 
1046
1089
  If the dst argument passed to the get method is a writeable stream, the remote file will be piped into that writeable. If the writeable you pass in is a writeable stream created with `fs.createWriteStream()`, the data will be written to the file specified in the constructor call to `createWriteStream()`.
1047
1090
 
@@ -1097,7 +1140,7 @@ sftp
1097
1140
  });
1098
1141
  ```
1099
1142
 
1100
- ## How can I upload files without having to specify a password?<a id="sec-6-3"></a>
1143
+ ## How can I upload files without having to specify a password?<a id="sec-7-3"></a>
1101
1144
 
1102
1145
  There are a couple of ways to do this. Essentially, you want to setup SSH keys and use these for authentication to the remote server.
1103
1146
 
@@ -1129,7 +1172,7 @@ sftp.connect({
1129
1172
  }
1130
1173
  ```
1131
1174
 
1132
- ## How can I connect through a Socks Proxy<a id="sec-6-4"></a>
1175
+ ## How can I connect through a Socks Proxy<a id="sec-7-4"></a>
1133
1176
 
1134
1177
  This solution was provided by @jmorino.
1135
1178
 
@@ -1162,218 +1205,50 @@ client.connect({
1162
1205
  // client is connected
1163
1206
  ```
1164
1207
 
1165
- ## Timeout while waiting for handshake or handshake errors<a id="sec-6-5"></a>
1208
+ ## Timeout while waiting for handshake or handshake errors<a id="sec-7-5"></a>
1166
1209
 
1167
1210
  Some users have encountered the error 'Timeout while waiting for handshake' or 'Handshake failed, no matching client->server ciphers. This is often due to the client not having the correct configuration for the transport layer algorithms used by ssh2. One of the connect options provided by the ssh2 module is `algorithm`, which is an object that allows you to explicitly set the key exchange, ciphers, hmac and compression algorithms as well as server host key used to establish the initial secure connection. See the SSH2 documentation for details. Getting these parameters correct usually resolves the issue.
1168
1211
 
1169
- # Examples<a id="sec-7"></a>
1170
-
1171
- I have started collecting example scripts in the example directory of the repository. These are mainly scripts I have put together in order to investigate issues or provide samples for users. They are not robust, lack adequate error handling and may contain errors. However, I think they are still useful for helping developers see how the module and API can be used.
1172
-
1173
- # Change Log<a id="sec-8"></a>
1174
-
1175
- ## v5.2.1 (Prod Version)<a id="sec-8-1"></a>
1176
-
1177
- - Move some dependencies into dev-Dependencies
1178
-
1179
- ## v5.2.0<a id="sec-8-2"></a>
1180
-
1181
- - Add new method posixRename() which uses the openSSH POSIX rename extension.
1182
-
1183
- ## v5.1.3<a id="sec-8-3"></a>
1184
-
1185
- - Fix bug when writing to root directory and failure due to not being able to determine parent
1186
- - Refactor some tests to eliminate need to have artificial delays between tests
1187
- - Bumped some dependency versions to latest version
1188
-
1189
- ## v5.1.2<a id="sec-8-4"></a>
1190
-
1191
- - Added back global close handler
1192
- - Added dumpListeners() method
1193
-
1194
- ## v5.1.1<a id="sec-8-5"></a>
1195
-
1196
- - Added separate close handlers to each method.
1197
- - Added missing return statement in connect method
1198
- - Added additional troubleshooting documentation for common errors.
1199
-
1200
- ## v5.1.0<a id="sec-8-6"></a>
1201
-
1202
- - Fix bug in checkRemotePath() relating to handling of badly specified paths (issue #213)
1203
- - Added additional debugging support
1204
- - Add missing test for valid connection in end() method.
1205
- - Bump ssh2 version to v0.8.8
1206
-
1207
- ## v5.0.2<a id="sec-8-7"></a>
1208
-
1209
- - Fix bugs related to win32 platform and local tests for valid directories
1210
- - Fix problem with parsing of file paths
1211
-
1212
- ## v5.0.1<a id="sec-8-8"></a>
1213
-
1214
- - Turn down error checking to be less stringent and handle situations where user does not have read permission on parent directory.
1215
-
1216
- ## v5.0.0<a id="sec-8-9"></a>
1217
-
1218
- - Added two new methods `uploadDir()` and `downloadDir()`
1219
- - Removed deprecated `auxList()` method
1220
- - Improved error message consistency
1221
- - Added additional error checking to enable more accurate and useful error messages.
1222
- - Added default error handler to deal with event errors which fire outside of active SftpClient methods (i.e. connection unexpectedly reset by remote host).
1223
- - Modified event handlers to ensure that only event handlers added by the module are removed by the module (users now responsible for removing any custom event handlers they add).
1224
- - Module error handlers added using `prependListener` to ensure they are called before any additional custom handlers added by client code.
1225
- - Any error events fired during an `end()` call are now ignored.
1226
-
1227
- ## v4.3.1<a id="sec-8-10"></a>
1228
-
1229
- - Updated end() method to resolve once close event fires
1230
- - Added errorListener to error event in each promise to catch error events and reject the promise. This should resolve the issue of some error events causing uncaughtException erros and causing the process to exit.
1231
-
1232
- ## v4.3.0<a id="sec-8-11"></a>
1233
-
1234
- - Ensure errors include an err.code property and pass through the error code from the originating error
1235
- - Change tests for error type to use `error.code` instead of matching on `error.message`.
1236
-
1237
- ## v4.2.4<a id="sec-8-12"></a>
1238
-
1239
- - Bumped ssh2 to v0.8.6
1240
- - Added exists() usage example to examples directory
1241
- - Clarify documentation on get() method
1242
-
1243
- ## v4.2.3<a id="sec-8-13"></a>
1244
-
1245
- - Fix bug in `exist()` where tests on root directory returned false
1246
- - Minor documentation fixes
1247
- - Clean up mkdir example
1248
-
1249
- ## v4.2.2<a id="sec-8-14"></a>
1250
-
1251
- - Minor documentation fixes
1252
- - Added additional examples in the `example` directory
1253
-
1254
- ## v4.2.1<a id="sec-8-15"></a>
1255
-
1256
- - Remove default close listener. changes in ssh2 API removed the utility of a default close listener
1257
- - Fix path handling. Under mixed environments (where client platform and server platform were different i.e. one windows the other unix), path handling was broken due tot he use of path.join().
1258
- - Ensure error messages include path details. Instead of errors such as "No such file" now report "No such file /path/to/missing/file" to help with debugging
1212
+ ## How can I limit upload/download speed<a id="sec-7-6"></a>
1259
1213
 
1260
- ## v4.2.0<a id="sec-8-16"></a>
1214
+ If you want to limit the amount of bandwidth used during upload/download of data, you can use a stream to limit throughput. The following example was provided by *kennylbj*. Note that there is a caveat that we must set the `autoClose` flag to false to avoid calling an extra `_read()` on a closed stream that may cause \_get Permission Denied error in ssh2-streams.
1261
1215
 
1262
- - Work-around for SSH2 `end` event bug
1263
- - Added ability to set client name in constructor method
1264
- - Added additional error checking to prevent `connect()` being called on already connected client
1265
- - Added additional examples in `example` directory
1266
-
1267
- ## v4.1.0<a id="sec-8-17"></a>
1268
-
1269
- - move `end()` call to resolve into close hook
1270
- - Prevent `put()` and `get()` from creating empty files in destination when unable to read source
1271
- - Expand tests for operations when lacking required permissions
1272
- - Add additional data checks for `append()`
1273
- - Verify file exists
1274
- - Verify file is writeable
1275
- - Verify file is a regular file
1276
- - Fix handling of relative paths
1277
- - Add `realPath()` method
1278
- - Add `cwd()` method
1279
-
1280
- ## v4.0.4<a id="sec-8-18"></a>
1281
-
1282
- - Minor documentation fix
1283
- - Fix return value from `get()`
1284
-
1285
- ## v4.0.3<a id="sec-8-19"></a>
1286
-
1287
- - Fix bug in mkdir() relating to handling of relative paths
1288
- - Modify exists() to always return 'd' if path is '.'
1289
-
1290
- ## v4.0.2<a id="sec-8-20"></a>
1291
-
1292
- - Fix some minor packaging issues
1293
-
1294
- ## v4.0.0<a id="sec-8-21"></a>
1295
-
1296
- - Remove support for node < 8.x
1297
- - Fix connection retry feature
1298
- - sftp connection object set to null when 'end' signal is raised
1299
- - Removed 'connectMethod' argument from connect method.
1300
- - Refined adding/removing of listeners in connect() and end() methods to enable errors to be adequately caught and reported.
1301
- - Deprecate auxList() and add pattern/regexp filter option to list()
1302
- - Refactored handling of event signals to provide better feedback to clients
1303
- - Removed pointless 'permissions' property from objects returned by `stat()` (same as mode property). Added additional properties describing the type of object.
1304
- - Added the `removeListener()` method to compliment the existing `on()` method.
1305
-
1306
- ## Older Versions<a id="sec-8-22"></a>
1307
-
1308
- ### v2.5.2<a id="sec-8-22-1"></a>
1309
-
1310
- - Repository transferred to theophilusx
1311
- - Fix error in package.json pointing to wrong repository
1312
-
1313
- ### v2.5.1<a id="sec-8-22-2"></a>
1314
-
1315
- - Apply 4 pull requests to address minor issues prior to transfer
1316
-
1317
- ### v2.5.0<a id="sec-8-22-3"></a>
1318
-
1319
- - ???
1320
-
1321
- ### v2.4.3<a id="sec-8-22-4"></a>
1322
-
1323
- - merge #108, #110
1324
- - fix connect promise if connection ends
1325
-
1326
- ### v2.4.2<a id="sec-8-22-5"></a>
1327
-
1328
- - merge #105
1329
- - fix windows path
1330
-
1331
- ### v2.4.1<a id="sec-8-22-6"></a>
1332
-
1333
- - merge pr #99, #100
1334
- - bug fix
1335
-
1336
- ### v2.4.0<a id="sec-8-22-7"></a>
1337
-
1338
- - Requires node.js v7.5.0 or above.
1339
- - merge pr #97, thanks for @theophilusx
1340
- - Remove emitter.maxListener warnings
1341
- - Upgraded ssh2 dependency from 0.5.5 to 0.6.1
1342
- - Enhanced error messages to provide more context and to be more consistent
1343
- - re-factored test
1344
- - Added new 'exists' method and re-factored mkdir/rmdir
1345
-
1346
- ### v2.3.0<a id="sec-8-22-8"></a>
1347
-
1348
- - add: `stat` method
1349
- - add `fastGet` and `fastPut` method.
1350
- - fix: `mkdir` file exists decision logic
1351
-
1352
- ### v3.0.0 &#x2013; deprecate this version<a id="sec-8-22-9"></a>
1216
+ ```javascript
1353
1217
 
1354
- - change: `sftp.get` will return chunk not stream anymore
1355
- - fix: get readable not emitting data events in node 10.0.0
1356
1218
 
1357
- ### v2.1.1<a id="sec-8-22-10"></a>
1219
+ const Throttle = require('throttle');
1220
+ const progress = require('progress-stream');
1358
1221
 
1359
- - add: event listener. [doc](https://github.com/jyu213/ssh2-sftp-client#Event)
1360
- - add: `get` or `put` method add extra options [pr#52](https://github.com/jyu213/ssh2-sftp-client/pull/52)
1222
+ // limit download speed
1223
+ const throttleStream = new Throttle(config.throttle);
1361
1224
 
1362
- ### v2.0.1<a id="sec-8-22-11"></a>
1225
+ // download progress stream
1226
+ const progressStream = progress({
1227
+ length: fileSize,
1228
+ time: 500,
1229
+ });
1230
+ progressStream.on('progress', (progress) => {
1231
+ console.log(progress.percentage.toFixed(2));
1232
+ });
1363
1233
 
1364
- - add: `chmod` method [pr#33](https://github.com/jyu213/ssh2-sftp-client/pull/33)
1365
- - update: upgrade ssh2 to V0.5.0 [pr#30](https://github.com/jyu213/ssh2-sftp-client/pull/30)
1366
- - fix: get method stream error reject unwork [#22](https://github.com/jyu213/ssh2-sftp-client/issues/22)
1367
- - fix: return Error object on promise rejection [pr#20](https://github.com/jyu213/ssh2-sftp-client/pull/20)
1234
+ const outStream = createWriteStream(localPath);
1368
1235
 
1369
- ### v1.1.0<a id="sec-8-22-12"></a>
1236
+ // pipe streams together
1237
+ throttleStream.pipe(progressStream).pipe(outStream);
1370
1238
 
1371
- - fix: add encoding control support for binary stream
1239
+ try {
1240
+ // set autoClose to false
1241
+ await client.get(remotePath, throttleStream, { autoClose: false });
1242
+ } catch (e) {
1243
+ console.log('sftp error', e);
1244
+ } finally {
1245
+ await client.end();
1246
+ }
1247
+ ```
1372
1248
 
1373
- ### v1.0.5:<a id="sec-8-22-13"></a>
1249
+ # Examples<a id="sec-8"></a>
1374
1250
 
1375
- - fix: multi image upload
1376
- - change: remove `this.client.sftp` to `connect` function
1251
+ I have started collecting example scripts in the example directory of the repository. These are mainly scripts I have put together in order to investigate issues or provide samples for users. They are not robust, lack adequate error handling and may contain errors. However, I think they are still useful for helping developers see how the module and API can be used.
1377
1252
 
1378
1253
  # Troubleshooting<a id="sec-9"></a>
1379
1254
 
@@ -1407,7 +1282,7 @@ sftp.connect(config)
1407
1282
  });
1408
1283
  ```
1409
1284
 
1410
- 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
1285
+ 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
1411
1286
 
1412
1287
  ```javascript
1413
1288
  sftp.connect(config)
@@ -1508,6 +1383,18 @@ node script.js 2> debug.log
1508
1383
 
1509
1384
  ```
1510
1385
 
1386
+ If you just want to see debug messages from `ssh2-sftp-client` and exclude debug messages from the underlying `ssh2` and `ssh2-streams` modules, you can filter based on messages which start with 'CLIENT' e.g.
1387
+
1388
+ ```javascript
1389
+ {
1390
+ debug: (msg) => {
1391
+ if (msg.startsWith('CLIENT')) {
1392
+ console.error(msg);
1393
+ }
1394
+ }
1395
+ }
1396
+ ```
1397
+
1511
1398
  # Logging Issues<a id="sec-10"></a>
1512
1399
 
1513
1400
  Please log an issue for all bugs, questions, feature and enhancement requests. Please ensure you include the module version, node version and platform.
@@ -1544,3 +1431,6 @@ Thanks to the following for their contributions -
1544
1431
  - **waldyrious:** Documentation fixes
1545
1432
  - **james-pellow:** Cleanup and fix for connect method logic
1546
1433
  - **jhorbulyk:** Contributed posixRename() functionality
1434
+ - **teenangst:** Contributed fix for error code 4 in stat() method
1435
+ - **kennylbj:** Contributed example of using a throttle stream to limit upload/download bandwidth.
1436
+ - **anton-erofeev:** Documentation fix