3.2 KiB
binary
(no submodules)
Purpose
This module owns ffmpeg-binary discovery for @suaveplan/audio-codec-ffmpeg-native.
It implements a fixed four-step precedence chain — caller-supplied provider,
explicit absolute path, dynamically imported @ffmpeg-installer/ffmpeg
optional dependency, then PATH-based discovery — and memoises successful
resolutions by options-object identity so that high-traffic decode/encode
pipelines pay the resolution cost exactly once per shared options bundle.
The resolver throws AudioCodecFfmpegNativeError("AUDIO_CODEC_FFMPEG_NATIVE.BINARY_MISSING")
when every step fails, which lets the codec surface an actionable error to the
caller instead of waiting for a downstream ENOENT from child_process.spawn.
Features
- Strict precedence: provider → explicit path → installer → PATH lookup.
- Promise-returning provider supported (sync providers also accepted).
- Dynamic
import("@ffmpeg-installer/ffmpeg")so the optional dependency is never a hard requirement at module load. - Test-injectable
installerLoaderandpathLookuphooks decouple resolution from real filesystem state. BINARY_MISSINGerror code on full-chain failure with no leaked stack from the underlying optional-dep failure.- WeakMap-keyed memoisation that automatically GCs entries when the caller drops their options reference.
Usage: Basic
import { resolveBinary } from "@suaveplan/audio-codec-ffmpeg-native/binary/binary";
const { path, source } = await resolveBinary();
console.log(`Using ffmpeg at ${path} via ${source}`);
Usage: Advanced
import { resolveBinary } from "@suaveplan/audio-codec-ffmpeg-native/binary/binary";
const opts = {
binaryProvider: async () => process.env.FFMPEG_PATH ?? "",
binaryPath: "/usr/local/bin/ffmpeg",
installerLoader: async () => ({ path: "/opt/ffmpeg" }),
pathLookup: () => "/usr/bin/ffmpeg",
} as const;
const first = await resolveBinary(opts);
const second = await resolveBinary(opts); // memoised — no re-resolution.
API Reference
resolveBinary(opts?): Promise<ResolvedBinary>— returns{ path, source }.BinaryResolverOptions—binaryProvider,binaryPath,installerLoader,pathLookup(all optional; first match wins per the precedence chain).ResolvedBinary.source—"provider" | "explicit" | "installer" | "path".
Implementation Notes
The four-step chain is hard-coded — there is no plugin slot — because deviation
in precedence would silently change which binary actually runs on production
servers. Empty strings are treated as "miss" so callers can write () => ""
in a provider to opt into the next strategy without throwing.
The installer is imported via dynamic import() because static imports would
make @ffmpeg-installer/ffmpeg a hard dependency rather than the optional one
the spec requires. Any failure inside the installer load (missing module,
platform mismatch, exec-bit stripped) is swallowed and the chain advances —
the only surfaced error is BINARY_MISSING after the entire chain misses.
Memoisation uses a WeakMap keyed by the options object reference; callers
who want forced re-resolution pass a fresh options bundle.