Files
2026-05-27 23:29:53 +01:00

4.0 KiB

@suaveplan/react-audio-stream — session core (chunk A)

  • Target path: packages/ui/react/react-audio-stream/
  • Tier: browser/react
  • Date: 2026-05-23
  • Status: PROPOSED — splits enterprise-react-audio-stream into 4 ship-sized changes; this is chunk A (foundation).

Why

The original enterprise-react-audio-stream change folder is ~80-120 files at the project quality bar — too large to ship in a single agent session at 100/100/100/100. Splitting into four disjoint-subtree chunks (session-core, transports, hooks-components, transport-share) lets each land independently while keeping the public surface contract preserved.

This chunk ships the session foundation: error codes, FSM lifecycle, source-plugin bridge, interruption classification, OTel instruments, and the package's structural shell (package.json with subpath exports, vitest/vite/tsconfig configs, root barrel). Every downstream chunk imports from here.

What changes

  1. NEW package shell @suaveplan/react-audio-stream at packages/ui/react/react-audio-stream/ with package.json, tsconfig.lib.json, vite.config.ts, vitest.config.ts, README.md, root src/index.ts, all required subpath exports per the original spec's Requirement 9 (gated to those whose targets exist after this chunk).
  2. Error codes — src/error-codes/ declares REACT_AUDIO_STREAM.{NO_PROVIDER, INVALID_STATE, SIGNALLING_FAILED, PEER_NOT_FOUND, MEDIA_PERMISSION_DENIED, RECONNECT_EXHAUSTED, INVALID_OPTIONS} via defineCodes plus ReactAudioStreamError extends SuaveplanError.
  3. FSM — src/session/session-fsm/ builds the 7-state FSM (idle → connecting → connected → joining → joined → disconnecting → disconnected) using @suaveplan/fsm. Exposes transition(method), emits 'state-changed' events.
  4. StreamSession — src/session/stream-session/ is the public class wrapping the FSM. connect, join, leave, disconnect; emits 'state-changed', 'interruption', 'peer-stream-added', 'peer-stream-removed'. Transport adapter is injected via constructor — concrete adapters land in chunk B.
  5. InterruptionClassifier — src/session/interruption-classifier/ deterministic rule mapping to network | media-permission | signalling | peer | unknown.
  6. StreamSourcePlugin — src/session/stream-source-plugin/ implements AudioFxPlugin from @suaveplan/audio-fx-plugin-base; setSourceStream(MediaStream); consumed by StreamSession to materialise peer streams onto peer:<participantId> tracks.
  7. Telemetry — src/telemetry/ registers 6 OTel instruments per the original Requirement 7 (peer connect/disconnect counters, active-sessions gauge, reconnect counters, RTT histogram).
  8. Purity test — tests/purity.test.ts asserts the built dist/ references no AudioContext/OfflineAudioContext/AudioNode/AudioWorklet.

Requirements landed by this chunk

From the original spec at openspec/changes/enterprise-react-audio-stream/specs/react-audio-stream/spec.md:

  • Stream-tier purity (full)
  • StreamSession FSM lifecycle (full)
  • Peer streams materialise as source plugins (full)
  • Interruption classification (full)
  • OpenTelemetry instrumentation (full)
  • Structured error codes (full)
  • Subpath exports — partial: only the subpaths whose targets exist after this chunk (., ./session, ./error-codes); transports/hooks/components subpaths come in their chunks.

Deferred to follow-up chunks: Auto-reconnect (chunk D), per-peer stream mixer (chunk C), transport-share mode (chunk D), WebRTC/WebSocket/Trystero transports (chunk B), 7 hooks + 4 components + Provider (chunk C), bundle-size test (chunk B).

Impact

  • New package shell with the FSM foundation. ~25 files (src + tests + docs + configs).
  • Unblocks chunks B, C, D — each imports StreamSession, ReactAudioStreamError, InterruptionClassifier, StreamSourcePlugin from here.
  • No dist/ archives until all four chunks merge. Spec fold + change archival happens after chunk D lands.