@nodeflow-network/nodeflow-bin
v0.1.4
Published
Prebuilt Lightning Network binaries (LND, Lightning Terminal suite, Loop, Pool, RGB Lightning Node, Tor) distributed as an npm package with per-platform optionalDependencies.
Maintainers
Readme
nodeflow-bin
Prebuilt Lightning Network binaries — litd, litcli, lncli, tapcli, loop, pool, frcli, rgb-lightning-node, and tor — distributed as a single npm package so Node.js projects can npm install and spawn them without building from source or running Docker.
Install
npm install @nodeflow-network/nodeflow-binnpm picks the right platform sub-package automatically via optionalDependencies constrained on os / cpu. Only the bytes for the current machine are downloaded.
Usage
const bin = require('@nodeflow-network/nodeflow-bin');
const { spawn } = require('child_process');
// Fail fast at startup: throws if anything you need is missing on this host.
bin.assertAvailable(['litd', 'lncli', 'tor']);
// Resolve absolute paths — no PATH mutation, no wrapper scripts.
console.log(bin.litd); // /.../node_modules/@nodeflow-network/bin-<platform>/bin/terminal/litd
console.log(bin.lncli);
console.log(bin.tor);
// Spawn normally.
const lit = spawn(bin.litd, ['--lit-dir=/tmp/lit'], { stdio: 'inherit' });The snake_case alias bin.rgb_lightning_node is accepted for readability; bin['rgb-lightning-node'] works too.
bin.toSpawnablePath(path) is exported for consumers who construct their own paths (e.g., from platformKey() or sub-package introspection) and need to translate them for spawn under Electron. It is a no-op outside Electron or when the input path contains no app.asar segment, so it is safe to call unconditionally.
Error handling
const bin = require('@nodeflow-network/nodeflow-bin');
try {
bin.assertAvailable(['litd', 'lncli', 'rgb-lightning-node']);
} catch (err) {
if (err instanceof bin.UnsupportedPlatformError) {
// Running on a platform we don't ship for (e.g., Intel Mac).
// err.platform, err.arch
}
if (err instanceof bin.BinaryNotAvailableError) {
// One or more binaries missing on this platform or broken install.
// err.missing is a string[] of every missing name.
// err.platformKey identifies the current host (e.g. 'win32-x64').
}
}Both errors have a human-readable message pointing at the exact cause.
Supported platforms
| Platform | All 9 binaries (litd, litcli, lncli, tapcli, loop, pool, frcli, rgb-lightning-node, tor) |
| --------------- | ------------------------------------------------------------------------------------------- |
| darwin-arm64 | ✓ |
| linux-x64 | ✓ |
| win32-x64 | ✓ |
Intel Mac (darwin-x64) is not supported. The rgb-lightning-node upstream publishes only an arm64 macOS build and Rosetta 2 cannot translate arm64 → x86_64. Intel Mac consumers receive an UnsupportedPlatformError. Other platforms (linux-arm64, FreeBSD, etc.) are also unsupported.
Electron support
Packaging with Electron requires two electron-builder settings so the bundled binaries are spawnable at runtime:
{
"build": {
"asar": true,
"asarUnpack": ["node_modules/@nodeflow-network/**"]
}
}Why the asarUnpack glob must cover the entire @nodeflow-network/ subtree: tor is dynamically linked against sibling shared libraries (libevent.*, libssl.*, libcrypto.*) that the fetch pipeline places alongside it in bin/tor/. Those libs are found at runtime via $ORIGIN RPATH on Linux and @executable_path on macOS — both resolve relative to the directory containing the tor binary. If asarUnpack unpacks only the executable but not its siblings, the dynamic linker fails with a "cannot open shared object file" error. A whole-subtree unpack keeps the whole layout intact on disk.
The resolver automatically translates app.asar paths to app.asar.unpacked before returning them, so consumer code does not need to know about this detail:
// Inside an Electron main process:
const bin = require('@nodeflow-network/nodeflow-bin');
spawn(bin.tor, ['-f', '/etc/torrc']); // path is already app.asar.unpacked/... — spawn just worksIf asarUnpack is misconfigured and the on-disk file is missing, assertAvailable throws BinaryNotAvailableError at pre-check time with the exact unpacked path that was expected, so the failure points straight at the packaging config rather than surfacing as a cryptic ENOTDIR from spawn.
Renderer process: spawning native binaries from the renderer is discouraged by Electron. Resolve paths in the main process or preload script and pass them to the renderer via IPC if needed.
What you get per binary
| Binary | Source | Version |
| --- | --- | --- |
| litd, litcli, lncli, tapcli, loop, pool, frcli | Lightning Terminal v0.16.0-alpha | LND 0.20.0-beta, taproot-assets 0.7.0-alpha, loop 0.31.5-beta, pool 0.6.6-beta, faraday 0.2.16-alpha |
| rgb-lightning-node | lnfi-network-dev/rgb-lightning-node v0.2.1-rc.6 | 0.2.1-rc.6 |
| tor | Tor Project Expert Bundle 15.0.9 | 0.4.9.6 |
Version coupling is intentional: every Lightning Network binary comes from the same lightning-terminal release tag. Do not mix versions — gRPC schemas diverge across releases and mismatched binaries will refuse to talk to each other at runtime.
See PINNED_VERSIONS.md on GitHub for exact archive filenames, sha256 values, and GPG signer fingerprints.
Licensing
Each bundled upstream binary retains its original license. See LICENSES.md for the full list (MIT for the Lightning Labs suite and RGB Lightning Node; 3-clause BSD for Tor and libevent). The nodeflow-bin wrapper itself is MIT licensed.
Links
- Source: github.com/nodeflow-network/nodeflow-bin
- Issues: github.com/nodeflow-network/nodeflow-bin/issues
- Contributing / internals: see the repo root README.md for development workflow, CI release pipeline, and how upstream versions are pinned.
