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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@moritzloewenstein/rsync

v1.0.3

Published

Rsync cli wrapper

Readme

Rsync

A TypeScript-first rsync wrapper for Node.js with a Promise-based API.

Installation

npm install @moritzloewenstein/rsync

Features

  • TypeScript native - Full type definitions included
  • Promise-based API - Modern async/await support
  • Simple configuration - Options object-based API
  • Type-safe - Comprehensive TypeScript interfaces
  • ESM - Pure ES modules

Quick Start

import Rsync from "rsync";

const rsync = new Rsync({
  source: "/path/to/source",
  destination: "server:/path/to/destination",
  flags: "avz",
  shell: "ssh",
});

try {
  const result = await rsync.execute();
  console.log("Transfer complete:", result.cmd);
} catch (error) {
  console.error("Transfer failed:", error);
}

API

Constructor

Create a new Rsync instance with an options object:

const rsync = new Rsync(options);

Options

interface RsyncOptions {
  // Source and destination
  source?: string | string[];
  destination?: string;

  // Executable configuration
  executable?: string; // default: 'rsync'
  executableShell?: string; // default: '/bin/sh'

  // Process configuration
  cwd?: string;
  env?: NodeJS.ProcessEnv;

  // Flags (string or array of single letter flags)
  flags?: string | string[]; // e.g., 'avz' or ['a', 'v', 'z']

  // Common options
  shell?: string; // SSH shell
  delete?: boolean; // --delete
  progress?: boolean; // --progress
  chmod?: string | string[]; // --chmod

  // Transfer options
  archive?: boolean; // -a
  compress?: boolean; // -z
  recursive?: boolean; // -r
  update?: boolean; // -u
  quiet?: boolean; // -q
  dirs?: boolean; // -d
  links?: boolean; // -l
  dry?: boolean; // -n (dry run)

  // Preservation options
  hardLinks?: boolean; // -H
  perms?: boolean; // -p
  executability?: boolean; // -E
  owner?: boolean; // -o
  group?: boolean; // -g
  acls?: boolean; // -A
  xattrs?: boolean; // -X
  devices?: boolean; // --devices
  specials?: boolean; // --specials
  times?: boolean; // -t

  // Include/Exclude patterns
  exclude?: string | string[];
  include?: string | string[];

  // Output handlers
  output?: [(data: Buffer) => void, (data: Buffer) => void];

  // Custom options
  set?: Record<string, string | null>;
}

Methods

execute(stdoutHandler?, stderrHandler?): Promise<RsyncResult>

Execute the rsync command. Returns a Promise that resolves with the result or rejects with an error.

// Simple execution
const result = await rsync.execute();

// With output handlers
const result = await rsync.execute(
  (data) => console.log("stdout:", data.toString()),
  (data) => console.error("stderr:", data.toString())
);

Returns:

interface RsyncResult {
  code: number; // Exit code (0 for success)
  cmd: string; // The executed command
}

Errors:

interface RsyncError extends Error {
  code: number; // rsync exit code
  cmd: string; // The executed command
}

command(): string

Get the complete command string that will be executed.

const cmdString = rsync.command();
console.log(cmdString); // "rsync -avz --rsh=ssh /source server:/dest"

args(): string[]

Get the arguments array for the command.

const args = rsync.args();
console.log(args); // ['-avz', '--rsh=ssh', '/source', 'server:/dest']

executable(): string

Get the rsync executable path.

const exe = rsync.executable(); // 'rsync'

source(): string[]

Get the list of source paths.

const sources = rsync.source(); // ['/path/to/source']

destination(): string

Get the destination path.

const dest = rsync.destination(); // 'server:/path/to/dest'

Examples

Basic sync

const rsync = new Rsync({
  source: "/local/path",
  destination: "remote:/remote/path",
  flags: "avz",
});

await rsync.execute();

With excludes

const rsync = new Rsync({
  source: "/project",
  destination: "server:/backup",
  flags: "avz",
  exclude: ["node_modules", ".git", "*.log"],
  delete: true,
});

await rsync.execute();

With includes and excludes

const rsync = new Rsync({
  source: "/data",
  destination: "/backup",
  flags: "avz",
  exclude: ["*"],
  include: ["*.txt", "*.md"],
});

