Promise-based SFTP client for Node.js that wraps the ssh2 module
—
Directory management functionality including listing, creation, deletion, and bulk transfer operations with filtering and concurrent processing support.
Lists the contents of a remote directory with optional filtering.
/**
* List contents of a remote directory
* @param remotePath - Path to remote directory
* @param filter - Optional filter function to select entries
* @param addListeners - Whether to add event listeners (default: true)
* @returns Promise resolving to array of file entry objects
*/
list(remotePath, filter, addListeners = true): Promise<Array>;Usage Examples:
// List all files and directories
const files = await sftp.list('/remote/directory');
console.log(files);
// List with filter function
const textFiles = await sftp.list('/remote/docs', (item) => {
return item.name.endsWith('.txt');
});
// List only directories
const directories = await sftp.list('/remote/path', (item) => {
return item.type === 'd';
});
// List files larger than 1MB
const largeFiles = await sftp.list('/remote/files', (item) => {
return item.type === '-' && item.size > 1024 * 1024;
});File Entry Object:
interface FileEntry {
type: string; // 'd' for directory, '-' for file, 'l' for link
name: string; // File/directory name
size: number; // Size in bytes
modifyTime: number; // Last modified time (milliseconds)
accessTime: number; // Last access time (milliseconds)
rights: {
user: string; // User permissions (rwx format)
group: string; // Group permissions (rwx format)
other: string; // Other permissions (rwx format)
};
owner: number; // Owner UID
group: number; // Group GID
longname: string; // Full listing format string
}Creates directories on the remote server with optional recursive creation.
/**
* Create directory on remote server
* @param remotePath - Path for new directory
* @param recursive - Create parent directories if needed (default: false)
* @returns Promise resolving to success message
*/
mkdir(remotePath, recursive = false): Promise<String>;Usage Examples:
// Create single directory
await sftp.mkdir('/remote/new-folder');
// Create directory tree recursively
await sftp.mkdir('/remote/path/to/deep/folder', true);
// Create directory with error handling
try {
await sftp.mkdir('/remote/existing-folder');
} catch (err) {
if (err.code !== 'EEXIST') {
throw err; // Re-throw if not "already exists" error
}
}Removes directories from the remote server with optional recursive deletion.
/**
* Remove directory from remote server
* @param remoteDir - Path to directory to remove
* @param recursive - Remove contents recursively (default: false)
* @returns Promise resolving to success message
*/
rmdir(remoteDir, recursive = false): Promise<String>;Usage Examples:
// Remove empty directory
await sftp.rmdir('/remote/empty-folder');
// Remove directory and all contents
await sftp.rmdir('/remote/folder-with-files', true);
// Safe removal with existence check
const exists = await sftp.exists('/remote/maybe-folder');
if (exists === 'd') {
await sftp.rmdir('/remote/maybe-folder', true);
}Recursively uploads a local directory to the remote server with filtering and performance options.
/**
* Upload local directory to remote server recursively
* @param srcDir - Local source directory path
* @param dstDir - Remote destination directory path
* @param options - Optional upload configuration
* @returns Promise resolving to success message
*/
uploadDir(srcDir, dstDir, options): Promise<String>;Upload Options:
interface UploadDirectoryOptions {
filter?: (filePath: string, isDirectory: boolean) => boolean;
useFastput?: boolean; // Use fastPut for file uploads (default: false)
}Usage Examples:
// Upload entire directory
await sftp.uploadDir('/local/project', '/remote/project');
// Upload with filtering
await sftp.uploadDir('/local/source', '/remote/source', {
filter: (filePath, isDirectory) => {
// Skip hidden files and node_modules
const name = path.basename(filePath);
return !name.startsWith('.') && name !== 'node_modules';
}
});
// Upload with fast transfers
await sftp.uploadDir('/local/data', '/remote/data', {
useFastput: true,
filter: (filePath, isDirectory) => {
// Only upload .txt and .json files
return isDirectory || filePath.match(/\.(txt|json)$/);
}
});Recursively downloads a remote directory to the local system with filtering and performance options.
/**
* Download remote directory to local system recursively
* @param srcDir - Remote source directory path
* @param dstDir - Local destination directory path
* @param options - Optional download configuration
* @returns Promise resolving to success message
*/
downloadDir(srcDir, dstDir, options = { filter: null, useFastget: false }): Promise<String>;Download Options:
interface DownloadDirectoryOptions {
filter?: (filePath: string, isDirectory: boolean) => boolean;
useFastget?: boolean; // Use fastGet for file downloads (default: false)
}Usage Examples:
// Download entire directory
await sftp.downloadDir('/remote/backup', '/local/backup');
// Download with filtering
await sftp.downloadDir('/remote/logs', '/local/logs', {
filter: (filePath, isDirectory) => {
// Only download .log files from today
if (isDirectory) return true;
const today = new Date().toISOString().split('T')[0];
return filePath.includes(today) && filePath.endsWith('.log');
}
});
// Download with fast transfers
await sftp.downloadDir('/remote/media', '/local/media', {
useFastget: true,
filter: (filePath, isDirectory) => {
// Download images and videos only
return isDirectory || filePath.match(/\.(jpg|png|mp4|avi)$/i);
}
});Directory operations use concurrent processing with configurable limits:
Monitor bulk operations with custom event handlers:
// Listen for upload progress
sftp.client.on('upload', (info) => {
console.log(`Uploading: ${info.source} -> ${info.destination}`);
});
// Listen for download progress
sftp.client.on('download', (info) => {
console.log(`Downloading: ${info.source} -> ${info.destination}`);
});Common filtering patterns for directory operations:
// File extension filter
const imageFilter = (filePath, isDirectory) => {
return isDirectory || /\.(jpg|jpeg|png|gif)$/i.test(filePath);
};
// Size-based filter
const smallFilesFilter = (filePath, isDirectory) => {
if (isDirectory) return true;
const stats = fs.statSync(filePath);
return stats.size < 10 * 1024 * 1024; // Less than 10MB
};
// Date-based filter
const recentFilter = (filePath, isDirectory) => {
if (isDirectory) return true;
const stats = fs.statSync(filePath);
const weekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);
return stats.mtime.getTime() > weekAgo;
};
// Complex filter combining multiple criteria
const complexFilter = (filePath, isDirectory) => {
if (isDirectory) {
// Skip hidden and system directories
const dirName = path.basename(filePath);
return !dirName.startsWith('.') && dirName !== 'node_modules';
}
// For files: only .js/.json files, not too large
const ext = path.extname(filePath).toLowerCase();
if (!['.js', '.json'].includes(ext)) return false;
const stats = fs.statSync(filePath);
return stats.size < 5 * 1024 * 1024; // Less than 5MB
};Directory operation errors provide detailed context:
ERR_BAD_PATH: Invalid directory path or permissionsENOENT: Directory does not existENOTDIR: Path exists but is not a directoryEEXIST: Directory already exists (mkdir)ENOTEMPTY: Directory not empty (rmdir without recursive)Install with Tessl CLI
npx tessl i tessl/npm-ssh2-sftp-client