Skip to content

feat(client): integrate OpenAPI generated client - #2347

Draft
jdimovska wants to merge 8 commits into
mainfrom
openapi-migration
Draft

feat(client): integrate OpenAPI generated client #2347
jdimovska wants to merge 8 commits into
mainfrom
openapi-migration

Conversation

@jdimovska

@jdimovska jdimovska commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

💡 Overview

📝 Implementation notes

🎫 Ticket: https://linear.app/stream/issue/XYZ-123

📑 Docs: https://github.com/GetStream/docs-content/pull/

Summary by CodeRabbit

  • New Features

    • Updated call, device, statistics, reaction, and event handling to use the latest Video API.
    • Added compatibility exports to help existing integrations continue working with renamed types and enums.
    • Improved WebSocket connectivity with the updated API endpoint and authentication details.
  • Bug Fixes

    • Updated client event reporting and guest-user requests to use current API routes.
    • Improved response and rate-limit metadata handling.
    • Preserved legacy reaction and configuration type compatibility.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 33ecc39a-ce63-4150-b2b0-bbcc83c1b10d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The client migrates coordinator HTTP and WebSocket interactions to generated v2 APIs, adds compatibility exports for renamed models and enums, updates call and device operations, and adjusts SDK consumers and tests for the new request paths and types.

Changes

Coordinator v2 migration