await rsync.execute();

Progress monitoring

const rsync = new Rsync({
  source: "/large/dataset",
  destination: "server:/backup",
  flags: "avz",
  progress: true,
});

await rsync.execute(
  (data) => {
    // Parse progress from stdout
    console.log(data.toString());
  },
  (data) => {
    // Handle errors from stderr
    console.error(data.toString());
  }
);

Multiple sources

const rsync = new Rsync({
  source: ["/path/one", "/path/two", "/path/three"],
  destination: "/backup",
  flags: "avz",
});

await rsync.execute();

SSH with custom shell

const rsync = new Rsync({
  source: "/local",
  destination: "user@server:/remote",
  flags: "avz",
  shell: "ssh -i /path/to/key",
});

await rsync.execute();

Custom options

const rsync = new Rsync({
  source: "/source",
  destination: "/dest",
  flags: "avz",
  set: {
    "max-size": "100m",
    "min-size": "1k",
    timeout: "300",
  },
});

await rsync.execute();

Environment and working directory

const rsync = new Rsync({
  source: "./relative/path",
  destination: "/absolute/dest",
  cwd: "/project/root",
  env: {
    ...process.env,
    RSYNC_PASSWORD: "secret",
  },
  flags: "avz",
});

await rsync.execute();

TypeScript Usage

This library is written in TypeScript and provides full type definitions:

import Rsync, { RsyncOptions, RsyncResult, RsyncError } from "rsync";

const options: RsyncOptions = {
  source: "/src",
  destination: "/dst",
  flags: "avz",
};

const rsync = new Rsync(options);

try {
  const result: RsyncResult = await rsync.execute();
  console.log(`Success! Exit code: ${result.code}`);
} catch (error) {
  const rsyncError = error as RsyncError;
  console.error(`Failed with code ${rsyncError.code}: ${rsyncError.message}`);
}

Common Rsync Flags

  • a - Archive mode (equals -rlptgoD)
  • v - Verbose
  • z - Compress during transfer
  • r - Recursive
  • l - Copy symlinks as symlinks
  • p - Preserve permissions
  • t - Preserve modification times
  • g - Preserve group
  • o - Preserve owner
  • H - Preserve hard links
  • n - Dry run (no changes made)
  • u - Skip files that are newer on receiver
  • q - Quiet mode

Combine multiple flags as a string: flags: 'avz'

Migration from v0.x

The API has changed significantly in v1.0:

Old (v0.x) - Callback & Chaining

var Rsync = require("rsync");

var rsync = new Rsync()
  .shell("ssh")
  .flags("az")
  .source("/path/to/source")
  .destination("server:/path/to/destination");

rsync.execute(function (error, code, cmd) {
  // callback
});

New (v1.0+) - Promise & Options

import Rsync from "rsync";

const rsync = new Rsync({
  shell: "ssh",
  flags: "az",
  source: "/path/to/source",
  destination: "server:/path/to/destination",
});

await rsync.execute();

Key Changes

  1. ESM instead of CommonJS - Use import instead of require
  2. TypeScript native - Full type definitions included
  3. Promise-based - execute() returns a Promise instead of using callbacks
  4. Options object - Pass all configuration to constructor, no method chaining
  5. No build() method - Just use new Rsync(options)
  6. Simplified patterns - Use exclude and include arrays, no patterns() method

License

This module is licensed under the MIT License. See the LICENSE file for more details.

Development

Build

npm run build

Test

npm test

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Run tests and type checking
  5. Submit a pull request

Changelog

v1.0.0

  • Complete TypeScript rewrite
  • Promise-based API (breaking change)
  • Constructor options-only (breaking change)
  • Removed method chaining (breaking change)
  • Removed patterns() method, use include/exclude arrays
  • ESM modules only
  • Migrated to Vitest

v0.6.1

  • Add support for windows file paths under cygwin

v0.6.0

  • Escape dollar signs in filenames
  • Add permission shorthands
  • Added env() option to set the process environment variables

v0.5.0

  • Properly treat flags as String
  • Differentiate between shell and file arguments (escaping)
  • Added unit tests and TravisCI