# `provider/provider-bus-registry` ## Purpose `ProviderBusRegistry` is a thin wrapper around `DefaultBusRegistry` from `@suaveplan/audio-fx-plugin-base` that adds a synchronous `close()` method. The wrapper is owned by `` and torn down on unmount; closing it force-closes every still-active `SidechainPublisher` issued through this registry so no buses leak across remounts (especially relevant under React 19 Strict Mode, which double-invokes effects). ## Features - Implements `BusRegistry` so it is a drop-in for the inner default. - Tracks every `SidechainPublisher` returned by `publish()` and force-closes them on `close()`. - Inert after close — late `publish()` calls return a no-op publisher rather than throwing. - Forwards `get`, `list`, `subscribe` to the inner registry untouched. ## Usage: Basic ```ts import { ProviderBusRegistry } from "@suaveplan/react-audio/provider"; const buses = new ProviderBusRegistry(); const pub = buses.publish("sidechain", 1); pub.write([new Float32Array(128)]); buses.close(); // closes pub; subsequent publish() returns a no-op. ``` ## Usage: Advanced ```ts import { ProviderBusRegistry } from "@suaveplan/react-audio/provider"; const buses = new ProviderBusRegistry(); const pub = buses.publish("kick", 1); const off = buses.subscribe("kick", (bus) => { if (bus === undefined) console.log("bus closed"); }); buses.close(); off(); ``` ## API Reference - `new ProviderBusRegistry()` — no constructor arguments. - `publish(name, channels): SidechainPublisher` — tracked and closed on `close()`. - `get(name)`, `list()`, `subscribe(name, listener)` — delegate. - `close()` — idempotent; closes all tracked publishers. ## Implementation Notes Wrapping rather than subclassing keeps the implementation independent of the inner class's private state. The `Set` tracks the *outer* (wrapped) publisher so closing it removes itself from the set before delegating to the inner close — this avoids double-iteration concerns when `close()` calls each publisher's close which would in turn try to mutate the set. Iterating via `Array.from(this.active)` snapshots the set so concurrent mutation during the close loop is safe. Once closed, `publish()` returns an inert publisher whose `write` / `close` are no-ops, allowing late consumers to drain without throwing.