first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
# `register` — collector-pattern wiring entrypoint
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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.