first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
# stream-provider
## Purpose
`<StreamProvider>` is the singleton React surface that owns the live `StreamSession` for
a tree. It calls the caller-supplied `sessionFactory` exactly once per provider instance,
subscribes to the seven session event channels (`state-changed`, `interruption`,
`peers-changed`, `mixer-changed`, `levels-changed`, `recording-changed`,
`permission-changed`), and increments a render-bump counter on every tick so descendant
hooks observe a fresh snapshot of session state.
The factory pattern keeps `@suaveplan/react-audio-stream` transport-agnostic: the
consumer decides whether the underlying transport is WebRTC, WebSocket, Trystero, or a
test fake, and the provider never imports any transport directly. Cleanup on unmount
calls `session.disconnect()` so the audio engine + socket are torn down deterministically.
## Features
- StrictMode-safe singleton via `useRef`-guarded lazy construction.
- Caller-injected `sessionFactory` — zero transport coupling at provider tier.
- Render-bump counter fans seven event channels into one re-render path.
- Cleanup-on-unmount disconnects the session and detaches every listener.
- Memoised context value — only the `version` field changes per tick.
## Usage: Basic
```tsx
import { StreamProvider } from "@suaveplan/react-audio-stream/provider";
import { createStreamSession } from "./my-session-factory";
export function App({ children }: { children: React.ReactNode }) {
return (
<StreamProvider sessionFactory={() => createStreamSession({ transport: "webrtc" })}>
{children}
</StreamProvider>
);
}
```
## Usage: Advanced
```tsx
import { StreamProvider } from "@suaveplan/react-audio-stream/provider";
import { useMemo } from "react";
export function ScopedRoom({ roomId, children }: { roomId: string; children: React.ReactNode }) {
const factory = useMemo(
() => () => createStreamSession({ transport: "trystero", initialRoomId: roomId }),
[roomId]
);
return <StreamProvider sessionFactory={factory}>{children}</StreamProvider>;
}
```
Keying the provider on `roomId` (`<StreamProvider key={roomId} …>`) forces a fresh
session when the room changes, because the singleton is per-instance.
## API Reference
- `StreamProviderProps` — `{ sessionFactory: StreamSessionFactory; children?: ReactNode }`
- `StreamProvider(props)` — renders a `StreamReactContext.Provider` with `{ session, version }`.
## Implementation Notes
The seven event subscriptions all funnel into a single `setVersion((v) => v + 1)` call,
which collapses bursts into a single React render pass thanks to automatic batching. The
disconnect call on unmount is wrapped in `Promise.resolve` so the same code path handles
both sync and async session implementations, and the rejection branch swallows errors
(any failure already surfaced as an `interruption` event before the listener detach).