unnbound-sftp-sdk
v1.0.21
Published
An SFTP client with structured logging.
Downloads
5,745
Readme
Unnbound SFTP Client
A TypeScript SFTP client with structured logging and distributed tracing capabilities, built on top of ssh2-sftp-client and integrated with the Unnbound logging system.
Features
- Full SFTP Operations: Complete set of SFTP operations including file transfer, directory management, and file system operations
- Structured Logging: Built-in integration with Unnbound Logger for comprehensive operation tracking
- Distributed Tracing: Automatic span creation for all SFTP operations with detailed payload information
- Type Safety: Full TypeScript support with comprehensive type definitions
- Performance Monitoring: Built-in metrics collection for file sizes, operation counts, and timing
- Flexible Configuration: Support for various authentication methods and connection options
Installation
npm install unnbound-sftp-sdk
# or
pnpm add unnbound-sftp-sdk
# or
yarn add unnbound-sftp-sdkQuick Start
import { UnnboundSftpClient } from 'unnbound-sftp-sdk';
import { logger } from 'unnbound-logger-sdk';
const sftp = new UnnboundSftpClient({
host: 'your-sftp-server.com',
port: 22,
username: 'your-username',
privateKey: 'your-private-key', // or use password
});
// Connect to the SFTP server
await sftp.connect();
// Get current working directory
const currentPath = await sftp.cwd();
console.log('Current path:', currentPath);
// Create a directory
await sftp.mkdir('./uploads', true); // recursive
// Upload a file
const fileContent = Buffer.from('Hello, World!');
await sftp.put(fileContent, './uploads/hello.txt');
// Download a file
const downloadedContent = await sftp.get('./uploads/hello.txt');
console.log('Downloaded:', downloadedContent.toString());
// List files in a directory
const files = await sftp.list('./uploads');
console.log(
'Files:',
files.map((f) => f.name)
);
// Close the connection
await sftp.close();API Reference
Constructor
new UnnboundSftpClient(options: UnnboundSftpClientOptions)Options
| Property | Type | Required | Description |
| ------------------- | ---------------- | -------- | ----------------------------------------------------- |
| host | string | ✅ | SFTP server hostname |
| port | number | ❌ | SFTP server port (default: 22) |
| username | string | ❌ | Username for authentication |
| password | string | ❌ | Password for authentication |
| privateKey | string | ❌ | Private key for key-based authentication |
| passphrase | string | ❌ | Passphrase for encrypted private keys |
| localHostname | string | ❌ | Local hostname for hostbased authentication |
| localUsername | string | ❌ | Local username for hostbased authentication |
| keepaliveInterval | number | ❌ | SSH keepalive interval in milliseconds (0 to disable) |
| keepaliveCountMax | number | ❌ | Max unanswered keepalive packets before disconnection |
| readyTimeout | number | ❌ | SSH handshake timeout in milliseconds |
| localAddress | string | ❌ | Local network interface IP address |
| localPort | number | ❌ | Local port number |
| timeout | number | ❌ | Socket timeout in milliseconds |
| ident | string | ❌ | Server software identifier (default: 'unnbound') |
| logger | UnnboundLogger | ❌ | Custom logger instance (uses default if not provided) |
Connection Management
connect(): Promise<void>
Establishes a connection to the SFTP server.
await sftp.connect();close(): Promise<boolean>
Closes the SFTP connection.
const closed = await sftp.close();File Operations
get(path: string): Promise<Buffer>
Downloads a file from the remote server.
const content = await sftp.get('/remote/path/file.txt');put(input: Buffer, path: string): Promise<string>
Uploads a buffer to the remote server.
const data = Buffer.from('file content');
await sftp.put(data, '/remote/path/file.txt');append(input: Buffer | NodeJS.ReadableStream, path: string): Promise<string>
Appends data to an existing file.
const additionalData = Buffer.from('more content');
await sftp.append(additionalData, '/remote/path/file.txt');Directory Operations
list(path: string, filter?: ListFilterFunction): Promise<FileInfo[]>
Lists files and directories in the specified path.
const files = await sftp.list('/remote/directory');
const onlyFiles = await sftp.list('/remote/directory', (item) => item.type === '-');mkdir(path: string, recursive?: boolean): Promise<string>
Creates a directory.
await sftp.mkdir('/remote/new-directory');
await sftp.mkdir('/remote/nested/path', true); // recursivermdir(path: string, recursive?: boolean): Promise<string>
Removes a directory.
await sftp.rmdir('/remote/empty-directory');
await sftp.rmdir('/remote/directory-with-files', true); // recursiveuploadDir(sourcePath: string, destinationPath: string, options?: UploadDirOptions): Promise<string>
Uploads an entire directory.
await sftp.uploadDir('./local/directory', '/remote/destination');downloadDir(sourcePath: string, destinationPath: string, options?: DownloadDirOptions): Promise<string>
Downloads an entire directory.
await sftp.downloadDir('/remote/directory', './local/destination');File System Operations
exists(path: string): Promise<false | FileInfoType>
Checks if a file or directory exists.
const exists = await sftp.exists('/remote/path/file.txt');
// Returns: false, 'd' (directory), '-' (file), or 'l' (symlink)stat(path: string): Promise<FileStats>
Gets file or directory statistics.
const stats = await sftp.stat('/remote/path/file.txt');
console.log('Size:', stats.size);
console.log('Modified:', stats.modifyTime);realPath(path: string): Promise<string>
Resolves the real path of a file or directory.
const realPath = await sftp.realPath('/remote/symlink');cwd(): Promise<string>
Gets the current working directory.
const currentDir = await sftp.cwd();delete(path: string, noErrorOK?: boolean): Promise<string>
Deletes a file.
await sftp.delete('/remote/path/file.txt');rename(sourcePath: string, destinationPath: string): Promise<string>
Renames or moves a file or directory.
await sftp.rename('/remote/old-name.txt', '/remote/new-name.txt');chmod(path: string, mode: number | string): Promise<string>
Changes file or directory permissions.
await sftp.chmod('/remote/path/file.txt', 0o644);
await sftp.chmod('/remote/path/file.txt', '644');Type Definitions
FileInfo
interface FileInfo {
type: FileInfoType; // 'd' | '-' | 'l' (directory, file, symlink)
name: string;
size: number;
modifyTime: number;
accessTime: number;
rights: {
user: string;
group: string;
other: string;
};
owner: number;
group: number;
}FileStats
interface FileStats {
mode: number;
uid: number;
gid: number;
size: number;
accessTime: number;
modifyTime: number;
isDirectory: boolean;
isFile: boolean;
isBlockDevice: boolean;
isCharacterDevice: boolean;
isSymbolicLink: boolean;
isFIFO: boolean;
isSocket: boolean;
}Directory Options
interface DirOptions {
filter?: DirFilterFunction;
}
interface UploadDirOptions extends DirOptions {
useFastput?: boolean;
}
interface DownloadDirOptions extends DirOptions {
useFastget?: boolean;
}Logging and Tracing
The Unnbound SFTP Client automatically creates spans for all operations and logs detailed information including:
- Operation type and timing
- File paths and sizes
- Host information
- Error details (if any)
- File counts for directory operations
- Content previews for file operations
- Byte counts for transfers
Custom Logger
You can provide a custom logger instance:
import { UnnboundSftpClient } from 'unnbound-sftp-sdk';
import { logger } from 'unnbound-logger-sdk';
const sftp = new UnnboundSftpClient({
host: 'sftp.example.com',
username: 'user',
password: 'pass',
logger: logger, // Custom logger instance
});Example Log Output
{"level":"info","spanId":"556c53e6-3bb8-4118-b3b8-570e41c27654","type":"sftp","sftp":{"host":"sftp.domain.com","operation":"connect"},"message":"SFTP connect started."}
{"level":"info","spanId":"556c53e6-3bb8-4118-b3b8-570e41c27654","type":"sftp","sftp":{"host":"sftp.domain.com","operation":"connect"},"duration":2771,"message":"SFTP connect completed."}
{"level":"info","spanId":"556c53e6-3bb8-4118-b3b8-570e41c27654","type":"sftp","sftp":{"host":"sftp.domain.com","operation":"put","path":"/uploads/file.txt","bytes":1024,"content":"Hello World"},"message":"SFTP put started."}
{"level":"info","spanId":"556c53e6-3bb8-4118-b3b8-570e41c27654","type":"sftp","sftp":{"host":"sftp.domain.com","operation":"put","path":"/uploads/file.txt","bytes":1024,"content":"Hello World"},"duration":150,"message":"SFTP put completed."}Error Handling
All methods return promises that will reject with detailed error information:
try {
await sftp.get('/non-existent-file.txt');
} catch (error) {
console.error('SFTP operation failed:', error.message);
// Error details are automatically logged with the span
}Authentication Methods
Password Authentication
const sftp = new UnnboundSftpClient({
host: 'sftp.example.com',
username: 'myuser',
password: 'mypassword',
});Private Key Authentication
const sftp = new UnnboundSftpClient({
host: 'sftp.example.com',
username: 'myuser',
privateKey: `-----BEGIN OPENSSH PRIVATE KEY-----
...your private key content...
-----END OPENSSH PRIVATE KEY-----`,
});Private Key with Passphrase
const sftp = new UnnboundSftpClient({
host: 'sftp.example.com',
username: 'myuser',
privateKey: 'your-private-key',
passphrase: 'your-passphrase',
});Private Key from Environment Variables
The client automatically normalizes private keys from environment variables by converting \n escape sequences to actual newlines:
// Environment variable: PRIVATE_KEY="-----BEGIN OPENSSH PRIVATE KEY-----\nMIIEpAIBAAKCAQEA...\n-----END OPENSSH PRIVATE KEY-----"
const sftp = new UnnboundSftpClient({
host: 'sftp.example.com',
username: 'myuser',
privateKey: process.env.PRIVATE_KEY, // Automatically normalized
});Requirements
- Node.js >= 22.0.0
- TypeScript (for TypeScript projects)
Dependencies
ssh2-sftp-client: Core SFTP functionalityunnbound-logger-sdk: Structured logging and tracing
Support
For support, please open an issue on the GitHub repository.
