npm package: @kud/firefox-downloader-cli
Description: CLI tool to interactively or non-interactively download and install Firefox versions for macOS from Mozilla FTP.
Latest version: 0.4.0

<div align="center">

# 🦊 firefox-downloader-cli

**Download & (optionally) install Firefox builds for macOS – fast, scriptable, interactive.**

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](#license)  ![Platform](https://img.shields.io/badge/platform-macOS-black)  ![Node Version](https://img.shields.io/badge/node-%E2%89%A520.11%20%3C25-339933)  ![Status](https://img.shields.io/badge/status-alpha-orange)

</div>

A lightweight ESM CLI that pulls official Firefox builds (release / beta / ESR / nightly) from Mozilla infrastructure, with interactive selection or pure flag-driven automation.

---

## ✨ Highlights

- 🧭 **Interactive wizard** (channel → version → locale → install) 
- 🏷 **Version & channel listing** (`release`, `beta`, `esr`, `nightly`*)
- 📦 **Downloads universal macOS DMGs** (arm64 / x64 selection) 
- 🛠 **Direct install** (mounts DMG & copies into `/Applications` with intelligent permission fallback/prompt)
- 🔐 **Optional SHA256 verification** (release/beta/esr)
- 🧪 **Dry‑run + JSON output** for scripting / CI
- 🌍 **Locale selection** (including nightly per-build locale scraping)
- ⚡ **Nightly build directory exploration** (date + time + l10n variants)
- 🧱 **Zero build step** – pure Node ≥20 ESM

> *Nightly support currently lists recent dated build directories and fetches locales heuristically; deeper filtering & checksum verification for nightlies is on the roadmap.*

---

## 📦 Install

Global (once published to npm):

```bash
npm install -g firefox-downloader-cli
```

Local clone (development):

```bash
git clone <repo-url>
cd firefox-downloader-cli
npm install
npm link   # exposes `firefox-downloader`
```

One‑off (after publication):

```bash
npx firefox-downloader-cli --help
```

---

## 🚀 Quick Start

Preferred (and only shipped) command is `firefox-downloader`. You may optionally define a shell alias: `alias fx-dl='firefox-downloader'`

```bash
# Launch interactive selector
firefox-downloader   # (add your own alias: fx-dl)

# Latest release (download + install)
firefox-downloader -c release

# List versions (first 30 shown)
firefox-downloader -c esr -l

# Same but machine‑readable
firefox-downloader -c esr -l --json
```

---

### 🔄 Migration Note

Earlier snapshots referenced `firefox-dl` / `fx-dl`. These aliases are no longer published. Update scripts to use `firefox-downloader` (or create a local shell alias if desired).

---

## 🧪 Dry Run & JSON

Combine `--dry-run` and `--json` to preview what would happen:

```bash
firefox-downloader -c release --dry-run --json
# → { "action": "download", "url": "…", "outPath": "…", "install": true }
```

Use this in pipelines to compute artifacts without network transfer (yet).

---

## 🛠 CLI Reference

```
firefox-downloader [options]
```

| Flag | Description | Default |
|------|-------------|---------|
| `-i, --interactive` | Force interactive mode | auto when no other action flags |
| `-c, --channel <channel>` | `release|beta|esr|nightly` | – |
| `-v, --version <version>` | Explicit version (e.g. `143.0.1`, `115.28.0esr`) | resolved per channel |
| `-l, --list` | List available versions for the channel | – |
| `-a, --arch <arch>` | `arm64|x64` | host arch |
| `-L, --locale <locale>` | Locale code | `en-US` |
| `-d, --dest <path>` | Destination download directory | `cwd` |
| `--no-install` | Skip install; leave DMG only | install enabled |
| `--verify` | Verify SHA256 (non-nightly) | off |
| `--dry-run` | Show planned action only | off |
| `--json` | JSON output (list/dry-run) | off |
| `--timeout <ms>` | Network timeout | `30000` |

### Subcommand: `install`

```
firefox-downloader install [options]
```

| Flag | Description |
|------|-------------|
| `-v, --version <version>` | Version to download & install |
| `-c, --channel <channel>` | Fallback if no `--version` (incl. nightly) |
| `-a, --arch <arch>` | Architecture |
| `-L, --locale <locale>` | Locale |
| `-f, --file <path>` | Install from existing DMG (skip download) |
| `--no-verify` | Skip checksum verification |
| `--timeout <ms>` | Network timeout |

### Subcommand: `interactive`
Explicitly launches the same wizard as running bare.

---

## 🧭 Nightly Builds

Nightly directories are scraped for recent dates (current + previous month). You can:

1. Select a date.
2. Pick a timestamp build (base or `-l10n` variant – the l10n variant exposes all locales).
3. Choose a locale (scanned from directory listing).

Direct (non-interactive) nightly resolution with `-c nightly` uses the current nightly symlink when not specifying a dated directory.

---

## 🔐 Checksum Verification

For release/beta/ESR builds, `--verify` fetches `SHA256SUMS` and compares the downloaded DMG’s SHA256. Nightly verification is skipped (not yet implemented due to differing artifact layout / absence of stable checksum index).

---

## 📂 Installation Paths & Permissions

By default the tool attempts to install into `/Applications`.

If permission is denied (common on systems without sudo in the current environment):

- In interactive mode you are prompted to: Retry / Install to `~/Applications` / Cancel.
- On choosing retry you can adjust permissions externally then try again.
- Selecting the user option installs to `~/Applications` (creating it if missing).
- Non-interactive mode falls back automatically to `~/Applications` and prints a warning.
- A warning is printed if another Firefox bundle already exists in the alternate Applications directory so you can clean up duplicates.

This reduces confusion when both `/Applications/Firefox.app` and `~/Applications/Firefox.app` exist.

## 📁 Examples

```bash
# Latest beta, verify checksum
firefox-downloader -c beta --verify

# Explicit ESR version (download only)
firefox-downloader -v 115.28.0esr --no-install -d ./cache

# French locale, keep DMG
firefox-downloader -v 143.0.1 -L fr --no-install

# Install from an already-downloaded file
authenticated_path="./downloads/Firefox 143.0.1.dmg"
firefox-downloader install --file "$authenticated_path"

# Programmatic style (JSON list)
firefox-downloader -c release -l --json | jq '.[0]'
```

---

## 🧩 Integration Tips

- Use `--dry-run --json` first to stage artifact planning in CI.
- Cache DMGs between jobs to avoid re-download (e.g., GitHub Actions cache keyed by version + locale).
- For scripting, treat non-zero exit codes as failure (errors are written to stderr in red with stack when available).

---

## 🗺 Roadmap

- Improved nightly checksum & version abstraction
- Partial / resumable downloads
- Multi-locale enumeration outside nightly flow
- Uninstall command (`firefox-downloader uninstall`)
- Structured tests + CI matrix
- Progress bar (streaming) & retry logic

Have a feature in mind? Open an issue or PR.

---

## 🤝 Contributing

1. Fork & clone
2. `npm install`
3. Make changes (keep style consistent) 
4. Run `npm lint`
5. Open a PR with a concise description (include before/after if UX related)

Small focused PRs are easier to review.

---

## ⚠️ Disclaimer

This tool fetches official Firefox builds from Mozilla’s public distribution endpoints. Trademark & branding belong to Mozilla. Use at your own risk; verify hashes when security matters.

---

## 📄 License

MIT © 2025

---

<div align="center">
Made with ☕ + 🦊
</div>