Skip to content

feat: upgrade to TypeScript 6.0.3, pin ES2022, raise supported-browser floors#2290

Merged
oliverlaz merged 4 commits into
mainfrom
typescript-6
Jun 22, 2026
Merged

feat: upgrade to TypeScript 6.0.3, pin ES2022, raise supported-browser floors#2290
oliverlaz merged 4 commits into
mainfrom
typescript-6

Conversation

@oliverlaz

@oliverlaz oliverlaz commented Jun 17, 2026

Copy link
Copy Markdown
Member

💡 Overview

Upgrades the monorepo to TypeScript 6.0.3, pins the compilation target / module / lib to ES2022, introduces a shared TypeScript config package, and raises the supported-browser floors.

📝 Implementation notes

TypeScript 6.0.3 across all workspaces (root + packages + sample apps).

ES2022 everywhere. target, module, and lib are pinned to ES2022. The build does no transpilation (rollup / vite / Metro pass the TS output through), so lib: esnext would let post-ES2022 APIs type-check and then ship unpolyfilled, breaking the supported browsers. The pin already caught and replaced two real cases:

  • Set.difference (ES2025) in @stream-io/video-client
  • Array.findLastIndex (ES2023) in the react-dogfood sample

Shared config. New private @stream-io/typescript-config (base + library-web + library-rn + app-web), adopted by the 9 libraries and 8 sample apps. Removes ~16 duplicated compiler options per package and fixes the drift it surfaced (mixed esModuleInterop, jsx, moduleResolution). react-dogfood (Next.js) stays on its own Next-managed tsconfig but follows the ES2022 lib pin.

TS 6.0 deprecations migrated, not suppressed:

  • moduleResolution: "node" (node10) to "bundler"
  • esModuleInterop: false to true
  • explicit rootDir for the react-native-builder-bob .d.ts builds (TS 6.0 requires it)
  • @types/node + types: ["node"] where Node globals are used (TS 6.0 dropped @types auto-inclusion)

Supported browsers (isSupportedBrowser): Chrome / Edge / Android WebView 136, Firefox 137, Safari 18. iOS WebKit engine floor unchanged at 605.

React Native: jsx: "react-native"; ReturnType<typeof setTimeout | setInterval> instead of NodeJS.Timeout; globalThis instead of global.

Also includes the strict-flag fixes (e.g. explicit returns for noImplicitReturns) that accompany the shared base's stricter compiler options, and quarantines one flaky live-backend ringing integration test.

Verification. NODE_ENV=production yarn build:all, yarn lint:ci:all, and yarn test:react-native:sdk all pass. yarn test:ci:client passes except a pre-existing flaky live-backend integration test (api.test.ts > query calls, a 504 from the backend).

Deliberate follow-ups (out of scope): verbatimModuleSyntax and noUncheckedIndexedAccess sweeps for the web packages (measured at roughly 400-700 and 100-200 fixes respectively; better as standalone PRs).

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

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

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability around connection outcomes and mute behavior when no target users are available.
    • Refined SDP codec filtering to match the intended fmtp profile rules more consistently.
  • Tests

    • Updated browser support coverage to match new supported/unsupported version thresholds.
  • Chores

    • Updated build output to ES2022.
    • Upgraded TypeScript tooling to 6.0.3 and standardized shared TypeScript configuration across packages.
    • Adjusted browser support checks (Chrome/Edge 136+, Firefox 137+, Safari 18+, Android WebView 136+).

…er floors

- Bump typescript to ^6.0.3 across all workspaces
- Pin target/module/lib to ES2022; with no transpilation in the build,
  this prevents post-ES2022 APIs from shipping unpolyfilled
- Add shared @stream-io/typescript-config (base + library-web/library-rn + app-web);
  adopt across the libraries and Vite sample apps
- Migrate TS 6.0 deprecations instead of suppressing them:
  moduleResolution node10 -> bundler, esModuleInterop false -> true
