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-streaminto 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
- NEW package shell
@suaveplan/react-audio-streamatpackages/ui/react/react-audio-stream/withpackage.json,tsconfig.lib.json,vite.config.ts,vitest.config.ts,README.md, rootsrc/index.ts, all required subpath exports per the original spec's Requirement 9 (gated to those whose targets exist after this chunk). - Error codes —
src/error-codes/declaresREACT_AUDIO_STREAM.{NO_PROVIDER, INVALID_STATE, SIGNALLING_FAILED, PEER_NOT_FOUND, MEDIA_PERMISSION_DENIED, RECONNECT_EXHAUSTED, INVALID_OPTIONS}viadefineCodesplusReactAudioStreamError extends SuaveplanError. - FSM —
src/session/session-fsm/builds the 7-state FSM (idle→connecting→connected→joining→joined→disconnecting→disconnected) using@suaveplan/fsm. Exposestransition(method), emits'state-changed'events. - 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. - InterruptionClassifier —
src/session/interruption-classifier/deterministic rule mapping tonetwork | media-permission | signalling | peer | unknown. - StreamSourcePlugin —
src/session/stream-source-plugin/implementsAudioFxPluginfrom@suaveplan/audio-fx-plugin-base;setSourceStream(MediaStream); consumed byStreamSessionto materialise peer streams ontopeer:<participantId>tracks. - Telemetry —
src/telemetry/registers 6 OTel instruments per the original Requirement 7 (peer connect/disconnect counters, active-sessions gauge, reconnect counters, RTT histogram). - Purity test —
tests/purity.test.tsasserts the builtdist/references noAudioContext/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,StreamSourcePluginfrom here. - No
dist/archives until all four chunks merge. Spec fold + change archival happens after chunk D lands.