# `provider/chain-map` ## Purpose `ChainMap` is the provider-scoped lazy registry of `PluginChain` instances, keyed by track id. The hook `usePluginChain(trackId)` calls `getOrCreate(trackId)` to fetch (or create) the chain associated with that track, so two consumers asking for the same id see the same chain instance. The map's `dispose()` is wired into the provider's unmount path to dispose every chain it holds. ## Features - Lazy creation: chains are constructed on first request, not eagerly at mount. - Identity stable for the same `trackId` across calls. - Configurable default channels / sampleRate / blockSize at construction; per-call overrides via `getOrCreate(id, config)`. - Inert after `dispose()` — further calls throw. ## Usage: Basic ```ts import { ChainMap, ProviderBusRegistry } from "@suaveplan/react-audio/provider"; const buses = new ProviderBusRegistry(); const chains = new ChainMap(buses); const chainA = chains.getOrCreate("track-a"); const sameChainA = chains.getOrCreate("track-a"); // === chainA ``` ## Usage: Advanced ```ts import { ChainMap, ProviderBusRegistry } from "@suaveplan/react-audio/provider"; const buses = new ProviderBusRegistry(); const chains = new ChainMap(buses, { channels: 1, sampleRate: 44_100, blockSize: 256, }); // Per-track override: const monoChain = chains.getOrCreate("voice", { channels: 1 }); const stereoChain = chains.getOrCreate("master", { channels: 2 }); ``` ## API Reference - `new ChainMap(buses, defaultConfig?)`. - `getOrCreate(trackId, config?): PluginChain`. - `get(trackId): PluginChain | undefined`. - `list(): ReadonlyArray`. - `dispose(): void`. ## Implementation Notes The map stores fully-constructed `PluginChain` instances; there is no proxy or wrapping. `dispose()` is idempotent and iterates the internal map's `values()`, calling `chain.dispose()` on each. After dispose the map is cleared so a late `get()` returns `undefined` and a late `getOrCreate()` throws. The Phase-1 default channels / sampleRate / blockSize line up with the typical browser audio context defaults; consumers who need different shapes pass them through `getOrCreate(id, config)` per chain. The `buses` argument is held by reference and passed into every chain — keeping a single bus registry for the whole provider subtree means sidechain wiring across tracks remains coherent.