npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@simplysm/storage

v13.0.67

Published

심플리즘 패키지 - 스토리지 모듈 (node)

Downloads

7,996

Readme

@simplysm/storage

A storage client package that supports FTP, FTPS, and SFTP protocols. Through the unified Storage interface, you can perform file upload, download, directory manipulation and other operations with the same API regardless of protocol.

Using StorageFactory, you can automatically manage connection/disconnection, and you can also directly instantiate FtpStorageClient or SftpStorageClient if needed.

Installation

npm install @simplysm/storage
# or
pnpm add @simplysm/storage

Main Modules

Export List

| Module | Type | Description | |------|------|------| | StorageFactory | Class | Creates clients based on storage type and automatically manages connection/disconnection | | FtpStorageClient | Class | FTP/FTPS protocol client (based on basic-ftp) | | SftpStorageClient | Class | SFTP protocol client (based on ssh2-sftp-client) | | Storage | Interface | Common interface implemented by all storage clients | | StorageConnConfig | Interface | Connection configuration | | FileInfo | Interface | Directory entry information | | StorageType | Type | Storage protocol types ("ftp" \| "ftps" \| "sftp") |

Type Definitions

StorageConnConfig

Configuration required for server connection.

interface StorageConnConfig {
  host: string;   // Server host
  port?: number;  // Port (FTP default: 21, SFTP default: 22)
  user?: string;  // Username
  pass?: string;  // Password (required for FTP/FTPS; optional for SFTP)
}

SFTP SSH Key Authentication:

  • If pass is omitted for SFTP connections, the client automatically attempts authentication using:
    1. SSH key file at ~/.ssh/id_ed25519
    2. SSH agent (if SSH_AUTH_SOCK environment variable is set)
    • Both methods are tried in order; if the key file authentication fails (e.g., encrypted keys), the client falls back to agent-only authentication.

FileInfo

File/directory information returned by readdir().

interface FileInfo {
  name: string;    // File or directory name
  isFile: boolean; // true if file, false if directory
}

StorageType

Supported storage protocol types.

type StorageType = "ftp" | "ftps" | "sftp";

| Value | Protocol | Default Port | Description | |-----|---------|----------|------| | "ftp" | FTP | 21 | Unencrypted FTP | | "ftps" | FTPS | 21 | TLS-encrypted FTP | | "sftp" | SFTP | 22 | SSH-based file transfer |

Storage Interface

Common interface implemented by all storage clients (FtpStorageClient, SftpStorageClient). Bytes is a Uint8Array type alias defined in @simplysm/core-common.

| Method | Signature | Description | |--------|---------|------| | connect | (config: StorageConnConfig) => Promise<void> | Connect to server | | close | () => Promise<void> | Close connection | | put | (localPathOrBuffer: string \| Bytes, storageFilePath: string) => Promise<void> | Upload file (local path or byte data) | | readFile | (filePath: string) => Promise<Bytes> | Download file (returns Bytes) | | readdir | (dirPath: string) => Promise<FileInfo[]> | List directory contents | | remove | (filePath: string) => Promise<void> | Delete file | | exists | (filePath: string) => Promise<boolean> | Check if file/directory exists | | mkdir | (dirPath: string) => Promise<void> | Create directory (recursive) | | rename | (fromPath: string, toPath: string) => Promise<void> | Rename file/directory | | uploadDir | (fromPath: string, toPath: string) => Promise<void> | Upload entire local directory to remote |

Usage

StorageFactory (Recommended)

StorageFactory.connect() automatically manages connection and disconnection with a callback pattern. The connection is always closed even if an exception occurs in the callback, so it's recommended over using clients directly.

import { StorageFactory } from "@simplysm/storage";