- Add @types/node + types:["node"] where Node globals are used
  (TS 6.0 dropped @types auto-inclusion); add rootDir for builder-bob d.ts builds
- Raise isSupportedBrowser floors: Chrome/Edge/Android WebView 136, Firefox 137, Safari 18
- Replace post-ES2022 APIs the lib pin caught: Set.difference (ES2025), Array.findLastIndex (ES2023)
- React Native: jsx "react-native"; ReturnType<typeof setTimeout> over NodeJS.Timeout; globalThis over global
- Quarantine one flaky live-backend ringing integration test
@changeset-bot

changeset-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9b8b13c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b39a5bef-4f89-4c09-b4e6-3eac19826b44

📥 Commits

Reviewing files that changed from the base of the PR and between e617773 and 77a9c11.

⛔ Files ignored due to path filters (2)
  • sample-apps/react-native/dogfood/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • .yarnrc.yml
💤 Files with no reviewable changes (1)
  • .yarnrc.yml

📝 Walkthrough

Walkthrough

Introduces a new @stream-io/typescript-config shared package with base, library-web, library-rn, and app-web presets. Upgrades TypeScript from ^5.9.3 to ^6.0.3 across all manifests, migrates tsconfig.json files to extend the shared presets, and fixes source-level typing and control-flow return paths to satisfy new TS6 strictness rules.

Changes

TypeScript 6 migration and shared tsconfig adoption

