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

@heronlabs/terminal-cli

v2.2.1

Published

Heron CLI — database backup & rollup (PostgreSQL/MySQL → S3)

Readme

🪶 terminal-cli — Heron CLI (hcli)

npm version license CI TypeScript NestJS Node.js License

Database backup & rollup CLI for PostgreSQL and MySQL. Dumps a database to a gzipped SQL file, uploads it to S3 (or keeps it local), and restores it back on demand. Built with NestJS + nest-commander, AWS S3, and Luxon. Designed to run as a scheduled cron container on EasyPanel.

Table of Contents

Why This Project

Scheduled, type-safe database backups with a single binary:

  • One tool, two engines — PostgreSQL (pg_dump/psql) and MySQL (mysqldump/mysql) behind one CLI.
  • S3 or local — push backups to S3 by default, or keep them on disk with --local (handy for seeding).
  • Cron-ready container — one image plus easypanel/ inline-Dockerfile templates run a backup on start and every 12 hours.
  • 100% tested — v8 coverage + Stryker mutation testing, both at 100% thresholds.

Install

hcli is a global CLI binary. Install it globally to put hcli on your PATH:

npm i -g @heronlabs/terminal-cli
# or: pnpm add -g @heronlabs/terminal-cli

Then run any command:

hcli version
hcli psql-backup

You also need the database client tools for the engine you back up: pg_dump / psql for PostgreSQL, mysqldump / mysql for MySQL.

Quick Start

Prerequisites

| Requirement | Version | Purpose | |-------------|---------|---------| | Node.js | >=22 | Runtime | | pnpm | >=10.29.3 | Package manager | | pg_dump / psql | — | PostgreSQL backup/restore | | mysqldump / mysql | — | MySQL backup/restore |

From source (development)

git clone https://github.com/heronlabs/terminal-cli.git
cd terminal-cli
pnpm install
pnpm build         # nest build → bin/

After pnpm build, run the CLI via node bin/src/main.js <command> or link the hcli bin (pnpm link --global).

Verify

pnpm build         # nest build → bin/
pnpm lint:check    # gts + eslint
pnpm test:unit     # vitest run (100% coverage)
pnpm test:mutation # stryker (100% break)
pnpm dep:cruise    # architecture check

Commands

| Command | Description | |---|---| | hcli psql-backup | Back up a PostgreSQL database (S3 by default) | | hcli psql-rollup --filename <file> | Restore a PostgreSQL database from a backup | | hcli mysql-backup | Back up a MySQL database (S3 by default) | | hcli mysql-rollup --filename <file> | Restore a MySQL database from a backup | | hcli easypanel-backup | Snapshot an EasyPanel host — config + Docker state — to a .tar.gz (S3 by default). Run as root on the host. | | hcli easypanel-rollup --filename <file> | Restore an EasyPanel host from a snapshot. Run as root on the host. Overwrites host files. | | hcli version | Print the current version |

Flags

| Flag | Applies to | Meaning | |---|---|---| | -f, --filename <name> | all | Backup filename. DB backups default to <database>-<timestamp>.sql.gz and easypanel-backup to easypanel-<timestamp>.tar.gz; rollup requires it. | | --local | all | Read/write the backup on the local filesystem instead of S3. |

Examples:

# Back up to S3 with an auto-generated, timestamped filename
hcli psql-backup

# Back up to a local file (no S3)
hcli psql-backup --local --filename seed.sql.gz

# Restore from a local file
hcli psql-rollup --local --filename seed.sql.gz

# Restore from S3
hcli mysql-rollup --filename mydb-2026-03-05T12-00-00Z.sql.gz

# Snapshot an EasyPanel host to S3 (run as root on the host)
sudo hcli easypanel-backup

# Snapshot to a local file with a custom name
sudo hcli easypanel-backup --local --filename easypanel-snapshot.tar.gz

# Restore an EasyPanel host from S3 (OVERWRITES host files)
sudo hcli easypanel-rollup --filename easypanel-2026-03-05T12-00-00Z.tar.gz

Configuration

All configuration comes from environment variables (see .env.example).

