@stream-io/video-client 1.27.3 → 1.27.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.27.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.27.3...@stream-io/video-client-1.27.4) (2025-08-13)
6
+
7
+ ### Bug Fixes
8
+
9
+ - expose isSupportedBrowser() utility ([#1859](https://github.com/GetStream/stream-video-js/issues/1859)) ([f51a434](https://github.com/GetStream/stream-video-js/commit/f51a4341f57407210ab2e9ba57f41818ddbd7ed9))
10
+
5
11
  ## [1.27.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.27.2...@stream-io/video-client-1.27.3) (2025-08-07)
6
12
 
7
13
  ### Bug Fixes
@@ -5643,6 +5643,151 @@ const getSdkVersion = (sdk) => {
5643
5643
  return sdk ? `${sdk.major}.${sdk.minor}.${sdk.patch}` : '0.0.0-development';
5644
5644
  };
5645
5645
 
5646
+ const version = "1.27.4";
5647
+ const [major, minor, patch] = version.split('.');
5648
+ let sdkInfo = {
5649
+ type: SdkType.PLAIN_JAVASCRIPT,
5650
+ major,
5651
+ minor,
5652
+ patch,
5653
+ };
5654
+ let osInfo;
5655
+ let deviceInfo;
5656
+ let webRtcInfo;
5657
+ let deviceState = { oneofKind: undefined };
5658
+ const setSdkInfo = (info) => {
5659
+ sdkInfo = info;
5660
+ };
5661
+ const getSdkInfo = () => {
5662
+ return sdkInfo;
5663
+ };
5664
+ const setOSInfo = (info) => {
5665
+ osInfo = info;
5666
+ };
5667
+ const setDeviceInfo = (info) => {
5668
+ deviceInfo = info;
5669
+ };
5670
+ const getWebRTCInfo = () => {
5671
+ return webRtcInfo;
5672
+ };
5673
+ const setWebRTCInfo = (info) => {
5674
+ webRtcInfo = info;
5675
+ };
5676
+ const setThermalState = (state) => {
5677
+ if (!osInfo) {
5678
+ deviceState = { oneofKind: undefined };
5679
+ return;
5680
+ }
5681
+ if (osInfo.name === 'android') {
5682
+ const thermalState = AndroidThermalState[state] ||
5683
+ AndroidThermalState.UNSPECIFIED;
5684
+ deviceState = {
5685
+ oneofKind: 'android',
5686
+ android: {
5687
+ thermalState,
5688
+ isPowerSaverMode: deviceState?.oneofKind === 'android' &&
5689
+ deviceState.android.isPowerSaverMode,
5690
+ },
5691
+ };
5692
+ }
5693
+ if (osInfo.name.toLowerCase() === 'ios') {
5694
+ const thermalState = AppleThermalState[state] ||
5695
+ AppleThermalState.UNSPECIFIED;
5696
+ deviceState = {
5697
+ oneofKind: 'apple',
5698
+ apple: {
5699
+ thermalState,
5700
+ isLowPowerModeEnabled: deviceState?.oneofKind === 'apple' &&
5701
+ deviceState.apple.isLowPowerModeEnabled,
5702
+ },
5703
+ };
5704
+ }
5705
+ };
5706
+ const setPowerState = (powerMode) => {
5707
+ if (!osInfo) {
5708
+ deviceState = { oneofKind: undefined };
5709
+ return;
5710
+ }
5711
+ if (osInfo.name === 'android') {
5712
+ deviceState = {
5713
+ oneofKind: 'android',
5714
+ android: {
5715
+ thermalState: deviceState?.oneofKind === 'android'
5716
+ ? deviceState.android.thermalState
5717
+ : AndroidThermalState.UNSPECIFIED,
5718
+ isPowerSaverMode: powerMode,
5719
+ },
5720
+ };
5721
+ }
5722
+ if (osInfo.name.toLowerCase() === 'ios') {
5723
+ deviceState = {
5724
+ oneofKind: 'apple',
5725
+ apple: {
5726
+ thermalState: deviceState?.oneofKind === 'apple'
5727
+ ? deviceState.apple.thermalState
5728
+ : AppleThermalState.UNSPECIFIED,
5729
+ isLowPowerModeEnabled: powerMode,
5730
+ },
5731
+ };
5732
+ }
5733
+ };
5734
+ const getDeviceState = () => {
5735
+ return deviceState;
5736
+ };
5737
+ const getClientDetails = async () => {
5738
+ if (isReactNative()) {
5739
+ // Since RN doesn't support web, sharing browser info is not required
5740
+ return {
5741
+ sdk: sdkInfo,
5742
+ os: osInfo,
5743
+ device: deviceInfo,
5744
+ };
5745
+ }
5746
+ // @ts-expect-error - userAgentData is not yet in the TS types
5747
+ const userAgentDataApi = navigator.userAgentData;
5748
+ let userAgentData;
5749
+ if (userAgentDataApi && userAgentDataApi.getHighEntropyValues) {
5750
+ try {
5751
+ userAgentData = await userAgentDataApi.getHighEntropyValues([
5752
+ 'platform',
5753
+ 'platformVersion',
5754
+ 'fullVersionList',
5755
+ ]);
5756
+ }
5757
+ catch {
5758
+ // Ignore the error
5759
+ }
5760
+ }
5761
+ const userAgent = new UAParser(navigator.userAgent);
5762
+ const { browser, os, device, cpu } = userAgent.getResult();
5763
+ // If userAgentData is available, it means we are in a modern Chromium browser,
5764
+ // and we can use it to get more accurate browser information.
5765
+ // We hook into the fullVersionList to find the browser name and version and
5766
+ // eventually detect exotic browsers like Samsung Internet, AVG Secure Browser, etc.
5767
+ // who by default they identify themselves as "Chromium" in the user agent string.
5768
+ // Eliminates the generic "Chromium" name and "Not)A_Brand" name from the list.
5769
+ // https://wicg.github.io/ua-client-hints/#create-arbitrary-brands-section
5770
+ const uaBrowser = userAgentData?.fullVersionList?.find((v) => !v.brand.includes('Chromium') && !v.brand.match(/[()\-./:;=?_]/g));
5771
+ return {
5772
+ sdk: sdkInfo,
5773
+ browser: {
5774
+ name: uaBrowser?.brand || browser.name || navigator.userAgent,
5775
+ version: uaBrowser?.version || browser.version || '',
5776
+ },
5777
+ os: {
5778
+ name: userAgentData?.platform || os.name || '',
5779
+ version: userAgentData?.platformVersion || os.version || '',
5780
+ architecture: cpu.architecture || '',
5781
+ },
5782
+ device: {
5783
+ name: [device.vendor, device.model, device.type]
5784
+ .filter(Boolean)
5785
+ .join(' '),
5786
+ version: '',
5787
+ },
5788
+ };
5789
+ };
5790
+
5646
5791
  /**
5647
5792
  * Checks whether the current browser is Safari.
5648
5793
  */
@@ -5667,12 +5812,34 @@ const isChrome = () => {
5667
5812
  return false;
5668
5813
  return navigator.userAgent?.includes('Chrome');
5669
5814
  };
5815
+ /**
5816
+ * Checks whether the current browser is among the list of first-class supported browsers.
5817
+ * This includes Chrome, Edge, Firefox, and Safari.
5818
+ *
5819
+ * Although the Stream Video SDK may work in other browsers, these are the ones we officially support.
5820
+ */
5821
+ const isSupportedBrowser = async () => {
5822
+ const { browser } = await getClientDetails();
5823
+ if (!browser)
5824
+ return false; // we aren't running in a browser
5825
+ const name = browser.name.toLowerCase();
5826
+ const [major] = browser.version.split('.');
5827
+ const version = parseInt(major, 10);
5828
+ return ((name.includes('chrome') && version >= 124) ||
5829
+ (name.includes('edge') && version >= 124) ||
5830
+ (name.includes('firefox') && version >= 124) ||
5831
+ (name.includes('safari') && version >= 17) ||
5832
+ (name.includes('webkit') && version >= 605) || // WebView on iOS
5833
+ (name.includes('webview') && version >= 124) // WebView on Android
5834
+ );
5835
+ };
5670
5836
 
5671
5837
  var browsers = /*#__PURE__*/Object.freeze({
5672
5838
  __proto__: null,
5673
5839
  isChrome: isChrome,
5674
5840
  isFirefox: isFirefox,
5675
- isSafari: isSafari
5841
+ isSafari: isSafari,
5842
+ isSupportedBrowser: isSupportedBrowser
5676
5843
  });
5677
5844
 
5678
5845
  /**
@@ -5914,142 +6081,6 @@ const aggregate = (stats) => {
5914
6081
  return report;
5915
6082
  };
5916
6083
 
5917
- const version = "1.27.3";
5918
- const [major, minor, patch] = version.split('.');
5919
- let sdkInfo = {
5920
- type: SdkType.PLAIN_JAVASCRIPT,
5921
- major,
5922
- minor,
5923
- patch,
5924
- };
5925
- let osInfo;
5926
- let deviceInfo;
5927
- let webRtcInfo;
5928
- let deviceState = { oneofKind: undefined };
5929
- const setSdkInfo = (info) => {
5930
- sdkInfo = info;
5931
- };
5932
- const getSdkInfo = () => {
5933
- return sdkInfo;
5934
- };
5935
- const setOSInfo = (info) => {
5936
- osInfo = info;
5937
- };
5938
- const setDeviceInfo = (info) => {
5939
- deviceInfo = info;
5940
- };
5941
- const getWebRTCInfo = () => {
5942
- return webRtcInfo;
5943
- };
5944
- const setWebRTCInfo = (info) => {
5945
- webRtcInfo = info;
5946
- };
5947
- const setThermalState = (state) => {
5948
- if (!osInfo) {
5949
- deviceState = { oneofKind: undefined };
5950
- return;
5951
- }
5952
- if (osInfo.name === 'android') {
5953
- const thermalState = AndroidThermalState[state] ||
5954
- AndroidThermalState.UNSPECIFIED;
5955
- deviceState = {
5956
- oneofKind: 'android',
5957
- android: {
5958
- thermalState,
5959
- isPowerSaverMode: deviceState?.oneofKind === 'android' &&
5960
- deviceState.android.isPowerSaverMode,
5961
- },
5962
- };
5963
- }
5964
- if (osInfo.name.toLowerCase() === 'ios') {
5965
- const thermalState = AppleThermalState[state] ||
5966
- AppleThermalState.UNSPECIFIED;
5967
- deviceState = {
5968
- oneofKind: 'apple',
5969
- apple: {
5970
- thermalState,
5971
- isLowPowerModeEnabled: deviceState?.oneofKind === 'apple' &&
5972
- deviceState.apple.isLowPowerModeEnabled,
5973
- },
5974
- };
5975
- }
5976
- };
5977
- const setPowerState = (powerMode) => {
5978
- if (!osInfo) {
5979
- deviceState = { oneofKind: undefined };
5980
- return;
5981
- }
5982
- if (osInfo.name === 'android') {
5983
- deviceState = {
5984
- oneofKind: 'android',
5985
- android: {
5986
- thermalState: deviceState?.oneofKind === 'android'
5987
- ? deviceState.android.thermalState
5988
- : AndroidThermalState.UNSPECIFIED,
5989
- isPowerSaverMode: powerMode,
5990
- },
5991
- };
5992
- }
5993
- if (osInfo.name.toLowerCase() === 'ios') {
5994
- deviceState = {
5995
- oneofKind: 'apple',
5996
- apple: {
5997
- thermalState: deviceState?.oneofKind === 'apple'
5998
- ? deviceState.apple.thermalState
5999
- : AppleThermalState.UNSPECIFIED,
6000
- isLowPowerModeEnabled: powerMode,
6001
- },
6002
- };
6003
- }
6004
- };
6005
- const getDeviceState = () => {
6006
- return deviceState;
6007
- };
6008
- const getClientDetails = async () => {
6009
- if (isReactNative()) {
6010
- // Since RN doesn't support web, sharing browser info is not required
6011
- return {
6012
- sdk: sdkInfo,
6013
- os: osInfo,
6014
- device: deviceInfo,
6015
- };
6016
- }
6017
- // @ts-expect-error - userAgentData is not yet in the TS types
6018
- const userAgentDataApi = navigator.userAgentData;
6019
- let userAgentData;
6020
- if (userAgentDataApi && userAgentDataApi.getHighEntropyValues) {
6021
- try {
6022
- userAgentData = await userAgentDataApi.getHighEntropyValues([
6023
- 'platform',
6024
- 'platformVersion',
6025
- ]);
6026
- }
6027
- catch {
6028
- // Ignore the error
6029
- }
6030
- }
6031
- const userAgent = new UAParser(navigator.userAgent);
6032
- const { browser, os, device, cpu } = userAgent.getResult();
6033
- return {
6034
- sdk: sdkInfo,
6035
- browser: {
6036
- name: browser.name || navigator.userAgent,
6037
- version: browser.version || '',
6038
- },
6039
- os: {
6040
- name: userAgentData?.platform || os.name || '',
6041
- version: userAgentData?.platformVersion || os.version || '',
6042
- architecture: cpu.architecture || '',
6043
- },
6044
- device: {
6045
- name: [device.vendor, device.model, device.type]
6046
- .filter(Boolean)
6047
- .join(' '),
6048
- version: '',
6049
- },
6050
- };
6051
- };
6052
-
6053
6084
  class SfuStatsReporter {
6054
6085
  constructor(sfuClient, { options, clientDetails, subscriber, publisher, microphone, camera, state, tracer, unifiedSessionId, }) {
6055
6086
  this.logger = getLogger(['SfuStatsReporter']);
@@ -14514,7 +14545,7 @@ class StreamClient {
14514
14545
  this.getUserAgent = () => {
14515
14546
  if (!this.cachedUserAgent) {
14516
14547
  const { clientAppIdentifier = {} } = this.options;
14517
- const { sdkName = 'js', sdkVersion = "1.27.3", ...extras } = clientAppIdentifier;
14548
+ const { sdkName = 'js', sdkVersion = "1.27.4", ...extras } = clientAppIdentifier;
14518
14549
  this.cachedUserAgent = [
14519
14550
  `stream-video-${sdkName}-v${sdkVersion}`,
14520
14551
  ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),