Files
skills/docs/media/audio-ir/audio-ir-room-plugin-club/src/register/register.md
2026-05-29 08:20:56 +01:00

5.0 KiB

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 UriPlugins 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

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

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.