// FTP connection
const result = await StorageFactory.connect("ftp", {
  host: "ftp.example.com",
  port: 21,
  user: "username",
  pass: "password",
}, async (client) => {
  // Upload local file to remote server
  await client.put("/local/path/file.txt", "/remote/path/file.txt");

  // Upload byte data directly
  const data = new TextEncoder().encode("hello world");
  await client.put(data, "/remote/path/hello.txt");

  // Download remote file
  const content = await client.readFile("/remote/path/file.txt");

  // The callback's return value becomes the return value of StorageFactory.connect()
  return content;
});
// FTPS connection (TLS encryption)
await StorageFactory.connect("ftps", {
  host: "ftps.example.com",
  user: "username",
  pass: "password",
}, async (client) => {
  await client.put("/local/file.txt", "/remote/file.txt");
});
// SFTP connection with password
await StorageFactory.connect("sftp", {
  host: "sftp.example.com",
  port: 22,
  user: "username",
  pass: "password",
}, async (client) => {
  // List directory contents
  const files = await client.readdir("/remote/path");
  for (const file of files) {
    console.log(`${file.name} - ${file.isFile ? "File" : "Directory"}`);
  }

  // Upload entire directory
  await client.uploadDir("/local/dir", "/remote/dir");
});
// SFTP connection with SSH key (if pass is omitted, uses ~/.ssh/id_ed25519 or SSH agent)
await StorageFactory.connect("sftp", {
  host: "sftp.example.com",
  port: 22,
  user: "username",
  // No password provided - uses SSH key authentication
}, async (client) => {
  const files = await client.readdir("/remote/path");
  await client.uploadDir("/local/dir", "/remote/dir");
});

FtpStorageClient (Direct Usage)

Client that uses FTP or FTPS protocol. The secure parameter in the constructor determines whether to use FTPS.

import { FtpStorageClient } from "@simplysm/storage";

// FTP client (secure: false is default)
const client = new FtpStorageClient();

// FTPS client
const secureClient = new FtpStorageClient(true);

await client.connect({
  host: "ftp.example.com",
  port: 21,
  user: "username",
  pass: "password",
});

try {
  // Upload file - from local file path
  await client.put("/local/path/file.txt", "/remote/path/file.txt");

  // Upload file - from Uint8Array byte data
  const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
  await client.put(bytes, "/remote/path/hello.bin");

  // Download file (returns Bytes, i.e. Uint8Array)
  const data = await client.readFile("/remote/path/file.txt");
  const text = new TextDecoder().decode(data);

  // List directory contents
  const files = await client.readdir("/remote/path");

  // Check if file/directory exists
  const exists = await client.exists("/remote/path/file.txt");

  // Create directory (creates parent directories too)
  await client.mkdir("/remote/new/nested/path");

  // Rename file
  await client.rename("/remote/old-name.txt", "/remote/new-name.txt");

  // Delete file
  await client.remove("/remote/path/file.txt");

  // Upload entire local directory to remote
  await client.uploadDir("/local/dir", "/remote/dir");
} finally {
  // Connection must be closed
  await client.close();
}

SftpStorageClient (Direct Usage)

Client that uses SFTP protocol. It implements the same Storage interface as FtpStorageClient, so the API is identical.

import { SftpStorageClient } from "@simplysm/storage";

const client = new SftpStorageClient();

// Connection with password
await client.connect({
  host: "sftp.example.com",
  port: 22,
  user: "username",
  pass: "password",
});

try {
  // All methods of the Storage interface can be used identically
  await client.put("/local/path/file.txt", "/remote/path/file.txt");
  const data = await client.readFile("/remote/path/file.txt");
  const files = await client.readdir("/remote/path");
  const exists = await client.exists("/remote/path/file.txt");
  await client.mkdir("/remote/new/path");
  await client.rename("/remote/old.txt", "/remote/new.txt");
  await client.remove("/remote/path/file.txt");
  await client.uploadDir("/local/dir", "/remote/dir");
} finally {
  await client.close();
}
// Connection with SSH key (password omitted)
const client = new SftpStorageClient();

await client.connect({
  host: "sftp.example.com",
  port: 22,
  user: "username",
  // Uses ~/.ssh/id_ed25519 or SSH agent for authentication
});

try {
  await client.put("/local/path/file.txt", "/remote/path/file.txt");
  // ... other operations
} finally {
  await client.close();
}

Caveats

Connection Management

  • Using StorageFactory.connect() is recommended. The connection is automatically closed when the callback ends, and closure is guaranteed in the finally block even if an exception occurs.
  • When using clients directly, you must call close() with a try/finally pattern. Otherwise, connections may leak.
  • Calling connect() again on an already connected instance will cause an error. If reconnection is needed, call close() first.
  • Calling close() when already closed does not cause an error.

exists() Behavior

  • FTP: Checks files with the SIZE command (O(1)), and on failure, lists the parent directory to check if a directory exists. Performance may degrade in directories with many entries.
  • SFTP: Uses ssh2-sftp-client's exists() method, returns true for files ("-"), directories ("d"), and symbolic links ("l").
  • Both implementations return false instead of throwing exceptions when the parent directory doesn't exist or on network/permission errors.

Byte Data Type

  • Bytes used in the return type of readFile() and input type of put() is a Uint8Array type alias defined in @simplysm/core-common.

License

Apache-2.0