# `hooks/use-provider-state` _(no submodules)_ ## Purpose Internal helpers shared across every public hook. They centralise the two structured-error throws every engine-dependent hook must perform: `REACT_AUDIO.NO_PROVIDER` when the consumer renders outside an `` ancestor, and `REACT_AUDIO.PROVIDER_PENDING` when the engine has not yet finished its async init. Keeping the throw logic in one file means there is exactly one place to audit the error contract. ## Features - `useProviderStateOrThrow()` — returns the resolved `ProviderState` or throws. - `useAudioContextOrThrow()` — returns the raw `AudioContextValue` (without the pending check) for hooks like `useEngineState` that need to *report* the lifecycle phase rather than throw on it. ## Usage: Basic ```ts import { useProviderStateOrThrow } from "@suaveplan/react-audio"; function MyHook() { const state = useProviderStateOrThrow(); return state.transport; } ``` ## Usage: Advanced ```ts import { useAudioContextOrThrow } from "@suaveplan/react-audio"; function useReadyOrLoading(): "ready" | "loading" { const ctx = useAudioContextOrThrow(); return ctx.engineState === "ready" ? "ready" : "loading"; } ``` ## API Reference - `useProviderStateOrThrow(): ProviderState` — throws `REACT_AUDIO.NO_PROVIDER` outside provider; throws `REACT_AUDIO.PROVIDER_PENDING` while engine init is pending. - `useAudioContextOrThrow(): AudioContextValue` — throws `REACT_AUDIO.NO_PROVIDER` outside provider. ## Implementation Notes `useContext` returns `null` as the "no provider" sentinel because the context's default value is `null`. The two helpers use a single discriminator check (`ctx === null`) for that path so the throw site is canonical. `useProviderStateOrThrow` additionally checks for `ctx.state === null` (the async init window) and throws `PROVIDER_PENDING` so engine-dependent hooks fail fast — consumers typically gate on `useEngineState() === 'ready'` before rendering those hooks' subtrees. The split into two helpers exists so `useEngineState` itself can read the phase without throwing on it — otherwise the consumer would have no way to discover "we're still initialising" without crashing the component tree. Both helpers register exactly one React hook (`useContext`) so any downstream hook can register additional `useCallback` / `useSyncExternalStore` calls unconditionally and stay compliant with the Rules of Hooks.