# `provider/audio-provider` ## Purpose `` is the single React component that owns the audio engine bundle for a React subtree. It constructs exactly one `BrowserTimelineAdapter`, one `TimelineEngine`, one `Transport`, one `ProviderBusRegistry`, and one `PluginRegistry`, publishes the resolved bundle through `AudioReactContext`, and tears every one of them down on unmount. The provider is React 19 Strict Mode safe: under the development double-invoke pattern (mount → unmount → re-mount) it never leaks an engine. The async init pipeline is gated by a cancellation flag and an `AbortController`; if the effect tears down before init resolves the flag suppresses the publish step and any partially-constructed adapter is force-disposed immediately. ## Features - Strict-mode-safe async init with `AbortSignal` cancellation. - Synchronous unmount path that disposes `adapter`, then `transport`, then `buses` — each at most once. - Zod-validated options (`AudioProviderOptions`) — invalid input throws `ReactAudioError(REACT_AUDIO.INVALID_OPTIONS)` at construct time. - Auto-registers consumer-supplied plugin factories into the package registry. - Publishes `engineState` (`'pending' | 'ready' | 'error'`) for the `useEngineState` hook and any consumer that wants to render a loading state. ## Usage: Basic ```tsx import { AudioProvider } from "@suaveplan/react-audio"; function App() { return ( ); } ``` ## Usage: Advanced ```tsx import { AudioProvider } from "@suaveplan/react-audio"; function App() { return ( makeDelay() }, ], sampleRateHz: 30, }} > ); } ``` ## API Reference - `` — renders a context provider. - `AudioProviderProps` — `{ options?: AudioProviderOptions, children?: ReactNode }`. ## Implementation Notes The async init pipeline lives entirely inside `useEffect`'s async IIFE so React's render path stays synchronous. A `PendingInit` value carries the in-flight adapter, transport, and bus-registry references so the cleanup callback can dispose anything already constructed if the effect is torn down mid-init — this is the linchpin of the Strict Mode guarantee. The `AbortController` is also passed to `adapter.init({ signal })` so the engine package's own cancellable work paths short-circuit. State updates (`setState`, `setEngineState`, `setVersion`) are skipped when `cancelled` is true so a torn-down effect cannot mutate React state. The teardown path is unconditional and synchronous: every dispose is wrapped in nothing but a null check, no try/catch — disposing a class that hasn't fully initialised is the responsibility of the owning package's `dispose()` to handle.