first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
# `binary`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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 `installerLoader` and `pathLookup` hooks decouple resolution
from real filesystem state.
- `BINARY_MISSING` error 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
```ts
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
```ts
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.