fs-tunnel
Version:
Modern SSH/SFTP file system client for Node.js - provides seamless remote file operations with a clean Promise-based API. Supports secure file transfers, directory management, and streaming for large files.
165 lines (164 loc) • 6.24 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SSHFileSystem = void 0;
const ssh2_1 = require("ssh2");
class SSHFileSystem {
constructor(credentials) {
this.credentials = credentials;
this.connection = new ssh2_1.Client();
this.sftp = null;
this.connected = false;
}
connect() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.credentials.username || !this.credentials.password) {
throw new Error('Username and password required for SSH connection');
}
return this.connectInternal();
});
}
connectWithCredentials(username, password) {
return __awaiter(this, void 0, void 0, function* () {
this.credentials.username = username;
this.credentials.password = password;
return this.connectInternal();
});
}
connectInternal() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
this.connection.on('ready', () => {
this.connection.sftp((err, sftp) => {
if (err)
return reject(err);
this.sftp = sftp;
this.connected = true;
console.log('SSH/SFTP connection established');
resolve();
});
}).on('error', reject).connect(this.credentials);
});
});
}
ensureConnection() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.connected) {
if (!this.credentials.username || !this.credentials.password) {
throw new Error('Not connected and no credentials configured');
}
yield this.connectInternal();
}
});
}
readdir(remotePath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
this.sftp.readdir(remotePath, (err, list) => {
if (err)
return reject(err);
resolve(list.map(item => ({
name: item.filename,
isDirectory: item.attrs.isDirectory(),
size: item.attrs.size,
mtime: new Date(item.attrs.mtime * 1000),
mode: item.attrs.mode
})));
});
});
});
}
stat(remotePath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
const normalizedPath = remotePath === '' ? '/' : remotePath;
this.sftp.stat(normalizedPath, (err, stats) => {
if (err)
return reject(err);
resolve({
isDirectory: stats.isDirectory(),
size: stats.size,
mtime: new Date(stats.mtime * 1000),
mode: stats.mode
});
});
});
});
}
mkdir(remotePath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
this.sftp.mkdir(remotePath, (err) => {
if (err)
return reject(err);
resolve();
});
});
});
}
rmdir(remotePath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
this.sftp.rmdir(remotePath, (err) => {
if (err)
return reject(err);
resolve();
});
});
});
}
unlink(remotePath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
this.sftp.unlink(remotePath, (err) => {
if (err)
return reject(err);
resolve();
});
});
});
}
createReadStream(remotePath) {
if (!this.sftp)
throw new Error('Not connected to SFTP');
return this.sftp.createReadStream(remotePath);
}
createWriteStream(remotePath, options) {
if (!this.sftp)
throw new Error('Not connected to SFTP');
return this.sftp.createWriteStream(remotePath, options);
}
rename(oldPath, newPath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.ensureConnection();
return new Promise((resolve, reject) => {
this.sftp.rename(oldPath, newPath, (err) => {
if (err)
return reject(err);
resolve();
});
});
});
}
disconnect() {
if (this.connected) {
this.connection.end();
this.connected = false;
this.sftp = null;
}
}
}
exports.SSHFileSystem = SSHFileSystem;