| Variable | Required | Description | |---|---|---| | DB_URL | ✅ | Connection URL (postgres:///mysql://user:pass@host:port/dbname) or an AWS SSM Parameter Store ARN resolved via @heronlabs/env-ssm | | AWS_S3_BUCKET_NAME | for S3 | Destination bucket for remote backups | | AWS_REGION | for S3 | AWS region | | AWS_ACCESS_KEY_ID | for S3 | AWS credentials (or use an instance role) | | AWS_SECRET_ACCESS_KEY | for S3 | AWS credentials (or use an instance role) |

Locally, pnpm start -- <command> loads variables from a .env file via dotenv.

Architecture

Hexagonal NestJS layering:

src/
├── application/          # CLI surface (nest-commander)
│   └── cli/
│       ├── cli-module.ts
│       └── commands/     # backup/, rollup/, version/ + per-command option types
├── core/                 # domain logic
│   ├── interfaces/       # BackupService / RollupService abstract base services
│   └── services/         # {mysql,psql}-{backup,rollup}-service
└── infrastructure/       # adapters
    ├── environment/      # EnvironmentService (ConfigService wrapper)
    ├── log/              # nestjs-pino logger module
    └── storage/          # S3StorageService (AWS SDK v3)
  • application/ wires commands into modules — the composition root.
  • core/ holds the backup/rollup flow. The abstract BackupService/RollupService own the S3 upload/download + local-cleanup orchestration; engine subclasses implement the dump/restore shell commands.
  • infrastructure/ adapters never import inward (enforced by pnpm dep:cruise).

Docker & Cron

One published image — heronlabs/terminal-cli (built from Dockerfile) — carries hcli on PATH, both DB clients, and busybox crond. Scheduled backups are deployed from the inline-Dockerfile templates under easypanel/: each one is FROM heronlabs/terminal-cli:<tag>, adds a 12-hourly crontab, and runs an immediate backup before starting crond in the foreground (dumping printenv to /etc/environment so cron inherits the runtime variables EasyPanel injects). See easypanel/README.md for deploy steps.

Local stack for manual testing — docker-compose.yml runs the psql + mysql DBs (exposed on ports 5434/3307) and the psql-integration/mysql-integration services that run the backup/rollup round-trip inside the prod-shaped integration-{postgres,mysql}.dockerfile images:

docker compose up postgres mysql              # local DBs only
docker compose run --build --rm psql-integration   # PostgreSQL round-trip
docker compose run --build --rm mysql-integration  # MySQL round-trip

EasyPanel host backup

easypanel-backup / easypanel-rollup snapshot a whole EasyPanel host — /etc/easypanel, /var/lib/docker/volumes, and /var/lib/docker/buildkit — into a single .tar.gz. To keep the snapshot consistent the command stops the Docker daemon while the archive is taken and restarts it afterwards (even if the backup fails).

Because it runs systemctl stop docker and reads /var/lib/docker, it must run natively on the host as root, not inside a container managed by that daemon. If not run as root the command refuses to start (it will not stop Docker and then fail), so schedule it as root.

⚠️ easypanel-rollup extracts the archive to / and overwrites host files (/etc/easypanel and /var/lib/docker). It does not prompt — run it deliberately, against a host you intend to roll back.

Scheduling (every 12h)

Install the CLI on the host (Ubuntu 22.04) and match the DB backup templates' cadence with a host crontab line:

npm i -g @heronlabs/terminal-cli
# /etc/crontab — run as root, source the env first
0 */12 * * * root . /etc/easypanel-backup.env; hcli easypanel-backup

Put the AWS_* variables (the easypanel-* commands need only AWS_*, no DB vars) in /etc/easypanel-backup.env.

Testing

| Detail | Value | |---|---| | Framework | Vitest 4.x (vitest.config.ts, SWC transform for decorators) | | Test location | tests/specs/ (mirrors src/) | | Shared mocks | tests/__mocks__/create-testing-module.ts (moq.ts + vitest) | | Coverage | v8, 100% lines/functions/branches/statements | | Coverage excludes | **/main.ts, **/*.d.ts, **/*factory.ts, **/types/ | | Mutation | Stryker 9.x (stryker.conf.json), 100% break threshold | | Mutation scope | src/**/*.ts excluding main.ts, *.d.ts, *factory.ts, *-module.ts |

pnpm test:unit      # vitest run with coverage
pnpm test:mutation  # stryker mutation testing

Contributing

pnpm lint:check   # check
pnpm lint:fix     # auto-fix
pnpm build        # verify compilation
pnpm test:unit    # verify tests pass at 100% coverage
pnpm dep:cruise   # verify architecture

Conventional Commits:

feat: add mongodb backup engine
fix: handle empty database name in psql dump
test: cover s3 download error path
  • All work branches from main; PRs target main. Never commit directly to main.

License

MIT — see LICENSE.


Built by HeronLabs