The Problem

Developers need a turnkey way to embed real‑time video, audio rooms, and live‑streaming into web, React, and React‑Native apps while handling signaling, media negotiation, and device management. Building that stack from scratch requires deep WebRTC knowledge, cross‑platform glue code, and a reliable backend.

What This Does

The repo ships a family of SDKs that abstract those concerns:

  • packages/client supplies the low‑level JavaScript client (src/StreamVideoClient.ts, src/Call.ts) that talks to Stream’s SFU, manages peer connections, and exposes a typed API.
  • packages/react-bindings and packages/react-sdk wrap the client in React hooks (useCallStateHooks, useCall, useStreamVideoClient) and UI components (src/components/index.tsx).
  • packages/react-native-sdk mirrors the same hooks for React‑Native, plus native modules for audio‑device handling.

All SDKs share common utilities (packages/client/src/helpers/*) and a generated protobuf model (packages/client/src/gen/video/sfu/models/models.ts).

How It Is Wired

Execution begins in the React entry points:

  1. packages/react-bindings/src/contexts/StreamCallContext.tsx creates StreamCallProvider. Inside it calls useCallStateHooks from packages/react-bindings/src/hooks/index.ts.
  2. useCallStateHooks (the most‑called function – 29 distinct callers) pulls in useCall from StreamCallProvider and ultimately creates a Call instance via packages/client/src/Call.ts.
  3. Call.ts imports the hub module packages/client/src/gen/video/sfu/models/models.ts (68 inbound imports) and wires up the WebRTC stack (rtc/Publisher.ts, rtc/Subscriber.ts).
  4. Media tracks are created through createAudioStreamForDevice / createVideoStreamForDevice → createTrack (both called from two places).
  5. Event flow runs through the internal call graph: useCallStateHooks → useCall → Call → rtc/Dispatcher.ts → rtc/Publisher.ts / rtc/Subscriber.ts.

The most central hub (models.ts) holds generated types used across 68 modules; any change there propagates widely. A notable import cycle links packages/client/src/store/index.ts, packages/client/src/Call.ts, and packages/react-sdk/src/components/index.ts, increasing the blast radius for refactors.

Outside the repo the only observed side‑effect is a single file read/write (packages/react-native-sdk/expo-config-plugin/fixtures/index.ts). No database or external service calls are present in the static analysis.

How To Use It

# Clone the repo
git clone https://github.com/moses-y/stream-video-js
cd stream-video-js

# Install dependencies (yarn is the declared package manager)
yarn install

# Build the packages (Nx workspace)
yarn nx run-many --target=build --all

# Run a sample app (e.g., React live‑stream)
cd sample-apps/react/livestream-app
yarn start   # uses Next.js / Vite as defined in package.json scripts

Configuration for the client lives in environment variables referenced in packages/client/.env-example (API key, secret, and user token). The sample apps read those values at runtime; replace the placeholder file with real credentials before starting.

Real‑World Use

A typical integration in a React app:

import { StreamVideoProvider, useCall } from '@stream-io/react-sdk';

function VideoRoom() {
  const { call } = useCall();               // pulls Call instance
  useEffect(() => call.join(), []);        // joins a room
  return <VideoComponent call={call} />;   // UI from react-sdk
}

The provider injects the client, the hook creates the Call object, and the UI component renders remote tracks supplied by the underlying rtc layer.

Code Health & Issues

  • Critical – Private key committed (sample-apps/react-native/dogfood/android/app/debug.keystore). Must rotate and purge from history.
  • High – GitHub Actions not pinned to commit SHA (.github/workflows/*). Replace @v3 tags with full SHAs.
  • Medium – GITHUB_TOKEN permissions undefined (.github/workflows/deploy-react-sample-apps.yml). Add least‑privilege scopes.
  • Medium – No automated dependency updater. Add dependabot.yml.
  • Medium – Docker base images unpinned (Dockerfile). Use digest tags.
  • Medium – No vulnerability scan in CI. Add dependency-review-action or osv-scanner.
  • Medium – Large binary assets (packages/video-filters-web/mediapipe/models/*.tflite) inflate repo size; move to Git LFS or external storage.
  • Medium – Checkout step retains push token (persist-credentials). Set persist-credentials: false.
  • Low – Workflow jobs lack timeout-minutes. Add reasonable limits.

Static analysis also flagged:

  • High/cognitive_load – Oversized files (Call.ts, models.ts, index.ts in coordinator) > 1 k lines; consider splitting by responsibility.
  • High/soundness – 41 modules involved in import cycles; break cycles by extracting shared types or inverting dependencies.
  • High/clarity – Hub module (models.ts) highly connected; keep stable, move volatile logic elsewhere.
  • Medium/cognitive_load – Functions with dense branching (src/utils/StreamVideoRN/types.ts, src/utils/push/libs/callingx.ts, src/rtc/helpers/sdp.ts); refactor to strategy tables.

The Bottom Line

The repo delivers a well‑structured, multi‑platform video SDK with comprehensive hooks and UI components, but the core client contains large, highly coupled modules and several import cycles that raise maintenance risk. Security hygiene needs immediate attention (private key, action pinning, token handling). Suitable for teams comfortable with TypeScript and willing to invest in refactoring the hub modules for long‑term stability.