# `register` — collector-pattern wiring entrypoint _(no submodules)_ ## Purpose This module is the only side-effecting entrypoint a consumer ever calls from `@suaveplan/audio-ir-room-plugin-club`. It bridges three pieces that exist in three separate packages: the in-memory `IrRegistry` from `@suaveplan/audio-ir-core` (which holds manifest entries), a `MutableUriPluginRegistrar` collector — typically built via `createUriPluginCollector()` — that gathers `UriPlugin`s before resolver construction, and the `bundleUriPlugin` from `@suaveplan/storage-uri-plugin-bundle` (which knows how to read this package's bundled WAVs). The package never auto-registers on import — every consumer calls `register(registry, collector)` explicitly. Importing the package's barrel without calling `register` is a no-op aside from loading the frozen manifest constant. This matches the side-effect-free contract on all `@suaveplan/audio-ir-*` content packages and matches the family-canon shape established by `audio-ir-room-plugin-pool`. ## Features - Single call wires both the bundle adapter (via `target.use(plugin)`) and the manifest registration (via `registerManifest`). - `RegisterOptions.fetch?: FetchLike` lets Node-tier callers pass `nodeFileFetch` so `file://` reads work under undici's global `fetch`. - Default `rootUrl` resolves to the in-tarball `files/` directory via `import.meta.url` — works in both Node and any modern bundler that preserves package URLs. - No `createPlugin()` separate step; no `resolver.hasScheme("bundle")` structural check; the collector pattern makes both unnecessary. - Errors from `registerManifest` (`AUDIO_IR.DUPLICATE_ID`, `AUDIO_IR.ID_PREFIX_MISMATCH`, …) pass through verbatim. ## Usage: Basic ```ts import { createIrRegistry, createUriPluginCollector, } from "@suaveplan/audio-ir-core"; import { register } from "@suaveplan/audio-ir-room-plugin-club"; import { createStorageUriResolver } from "@suaveplan/storage-uri"; const registry = createIrRegistry(); const collector = createUriPluginCollector(); register(registry, collector); const resolver = createStorageUriResolver(collector.plugins); // registry.has("club-club1") === true // registry.has("club-club2") === true ``` ## Usage: Advanced ```ts import { createIrRegistry, createUriPluginCollector, } from "@suaveplan/audio-ir-core"; import { createIrLoader } from "@suaveplan/audio-ir-loader"; import { decodeWav } from "@suaveplan/audio-decode-wav"; import { register } from "@suaveplan/audio-ir-room-plugin-club"; import { createStorageUriResolver } from "@suaveplan/storage-uri"; import { nodeFileFetch } from "@suaveplan/storage-uri-plugin-bundle/node-fetch"; // Node.js: globalThis.fetch refuses file:// — wire nodeFileFetch. const registry = createIrRegistry(); const collector = createUriPluginCollector(); register(registry, collector, { fetch: nodeFileFetch }); const resolver = createStorageUriResolver(collector.plugins); const loader = createIrLoader({ registry, resolver, decoders: { wav: decodeWav }, }); const club1 = await loader.load("club-club1"); console.log(club1.channelData[0].length, "samples @", club1.sampleRate, "Hz"); ``` ## API Reference ### `register(registry: IrRegistry, target: MutableUriPluginRegistrar, options?: RegisterOptions): void` Builds the package-scoped `bundleUriPlugin`, hands it to `target.use(plugin)`, then calls `registerManifest(registry, manifest)`. - `registry` — an `IrRegistry` from `@suaveplan/audio-ir-core`. - `target` — any object satisfying `MutableUriPluginRegistrar` (`use(plugin: UriPlugin): void`). Typically built via `createUriPluginCollector()`. - `options.fetch?: FetchLike` — overrides the runtime fetch (pass `nodeFileFetch` on Node so `file://` URLs resolve). Throws `AUDIO_IR.DUPLICATE_ID` if any manifest entry is already in the registry. ### `interface RegisterOptions` - `readonly fetch?: FetchLike` — see above. ## Implementation Notes `new URL("../../files/", import.meta.url)` is intentional — the `register/register.ts` file lives at `src/register/register.ts` in the source tree, and at `dist/register/register.js` after build. In both cases two levels up lands on the package root, where `files/` sits at the same level as `dist/` and `src/`. The trailing slash is required by `bundleUriPlugin`'s `rootUrl` validator. The `target.use(plugin)` call happens before `registerManifest(...)` so that even when `registerManifest` rejects (for example with `AUDIO_IR.DUPLICATE_ID` on a double-register), the bundle plugin is already in the caller's collector. This matches the family-canon ordering established by `audio-ir-room-plugin-pool` and keeps the collector observable when tests inspect it after a thrown error. The double-register test relies on `registerManifest` calling `registry.register(entry, ctx)` for each entry in declaration order. The registry throws `AUDIO_IR.DUPLICATE_ID` on the first colliding id — for this package, `club-club1` — so the rethrown error is deterministic.