Layer / File(s) Summary
Generated contracts and HTTP transport
packages/client/generate-openapi.sh, packages/client/src/compat.ts, packages/client/src/coordinator/connection/*
Generated clients, compatibility exports, response metadata, base URLs, and HTTP handling are updated for coordinator v2.
Call operation migration
packages/client/src/Call.ts
Call lifecycle, permissions, media controls, recordings, statistics, feedback, and events use generated API methods.
Client API wiring and request tests
packages/client/src/StreamVideoClient.ts, packages/client/src/__tests__/StreamVideoClient.api.test.ts
Client queries, guest creation, statistics, edges, and device operations use generated APIs and v2 request assertions.
WebSocket events and client state
packages/client/src/coordinator/connection/connection.ts, packages/client/src/coordinator/connection/types.ts, packages/client/src/store/CallState.ts
WebSocket authentication, v2 connection paths, event decoding, and event-driven state typing are updated.
Consumer type and enum migration
packages/client/src/devices/*, packages/client/src/types.ts, packages/react-sdk/*, packages/react-native-sdk/*, sample-apps/react-native/*
Consumers use renamed generated types and literal values for reactions, devices, permissions, noise cancellation, recording modes, and RTC configuration.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StreamVideoClient
  participant VideoApi
  participant ApiClient
  participant StreamClient
  StreamVideoClient->>VideoApi: queryCalls or listDevices
  VideoApi->>ApiClient: sendRequest
  ApiClient->>StreamClient: doAxiosRequest(v2 endpoint)
  StreamClient-->>ApiClient: AxiosResponse
  ApiClient-->>VideoApi: response body and metadata
  VideoApi-->>StreamVideoClient: typed result
Loading

Possibly related PRs

Suggested reviewers: oliverlaz, santhoshvai

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only repeats the template and leaves the Overview and Implementation notes empty, so it lacks the required project details. Fill in Overview and Implementation notes with a concise summary of the client/OpenAPI integration, and keep the Ticket and Docs links populated.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change: integrating an OpenAPI-generated client into the client package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch openapi-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jdimovska
jdimovska marked this pull request as draft July 27, 2026 21:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
packages/client/src/compat.ts (1)

27-449: 📐 Maintainability & Code Quality | 🔵 Trivial

Hand-duplicated enum values risk silent drift from the generated spec.

These enum objects (e.g. the ~34-entry language lists repeated across StartClosedCaptionsRequestLanguageEnum, StartTranscriptionRequestLanguageEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsResponseLanguageEnum) are now manually maintained duplicates of what the generator used to produce. Since generate-openapi.sh regenerates src/gen/coordinator from the spec but never touches compat.ts, a future backend enum change (new language, new recording mode, etc.) can silently desync this compatibility layer from the real contract.

Consider a lightweight guard — e.g. a unit test that asserts each compat enum's value set is a subset of/matches the corresponding inline literal union types used in the generated models — so drift fails CI instead of failing silently at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client/src/compat.ts` around lines 27 - 449, Add a unit test
covering the compatibility enum objects in compat.ts, including the repeated
language enums such as StartClosedCaptionsRequestLanguageEnum and
TranscriptionSettingsResponseLanguageEnum, and compare each value set with its
corresponding generated model literal union. Fail the test when values are
missing or extra so regenerated coordinator specs cannot silently drift from the
compatibility layer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/client/src/Call.ts`:
- Around line 957-961: Remove the debug console.log call from getOrCreate after
the API response is retrieved; leave the existing setup, request, and response
flow unchanged.

In `@packages/client/src/coordinator/connection/api-client.ts`:
- Around line 77-100: Update queryParamsStringify so arrays containing objects
are serialized as structured JSON rather than via value.join(','). Preserve the
existing comma-joined serialization for primitive arrays, while ensuring
object-containing arrays produce usable encoded JSON output.

In `@packages/client/src/coordinator/connection/client.ts`:
- Line 125: Update Call.getCallStatsMap to preserve the /video path segment when
constructing its call_stats URL, matching the new baseURL behavior and the
existing Call.streamClientBasePath convention. Ensure the request still targets
/video/call_stats/${type}/${id}/${callSessionId}/map, and inspect other direct
streamClient.baseURL concatenations for the same missing segment.

In `@packages/client/src/store/CallState.ts`:
- Around line 343-344: Add the missing call.user_muted property to the
eventHandlers initializer in CallState, using an explicit undefined handler or
the intended state-update callback so it satisfies the required WSEvent mapped
type. Preserve all existing event handlers.

In `@packages/react-sdk/src/embedded/hooks/useNoiseCancellationLoader.ts`:
- Around line 20-22: Update useNoiseCancellationLoader to obtain call settings
via useCallStateHooks().useCallSettings() from `@stream-io/video-react-bindings`,
then derive isNoiseCancellationEnabled from that reactive value. Remove the
direct call?.state.settings access while preserving the existing
noise-cancellation mode check and loader behavior.

---

Nitpick comments:
In `@packages/client/src/compat.ts`:
- Around line 27-449: Add a unit test covering the compatibility enum objects in
compat.ts, including the repeated language enums such as
StartClosedCaptionsRequestLanguageEnum and
TranscriptionSettingsResponseLanguageEnum, and compare each value set with its
corresponding generated model literal union. Fail the test when values are
missing or extra so regenerated coordinator specs cannot silently drift from the
compatibility layer.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 356568de-0880-458e-bb8c-a18eadd5180b

📥 Commits

Reviewing files that changed from the base of the PR and between 4fe5c40 and 82b70c8.

⛔ Files ignored due to path filters (7)
  • packages/client/src/gen/coordinator/index.ts is excluded by !**/gen/**
  • packages/client/src/gen/coordinator/model-decoders/decoders.ts is excluded by !**/gen/**
  • packages/client/src/gen/coordinator/model-decoders/event-decoder-mapping.ts is excluded by !**/gen/**
  • packages/client/src/gen/coordinator/models/index.ts is excluded by !**/gen/**
  • packages/client/src/gen/coordinator/video/CallApi.ts is excluded by !**/gen/**
  • packages/client/src/gen/coordinator/video/VideoApi.ts is excluded by !**/gen/**
  • packages/client/src/gen/gen-imports.ts is excluded by !**/gen/**
📒 Files selected for processing (22)
  • packages/client/generate-openapi.sh
  • packages/client/index.ts
  • packages/client/src/Call.ts
  • packages/client/src/StreamVideoClient.ts
  • packages/client/src/__tests__/StreamVideoClient.api.test.ts
  • packages/client/src/compat.ts
  • packages/client/src/coordinator/connection/api-client.ts
  • packages/client/src/coordinator/connection/client.ts
  • packages/client/src/coordinator/connection/connection.ts
  • packages/client/src/coordinator/connection/types.ts
  • packages/client/src/devices/MicrophoneManager.ts
  • packages/client/src/devices/SpeakerManager.ts
  • packages/client/src/reporting/ClientEventReporter.ts
  • packages/client/src/rtc/helpers/rtcConfiguration.ts
  • packages/client/src/store/CallState.ts
  • packages/client/src/types.ts
  • packages/react-native-sdk/src/components/Call/CallControls/internal/ReactionsPicker.tsx
  • packages/react-native-sdk/src/providers/NoiseCancellation/NoiseCancellationProvider.tsx
  • packages/react-sdk/src/components/NoiseCancellation/NoiseCancellationProvider.tsx
  • packages/react-sdk/src/core/components/ParticipantView/ParticipantActionsContextMenu.tsx
  • packages/react-sdk/src/embedded/hooks/useNoiseCancellationLoader.ts
  • sample-apps/react-native/dogfood/src/components/CallControls/MoreActionsButton/BottomControlsDrawer.tsx

Comment thread packages/client/src/Call.ts Outdated
Comment on lines +77 to +100
const queryParamsStringify = (params: Record<string, unknown>): string => {
const queryParams: string[] = [];

for (const key in params) {
const value = params[key];
if (value == null) continue;

if (Array.isArray(value)) {
queryParams.push(`${key}=${encodeURIComponent(value.join(','))}`);
} else if (value instanceof Date) {
queryParams.push(`${key}=${encodeURIComponent(value.toISOString())}`);
} else if (typeof value === 'object') {
queryParams.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`);
} else if (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean'
) {
queryParams.push(`${key}=${encodeURIComponent(value)}`);
}
}

return queryParams.join('&');
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Array-of-objects query params get silently corrupted.

Array.isArray(value) is checked before the generic object branch, so an array whose elements are themselves objects falls into value.join(','), producing "[object Object],[object Object]" rather than a usable serialization. No current call site in this cohort appears to hit this, but it's a foot-gun for any future/edge-case usage of this shared serializer.

🛠️ Suggested fix
     if (Array.isArray(value)) {
-      queryParams.push(`${key}=${encodeURIComponent(value.join(','))}`);
+      const serialized = value.every((v) => v == null || typeof v !== 'object')
+        ? value.join(',')
+        : JSON.stringify(value);
+      queryParams.push(`${key}=${encodeURIComponent(serialized)}`);
     } else if (value instanceof Date) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const queryParamsStringify = (params: Record<string, unknown>): string => {
const queryParams: string[] = [];
for (const key in params) {
const value = params[key];
if (value == null) continue;
if (Array.isArray(value)) {
queryParams.push(`${key}=${encodeURIComponent(value.join(','))}`);
} else if (value instanceof Date) {
queryParams.push(`${key}=${encodeURIComponent(value.toISOString())}`);
} else if (typeof value === 'object') {
queryParams.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`);
} else if (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean'
) {
queryParams.push(`${key}=${encodeURIComponent(value)}`);
}
}
return queryParams.join('&');
};
const queryParamsStringify = (params: Record<string, unknown>): string => {
const queryParams: string[] = [];
for (const key in params) {
const value = params[key];
if (value == null) continue;
if (Array.isArray(value)) {
const serialized = value.every((v) => v == null || typeof v !== 'object')
? value.join(',')
: JSON.stringify(value);
queryParams.push(`${key}=${encodeURIComponent(serialized)}`);
} else if (value instanceof Date) {
queryParams.push(`${key}=${encodeURIComponent(value.toISOString())}`);
} else if (typeof value === 'object') {
queryParams.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`);
} else if (
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'boolean'
) {
queryParams.push(`${key}=${encodeURIComponent(value)}`);
}
}
return queryParams.join('&');
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client/src/coordinator/connection/api-client.ts` around lines 77 -
100, Update queryParamsStringify so arrays containing objects are serialized as
structured JSON rather than via value.join(','). Preserve the existing
comma-joined serialization for primitive arrays, while ensuring
object-containing arrays produce usable encoded JSON output.

this.setBaseURL(
this.options.baseURL || 'https://video.stream-io-api.com/video',
);
this.setBaseURL(this.options.baseURL || 'https://video.stream-io-api.com');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

Base URL change breaks Call.getCallStatsMap, which manually reconstructs the URL.

Dropping the /video suffix from the default base URL is compensated for in connectGuestUser (now posts to /video/guest) and in Call.streamClientBasePath (now /video/call/${type}/${id}), but Call.getCallStatsMap was missed:

// packages/client/src/Call.ts (unchanged in this diff)
return this.streamClient.get<QueryCallStatsMapResponse>(
  `${this.streamClient.baseURL}/call_stats/${this.type}/${this.id}/${callSessionId}/map`,
  params,
);

With the old base URL (.../video), this resolved to .../video/call_stats/.... With the new default (no /video suffix), it now resolves to .../call_stats/..., silently dropping the /video segment and almost certainly 404ing.

🐛 Suggested fix (in Call.ts)
     return this.streamClient.get<QueryCallStatsMapResponse>(
-      `${this.streamClient.baseURL}/call_stats/${this.type}/${this.id}/${callSessionId}/map`,
+      `${this.streamClient.baseURL}/video/call_stats/${this.type}/${this.id}/${callSessionId}/map`,
       params,
     );
🔍 Verification script — check for other direct `baseURL` string concatenations
#!/bin/bash
rg -n 'streamClient\.baseURL' packages/client/src
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client/src/coordinator/connection/client.ts` at line 125, Update
Call.getCallStatsMap to preserve the /video path segment when constructing its
call_stats URL, matching the new baseURL behavior and the existing
Call.streamClientBasePath convention. Ensure the request still targets
/video/call_stats/${type}/${id}/${callSessionId}/map, and inspect other direct
streamClient.baseURL concatenations for the same missing segment.

Comment on lines +343 to +344
[EventType in WSEvent['type']]:
| ((event: Extract<WSEvent, { type: EventType }>) => void)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Add the missing call.user_muted handler key.

eventHandlers is now a required mapped type over WSEvent['type'], and generated WSEvent includes call.user_muted. The initializer has no corresponding property, so TypeScript reports a missing required key. Add an explicit undefined handler or implement the intended state update.

Proposed fix
       'call.user_feedback_submitted': undefined,
+      'call.user_muted': undefined,
       'connection.error': undefined,

Also applies to: 474-484

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client/src/store/CallState.ts` around lines 343 - 344, Add the
missing call.user_muted property to the eventHandlers initializer in CallState,
using an explicit undefined handler or the intended state-update callback so it
satisfies the required WSEvent mapped type. Preserve all existing event
handlers.

Comment thread packages/react-sdk/src/embedded/hooks/useNoiseCancellationLoader.ts
@github-actions

Copy link
Copy Markdown

Bundle size

Built package output. Sizes in KB; delta vs main@4fe5c40.

Package Unminified Minified Δ min vs main
@stream-io/video-client 770.6 KB 277.0 KB +12.8 KB (+4.8%)
@stream-io/video-react-sdk 183.9 KB 90.4 KB -51 B (-0.1%)
↳ install total (+ client + react-bindings) 985.1 KB 376.6 KB +12.7 KB (+3.5%)
@stream-io/video-react-sdk (embedded) 194.4 KB 94.6 KB -42 B (-0.0%)
@stream-io/video-react-native-sdk 402.4 KB 192.6 KB -39 B (-0.0%)
↳ install total (+ client + react-bindings) 1203.6 KB 478.8 KB +12.7 KB (+2.7%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant