Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
# `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
`<AudioProvider>` 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<SidechainPublisher>`
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.