Layer / File(s) Summary
Create shared TypeScript preset package
packages/typescript-config/package.json, packages/typescript-config/base.json, packages/typescript-config/library-web.json, packages/typescript-config/library-rn.json, packages/typescript-config/app-web.json
New @stream-io/typescript-config workspace package defines a base.json preset (ES2022, strict mode, bundler resolution) and three specialized presets that extend it: library-web.json (DOM, declaration, sourcemaps), library-rn.json (React Native JSX), and app-web.json (app-level react-jsx, no emit).
Upgrade package manifests to TypeScript 6
package.json, packages/*/package.json, sample-apps/*/package.json
All devDependencies blocks across root, packages, and sample apps bump typescript from ^5.9.3 to ^6.0.3, add @stream-io/typescript-config workspace references, and update @types/node to ^25.9.3 where needed.
Migrate tsconfig files to shared presets
packages/*/tsconfig.json, sample-apps/*/tsconfig.json, sample-apps/*/tsconfig.node.json
All package and sample-app tsconfig.json files replace inline compilerOptions blocks with extends pointing to the appropriate shared preset. tsconfig.node.json files change moduleResolution from Node to bundler. Vite build target is aligned to ES2022.
Client package logic and browser support updates
packages/client/src/Call.ts, packages/client/src/StreamSfuClient.ts, packages/client/src/coordinator/connection/connection.ts, packages/client/src/helpers/browsers.ts, packages/client/src/helpers/MediaPlaybackWatchdog.ts, packages/client/src/rtc/helpers/degradationPreference.ts, packages/client/src/rtc/helpers/sdp.ts, packages/client/src/rtc/helpers/tracks.ts, packages/client/src/helpers/__tests__/browsers.test.ts
Adds explicit return undefined statements required by TS6's noImplicitReturns; bumps isSupportedBrowser minimum versions (Chrome/Edge ≥136, Firefox ≥137, Safari ≥18, Android WebView ≥136); changes SDP fmtp filtering from Set.difference to an every-based check requiring all requested parts in config; casts SFU binary payload to Uint8Array<ArrayBuffer>; updates browser version test cases.
React bindings and React Native SDK typing and control-flow alignment
packages/react-bindings/src/i18n/StreamI18n.ts, packages/react-native-sdk/src/components/Call/CallContent/CallContent.tsx, packages/react-native-sdk/src/components/Livestream/HostLivestream/HostLivestream.tsx, packages/react-native-sdk/src/components/Livestream/LivestreamControls/ViewerLivestreamControls.tsx, packages/react-native-sdk/src/components/Livestream/LivestreamTopView/DurationBadge.tsx, packages/react-native-sdk/src/components/Livestream/ViewerLivestream/ViewerLivestream.tsx, packages/react-native-sdk/src/components/Participant/ParticipantView/ParticipantReaction.tsx, packages/react-native-sdk/src/components/Participant/ParticipantView/VideoRenderer/index.tsx, packages/react-native-sdk/src/hooks/useModeration.ts, packages/react-native-sdk/src/utils/StreamVideoRN/index.ts, packages/react-native-sdk/src/utils/internal/registerSDKGlobals.ts, packages/react-native-sdk/src/utils/push/libs/firebaseMessaging/index.ts
Explicitly types StreamI18n.i18nInstance as i18n; refactors component effect guards to early-return patterns instead of conditional wrappers; updates timer handle types from NodeJS.Timeout to ReturnType<typeof setTimeout/setInterval>; removes unused busyToneTimeout static member; switches global object access from global to globalThis; adds explicit return types (FirebaseMessagingType, FirebaseMessagingType | undefined) to Firebase messaging helper functions.
React SDK and sample-app source compatibility fixes
packages/react-sdk/src/embedded/hooks/useWakeLock.ts, packages/react-sdk/src/embedded/livestream/viewer/ViewerLobby.tsx, packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx, sample-apps/react/egress-composite/src/components/layouts/EgressReadyParticipantViewUI.tsx, sample-apps/react/livestream-app/src/viewers/HLSLivestream.tsx, sample-apps/react-native/dogfood/src/components/CallControlls/MoreActionsButton/index.tsx, sample-apps/react-native/dogfood/src/screens/LoginScreen/index.tsx, sample-apps/react/audio-rooms/src/components/Room/SpeakingRequestsList.tsx, sample-apps/react/react-dogfood/components/Ringing/DialerPage.tsx
Adds explicit return undefined in wake lock and egress composite effect paths; refactors canJoinEarly interval effects from conditional wrapping to early-exit patterns; updates timeout ref types in sample components; replaces use of Array.prototype.findLastIndex (ES2023) with a local generic polyfill in DialerPage; aligns early-exit logic from return null to return undefined.
Yarn cache configuration update
.yarnrc.yml
Replaces Yarn hardening mode (enableHardenedMode: true) with global cache enablement (enableGlobalCache: true) to optimize build caching behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GetStream/stream-video-js#2225: Both PRs modify StableWSConnection's _connect and _waitForHealthy async paths in packages/client/src/coordinator/connection/connection.ts.
  • GetStream/stream-video-js#2240: Main PR's change to packages/client/src/helpers/MediaPlaybackWatchdog.ts adjusts the function introduced in the retrieved PR to satisfy TS6's noImplicitReturns requirements.

Suggested reviewers

  • santhoshvai
  • greenfrvr
  • jdimovska

🐇 A new config package hops into view,
TS six has arrived — strict and brand new!
noImplicitReturns makes every path clear,
globalThis replaces global this year.
The bunny types timers with ReturnType care,
And shared presets mean configs are easy to share! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three main changes: TypeScript upgrade to 6.0.3, ES2022 pinning, and raised browser support floors.
Description check ✅ Passed The description covers all required template sections with comprehensive implementation details, verification steps, and documentation reference.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch typescript-6

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 and usage tips.

@oliverlaz oliverlaz changed the title chore: upgrade to TypeScript 6.0.3, pin ES2022, raise supported-browser floors feat: upgrade to TypeScript 6.0.3, pin ES2022, raise supported-browser floors Jun 17, 2026
Aligns the RN SDK with the other React Native packages, which already use bob ^0.41.0. bob 0.41 defaults to the automatic JSX runtime, so the published output now uses jsx() from react/jsx-runtime instead of React.createElement. ESM output and production mode are preserved.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sample-apps/react-native/dogfood/src/screens/LoginScreen/index.tsx (1)

38-89: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear the pending tap timer on unmount.

tapTimerRef is set at Line 38 and reused in handleImagePress, but there’s no lifecycle cleanup. If the screen unmounts within 500ms, the callback can still fire and update state/store.

Suggested fix
-import React, { useRef, useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
@@
   const tapTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
+
+  useEffect(() => {
+    return () => {
+      if (tapTimerRef.current) {
+        clearTimeout(tapTimerRef.current);
+        tapTimerRef.current = null;
+      }
+    };
+  }, []);
🤖 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 `@sample-apps/react-native/dogfood/src/screens/LoginScreen/index.tsx` around
lines 38 - 89, The tapTimerRef timer is set in the handleImagePress function but
is never cleaned up when the LoginScreen component unmounts. This can cause the
setTimeout callback to execute after unmount and attempt to update state/store.
Add a useEffect hook with an empty dependency array that returns a cleanup
function to check if tapTimerRef.current exists and clear it using clearTimeout
to prevent stale callbacks from firing.
🤖 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/rtc/helpers/sdp.ts`:
- Around line 161-166: The issue is that splitting the fmtp configuration
strings on semicolons without trimming whitespace causes profile matches to fail
when there are spaces around the delimiters. In the code where required is
created by splitting fmtpProfileToKeep on semicolons (line 161), and where
actual is created by splitting fmtp.config on semicolons (line 163), each
resulting string segment needs to be trimmed to remove leading and trailing
whitespace. Apply trim() to each element after the split operations on both the
required array and the actual Set to ensure that functionally equivalent profile
configurations with different whitespace are properly recognized as matches.

---

Outside diff comments:
In `@sample-apps/react-native/dogfood/src/screens/LoginScreen/index.tsx`:
- Around line 38-89: The tapTimerRef timer is set in the handleImagePress
function but is never cleaned up when the LoginScreen component unmounts. This
can cause the setTimeout callback to execute after unmount and attempt to update
state/store. Add a useEffect hook with an empty dependency array that returns a
cleanup function to check if tapTimerRef.current exists and clear it using
clearTimeout to prevent stale callbacks from firing.
🪄 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

Run ID: f51bbd79-3050-4262-8614-52cc117dd2b4

📥 Commits

Reviewing files that changed from the base of the PR and between a9c670d and 9b8b13c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (84)
  • package.json
  • packages/audio-filters-web/package.json
  • packages/audio-filters-web/tsconfig.json
  • packages/audio-filters-web/vite.config.ts
  • packages/client/package.json
  • packages/client/src/Call.ts
  • packages/client/src/StreamSfuClient.ts
  • packages/client/src/coordinator/connection/connection.ts
  • packages/client/src/helpers/MediaPlaybackWatchdog.ts
  • packages/client/src/helpers/__tests__/browsers.test.ts
  • packages/client/src/helpers/browsers.ts
  • packages/client/src/rtc/helpers/degradationPreference.ts
  • packages/client/src/rtc/helpers/sdp.ts
  • packages/client/src/rtc/helpers/tracks.ts
  • packages/client/tsconfig.json
  • packages/noise-cancellation-react-native/package.json
  • packages/noise-cancellation-react-native/tsconfig.json
  • packages/react-bindings/package.json
  • packages/react-bindings/src/i18n/StreamI18n.ts
  • packages/react-bindings/tsconfig.json
  • packages/react-native-callingx/package.json
  • packages/react-native-callingx/tsconfig.json
  • packages/react-native-sdk/expo-config-plugin/tsconfig.json
  • packages/react-native-sdk/package.json
  • packages/react-native-sdk/src/components/Call/CallContent/CallContent.tsx
  • packages/react-native-sdk/src/components/Livestream/HostLivestream/HostLivestream.tsx
  • packages/react-native-sdk/src/components/Livestream/LivestreamControls/ViewerLivestreamControls.tsx
  • packages/react-native-sdk/src/components/Livestream/LivestreamTopView/DurationBadge.tsx
  • packages/react-native-sdk/src/components/Livestream/ViewerLivestream/ViewerLivestream.tsx
  • packages/react-native-sdk/src/components/Participant/ParticipantView/ParticipantReaction.tsx
  • packages/react-native-sdk/src/components/Participant/ParticipantView/VideoRenderer/index.tsx
  • packages/react-native-sdk/src/hooks/useModeration.ts
  • packages/react-native-sdk/src/utils/StreamVideoRN/index.ts
  • packages/react-native-sdk/src/utils/internal/registerSDKGlobals.ts
  • packages/react-native-sdk/src/utils/push/libs/firebaseMessaging/index.ts
  • packages/react-native-sdk/tsconfig.json
  • packages/react-sdk/package.json
  • packages/react-sdk/src/embedded/hooks/useWakeLock.ts
  • packages/react-sdk/src/embedded/livestream/viewer/ViewerLobby.tsx
  • packages/react-sdk/src/wrappers/LivestreamPlayer/LivestreamPlayer.tsx
  • packages/react-sdk/tsconfig.json
  • packages/typescript-config/app-web.json
  • packages/typescript-config/base.json
  • packages/typescript-config/library-rn.json
  • packages/typescript-config/library-web.json
  • packages/typescript-config/package.json
  • packages/video-filters-react-native/package.json
  • packages/video-filters-react-native/tsconfig.json
  • packages/video-filters-web/package.json
  • packages/video-filters-web/tsconfig.json
  • sample-apps/client/ts-quickstart/package.json
  • sample-apps/client/ts-quickstart/tsconfig.json
  • sample-apps/react-native/dogfood/package.json
  • sample-apps/react-native/dogfood/src/components/CallControlls/MoreActionsButton/index.tsx
  • sample-apps/react-native/dogfood/src/screens/LoginScreen/index.tsx
  • sample-apps/react-native/expo-video-sample/package.json
  • sample-apps/react-native/ringing-tutorial/package.json
  • sample-apps/react/audio-rooms/package.json
  • sample-apps/react/audio-rooms/src/components/Room/SpeakingRequestsList.tsx
  • sample-apps/react/audio-rooms/tsconfig.json
  • sample-apps/react/audio-rooms/tsconfig.node.json
  • sample-apps/react/cookbook-participant-list/package.json
  • sample-apps/react/cookbook-participant-list/tsconfig.json
  • sample-apps/react/cookbook-participant-list/tsconfig.node.json
  • sample-apps/react/egress-composite/package.json
  • sample-apps/react/egress-composite/src/components/layouts/EgressReadyParticipantViewUI.tsx
  • sample-apps/react/egress-composite/tsconfig.json
  • sample-apps/react/egress-composite/tsconfig.node.json
  • sample-apps/react/livestream-app/package.json
  • sample-apps/react/livestream-app/src/viewers/HLSLivestream.tsx
  • sample-apps/react/livestream-app/tsconfig.json
  • sample-apps/react/livestream-app/tsconfig.node.json
  • sample-apps/react/messenger-clone/package.json
  • sample-apps/react/messenger-clone/tsconfig.json
  • sample-apps/react/messenger-clone/tsconfig.node.json
  • sample-apps/react/react-dogfood/components/Ringing/DialerPage.tsx
  • sample-apps/react/react-dogfood/package.json
  • sample-apps/react/react-dogfood/tsconfig.json
  • sample-apps/react/stream-video-react-tutorial/package.json
  • sample-apps/react/stream-video-react-tutorial/tsconfig.json
  • sample-apps/react/stream-video-react-tutorial/tsconfig.node.json
  • sample-apps/react/zoom-clone/package.json
  • sample-apps/react/zoom-clone/tsconfig.json
  • sample-apps/react/zoom-clone/tsconfig.node.json
💤 Files with no reviewable changes (1)
  • packages/react-native-sdk/src/utils/StreamVideoRN/index.ts

Comment thread packages/client/src/rtc/helpers/sdp.ts
@oliverlaz oliverlaz merged commit d9ea158 into main Jun 22, 2026
19 checks passed
@oliverlaz oliverlaz deleted the typescript-6 branch June 22, 2026 13:02
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.

2 participants