3.4 KiB
Add @suaveplan/audio-ir-core
Package: @suaveplan/audio-ir-core
Status: PROPOSED
Type: new-package
Why
The IR ecosystem (audio-ir-loader, audio-ir-{mic,speaker,room}-plugin-<name> packages) needs a single foundation that owns the IR contract, manifest schema, and in-memory registry. Without it, every IR content package would reinvent the entry shape, the registry collision rule, and the ID-derivation convention — guaranteed drift. This package is the foundation every sibling depends on.
What changes
- ADDED:
ImpulseResponsetype —{ id: string; channelData: readonly Float32Array[]; channels: number; sampleRate: number; lengthFrames: number; durationSec: number; gainDb: number; family: "mic" | "speaker" | "room"; manifest: IrManifestEntry }. Frozen, validated. - ADDED:
IrManifestEntryZod schema —{ id, family, uri, channels, sampleRate, gainDb, license, source }.idmatches/^[a-z][a-z0-9-]*$/(no consecutive-, starts with a letter, length 1–128).uriis any non-empty string (deferred validation tostorage-uriat load time). - ADDED:
IrManifestZod schema —{ packageSlug: <slug grammar>, family: "mic" | "speaker" | "room", entries: readonly IrManifestEntry[] }. Everyentry.idSHALL begin with<packageSlug>-(enforced by schema refinement).entry.familySHALL equal manifest-levelfamily. - ADDED:
IrRegistry— in-memoryMap-backed registry withregister(entry),has(id),get(id),list({ family? }),clear().registerthrowsAUDIO_IR.DUPLICATE_IDwhen an ID is registered twice. - ADDED:
createIrRegistry()factory. - ADDED:
AUDIO_IR.*codes viadefineCodes:DUPLICATE_ID,NOT_REGISTERED,INVALID_MANIFEST,ID_PREFIX_MISMATCH,FAMILY_MISMATCH. - ADDED: OTel —
audio_ir.registry_size{family}observable gauge;audio_ir.registrations_total{family, outcome}counter;audio_ir.lookups_total{family, outcome}counter;audio_ir.errors_total{code}counter.
Out of scope
Nothing functional within the foundation's scope. The following are explicitly NOT here, because they belong to siblings:
- Loading + decoding —
audio-ir-loaderowns the resolver-driven walk. - Concrete IR data —
audio-ir-{mic,speaker,room}-plugin-<name>packages own the files and the per-packageregister(registry, resolver)call.
Source mapping
Genesis-original. No upstream enterprise/audio-ir-core.md exists.
Requirements with no source line
| Requirement | Justification |
|---|---|
| every spec requirement | Genesis-original foundation; no upstream baseline |
Verification approach
src/types/manifest-entry.test.ts— Zod parsing + refinement (id grammar, id-prefix rule, family rule).src/types/manifest.test.ts— manifest-level Zod validation.src/registry/registry.test.ts— register / has / get / list / clear semantics;DUPLICATE_IDthrow.src/registry/registry.spec-conformance.test.ts— strict-mode behaviors, lookup invariants under concurrency.src/otel/otel.test.ts— counter + gauge assertions with real in-memoryMeterProvider.src/error-codes/error-codes.test.ts— exhaustion.
Impact
Affected dependents
No dependents yet (the package is brand new). Verified by bunx turbo ls --filter=...@suaveplan/audio-ir-core returning only the package itself.
The first downstream consumers will be @suaveplan/audio-ir-loader and every @suaveplan/audio-ir-{family}-plugin-<name> package, each landing in its own change.