Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
# `error-codes.ts` — `AUDIO_IR_LOADER.*` registry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module is the single source of truth for every error code raised by
`@suaveplan/audio-ir-loader`. It uses `defineCodes` from `@suaveplan/error`
to register an immutable, byte-stable mapping of short keys (`MANIFEST_MISMATCH`)
to fully-qualified strings (`AUDIO_IR_LOADER.MANIFEST_MISMATCH`). It also
declares the `AudioIrLoaderError` class, which exposes every dimension an
operator might filter on (`id`, `extension`, `field`, `manifestValue`,
`decodedValue`, `maxBytes`, `decodedBytes`, `errors`) as typed read-only
properties so dashboards and routing layers never have to parse message
text to know what happened.
## Features
- Six codes — `DECODER_UNAVAILABLE`, `MANIFEST_MISMATCH`, `ABORTED`,
`CACHE_OVERFLOW`, `DECODE_FAILED`, `RESOLVE_FAILED`.
- Frozen registry object — `Object.isFrozen(AUDIO_IR_LOADER_CODES)` is true.
- Typed error class with discriminants pre-typed on the class.
- Aggregate `errors[]` for the `DECODE_FAILED` partial-failure path from
`preload`.
## Usage: Basic
```ts
import {
AUDIO_IR_LOADER_CODES,
AudioIrLoaderError,
} from "@suaveplan/audio-ir-loader";
throw new AudioIrLoaderError(
AUDIO_IR_LOADER_CODES.DECODER_UNAVAILABLE,
"no decoder registered for .flac",
{ id: "club-club1", extension: "flac" }
);
```
## Usage: Advanced
The aggregate `errors` discriminant powers the `preload` partial-failure
contract:
```ts
import { AudioIrLoaderError, AUDIO_IR_LOADER_CODES } from "@suaveplan/audio-ir-loader";
try {
await loader.preload(["a", "b", "c"]);
} catch (err) {
if (
err instanceof AudioIrLoaderError &&
err.code === AUDIO_IR_LOADER_CODES.DECODE_FAILED
) {
for (const { id, error } of err.errors ?? []) {
console.error(`load ${id} failed:`, error.code);
}
}
}
```
Operators routing on the structured discriminants can ship dashboards that
break down failures by `extension` for `DECODER_UNAVAILABLE`, by `field` for
`MANIFEST_MISMATCH`, and by the size pair (`maxBytes` / `decodedBytes`) for
`CACHE_OVERFLOW`, with zero message-text regexes.
## API Reference
### `AUDIO_IR_LOADER_CODES`
Frozen `Readonly<Record<Key, "AUDIO_IR_LOADER.<Key>">>` with keys
`DECODER_UNAVAILABLE`, `MANIFEST_MISMATCH`, `ABORTED`, `CACHE_OVERFLOW`,
`DECODE_FAILED`, `RESOLVE_FAILED`.
### `AudioIrLoaderError extends SuaveplanError`
Constructor: `(code, message, options?)`. Discriminants on the instance:
`id`, `extension`, `field`, `manifestValue`, `decodedValue`, `maxBytes`,
`decodedBytes`, `errors`. `name === "AudioIrLoaderError"`.
### `AudioIrLoaderErrorOptions`
Extends `SuaveplanErrorOptions` with the seven optional discriminants
listed on the class plus `errors: readonly AggregatedLoadFailure[]`.
### `AggregatedLoadFailure`
`{ id: string; error: SuaveplanError }` — one entry per failed id in a
`preload` aggregate.
## Implementation Notes
`defineCodes` returns a frozen object; the registry guarantees byte-stable
code strings across builds. The discriminants on `AudioIrLoaderError` are
declared as `T | undefined` rather than via `exactOptionalPropertyTypes`
gymnastics so callers reading the property always get an unambiguous
"absent" sentinel. Every code in this registry is exercised by a real
call site under test (see `error-codes.test.ts`) — the exhaustion test
guarantees we cannot register a code that has no production thrower.