3.3 KiB
extension.ts — URI → file-extension extraction
Purpose
The loader dispatches decoders by file extension. This module owns the
canonicalisation step: given a URI string (which may be bundle://,
https://, drive://, plain path-based, or fallback://?u=…&u=…),
return the lowercase extension that decides which AudioDecoder runs.
Cross-format fallback:// URIs are explicitly rejected with
DECODER_UNAVAILABLE — a single load must pick a single decoder.
Features
- Universal across
bundle://,https://,drive://, and arbitrary path-based URIs. - Recursive handling for
fallback://URIs — every candidate is re-extracted and the result must agree across candidates. - Query and fragment components are stripped before extension extraction.
- Throws
AUDIO_IR_LOADER.DECODER_UNAVAILABLEon every failure mode (missing extension, parse error, candidate disagreement).
Usage: Basic
import { extractExtension } from "@suaveplan/audio-ir-loader";
extractExtension("bundle://x/foo.wav"); // → "wav"
extractExtension("https://cdn.example.com/path/clip.WAV?v=2"); // → "wav"
extractExtension("fallback://?u=bundle%3A%2F%2Fx%2Fa.wav&u=https%3A%2F%2Fh%2Fa.wav");
// → "wav"
Usage: Advanced
The loader uses this helper at the start of every load(id) to pick the
right decoder before any I/O happens:
import {
AUDIO_IR_LOADER_CODES,
AudioIrLoaderError,
extractExtension,
} from "@suaveplan/audio-ir-loader";
function pickDecoder<D>(decoders: Record<string, D>, uri: string, id: string): D {
const ext = extractExtension(uri, id);
const decoder = decoders[ext];
if (decoder === undefined) {
throw new AudioIrLoaderError(
AUDIO_IR_LOADER_CODES.DECODER_UNAVAILABLE,
`no decoder registered for '.${ext}'`,
{ id, extension: ext }
);
}
return decoder;
}
Cross-format fallback URIs surface as a single DECODER_UNAVAILABLE
throw with the first extension preserved on the error's extension
discriminant, which makes the diagnostic easy to act on in the manifest
authoring step.
API Reference
extractExtension(uri: string, id?: string): string
Returns the lowercase extension. The optional id is forwarded to the
AudioIrLoaderError.id discriminant on every throw so observers can
filter by IR identifier.
Throws AUDIO_IR_LOADER.DECODER_UNAVAILABLE when:
- the URI carries no
.<ext>segment after the last/, - the URI is
fallback://and is not parseable as a URL, - the URI is
fallback://with zerou=candidates, - the URI is
fallback://and candidates disagree on extension.
Implementation Notes
The bundle://x/y.wav URI form is technically not a valid RFC 3986
authority-less URI but every consumer of audio-ir-loader already deals
with it through storage-uri-plugin-bundle's own parser; the
path-stripping in this module is intentionally permissive about authority
shape so callers get a consistent dispatch result regardless of whether
the path-component is //host/key.wav or :/path/key.wav. The
fallback:// walk delegates to extractExtension recursively, so any
future URI scheme that itself wraps candidates (e.g. a hypothetical
mirror://) would only need to extend FALLBACK_PREFIX matching and
fall through to the same recursion.