@stream-io/video-client 1.17.0 → 1.18.0

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,26 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.18.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.17.1...@stream-io/video-client-1.18.0) (2025-02-26)
6
+
7
+
8
+ ### Features
9
+
10
+ * align SDK version reporting, use higher-entropy user agent data for stats ([#1696](https://github.com/GetStream/stream-video-js/issues/1696)) ([e02e8d9](https://github.com/GetStream/stream-video-js/commit/e02e8d9b3843086a3fa859a8bd31ba65ace5a7fd))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * don't implicitly mark calls as `ringing` ([#1697](https://github.com/GetStream/stream-video-js/issues/1697)) ([3429a7b](https://github.com/GetStream/stream-video-js/commit/3429a7ba52e13a43b96d2c3c28f270da111f84b2)), closes [/github.com/GetStream/stream-video-js/issues/1561#issuecomment-2662584543](https://github.com/GetStream//github.com/GetStream/stream-video-js/issues/1561/issues/issuecomment-2662584543)
16
+ * use axios version that doesnt import node specific module ([#1699](https://github.com/GetStream/stream-video-js/issues/1699)) ([414e01b](https://github.com/GetStream/stream-video-js/commit/414e01b9c7e4c4862b429e48c506673bcc228fa4))
17
+
18
+ ## [1.17.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.17.0...@stream-io/video-client-1.17.1) (2025-02-19)
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * do not reconnect when device is offline ([#1688](https://github.com/GetStream/stream-video-js/issues/1688)) ([c6b6f58](https://github.com/GetStream/stream-video-js/commit/c6b6f58310a3365eb6f40d76a15c26791f413241))
24
+
5
25
  ## [1.17.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.16.7...@stream-io/video-client-1.17.0) (2025-02-17)
6
26
 
7
27
 
@@ -5283,6 +5283,8 @@ class BasePeerConnection {
5283
5283
  this.onIceConnectionStateChange = () => {
5284
5284
  const state = this.pc.iceConnectionState;
5285
5285
  this.logger('debug', `ICE connection state changed`, state);
5286
+ if (this.state.callingState === CallingState.OFFLINE)
5287
+ return;
5286
5288
  if (this.state.callingState === CallingState.RECONNECTING)
5287
5289
  return;
5288
5290
  // do nothing when ICE is restarting
@@ -7461,7 +7463,7 @@ const aggregate = (stats) => {
7461
7463
  return report;
7462
7464
  };
7463
7465
 
7464
- const version = "1.17.0";
7466
+ const version = "1.18.0";
7465
7467
  const [major, minor, patch] = version.split('.');
7466
7468
  let sdkInfo = {
7467
7469
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -7482,15 +7484,9 @@ const getSdkInfo = () => {
7482
7484
  const setOSInfo = (info) => {
7483
7485
  osInfo = info;
7484
7486
  };
7485
- const getOSInfo = () => {
7486
- return osInfo;
7487
- };
7488
7487
  const setDeviceInfo = (info) => {
7489
7488
  deviceInfo = info;
7490
7489
  };
7491
- const getDeviceInfo = () => {
7492
- return deviceInfo;
7493
- };
7494
7490
  const getWebRTCInfo = () => {
7495
7491
  return webRtcInfo;
7496
7492
  };
@@ -7558,26 +7554,40 @@ const setPowerState = (powerMode) => {
7558
7554
  const getDeviceState = () => {
7559
7555
  return deviceState;
7560
7556
  };
7561
- const getClientDetails = () => {
7557
+ const getClientDetails = async () => {
7562
7558
  if (isReactNative()) {
7563
7559
  // Since RN doesn't support web, sharing browser info is not required
7564
7560
  return {
7565
- sdk: getSdkInfo(),
7566
- os: getOSInfo(),
7567
- device: getDeviceInfo(),
7561
+ sdk: sdkInfo,
7562
+ os: osInfo,
7563
+ device: deviceInfo,
7568
7564
  };
7569
7565
  }
7566
+ // @ts-expect-error - userAgentData is not yet in the TS types
7567
+ const userAgentDataApi = navigator.userAgentData;
7568
+ let userAgentData;
7569
+ if (userAgentDataApi && userAgentDataApi.getHighEntropyValues) {
7570
+ try {
7571
+ userAgentData = await userAgentDataApi.getHighEntropyValues([
7572
+ 'platform',
7573
+ 'platformVersion',
7574
+ ]);
7575
+ }
7576
+ catch (e) {
7577
+ // Ignore the error
7578
+ }
7579
+ }
7570
7580
  const userAgent = new UAParser(navigator.userAgent);
7571
7581
  const { browser, os, device, cpu } = userAgent.getResult();
7572
7582
  return {
7573
- sdk: getSdkInfo(),
7583
+ sdk: sdkInfo,
7574
7584
  browser: {
7575
7585
  name: browser.name || navigator.userAgent,
7576
7586
  version: browser.version || '',
7577
7587
  },
7578
7588
  os: {
7579
- name: os.name || '',
7580
- version: os.version || '',
7589
+ name: userAgentData?.platform || os.name || '',
7590
+ version: userAgentData?.platformVersion || os.version || '',
7581
7591
  architecture: cpu.architecture || '',
7582
7592
  },
7583
7593
  device: {
@@ -7806,8 +7816,6 @@ const globalOverrideKey = Symbol('globalOverrideKey');
7806
7816
  class DynascaleManager {
7807
7817
  /**
7808
7818
  * Creates a new DynascaleManager instance.
7809
- *
7810
- * @param call the call to manage.
7811
7819
  */
7812
7820
  constructor(callState, speaker) {
7813
7821
  /**
@@ -10445,6 +10453,7 @@ class Call {
10445
10453
  this.leaveCallHooks.forEach((hook) => hook());
10446
10454
  this.initialized = false;
10447
10455
  this.hasJoinedOnce = false;
10456
+ this.ringingSubject.next(false);
10448
10457
  this.clientStore.unregisterCall(this);
10449
10458
  this.camera.dispose();
10450
10459
  this.microphone.dispose();
@@ -10503,7 +10512,7 @@ class Call {
10503
10512
  this.state.updateFromCallResponse(response.call);
10504
10513
  this.state.setMembers(response.members);
10505
10514
  this.state.setOwnCapabilities(response.own_capabilities);
10506
- if (params?.ring || this.ringing) {
10515
+ if (params?.ring) {
10507
10516
  // the call response can indicate where the call is still ringing or not
10508
10517
  this.ringingSubject.next(true);
10509
10518
  }
@@ -10525,7 +10534,7 @@ class Call {
10525
10534
  this.state.updateFromCallResponse(response.call);
10526
10535
  this.state.setMembers(response.members);
10527
10536
  this.state.setOwnCapabilities(response.own_capabilities);
10528
- if (data?.ring || this.ringing) {
10537
+ if (data?.ring) {
10529
10538
  // the call response can indicate where the call is still ringing or not
10530
10539
  this.ringingSubject.next(true);
10531
10540
  }
@@ -10637,7 +10646,7 @@ class Call {
10637
10646
  : previousSfuClient;
10638
10647
  this.sfuClient = sfuClient;
10639
10648
  this.dynascaleManager.setSfuClient(sfuClient);
10640
- const clientDetails = getClientDetails();
10649
+ const clientDetails = await getClientDetails();
10641
10650
  // we don't need to send JoinRequest if we are re-using an existing healthy SFU client
10642
10651
  if (previousSfuClient !== sfuClient) {
10643
10652
  // prepare a generic SDP and send it to the SFU.
@@ -10896,7 +10905,7 @@ class Call {
10896
10905
  this.state.updateFromCallResponse(joinResponse.call);
10897
10906
  this.state.setMembers(joinResponse.members);
10898
10907
  this.state.setOwnCapabilities(joinResponse.own_capabilities);
10899
- if (data?.ring && !this.ringing) {
10908
+ if (data?.ring) {
10900
10909
  this.ringingSubject.next(true);
10901
10910
  }
10902
10911
  if (this.ringing && !this.isCreatedByMe) {
@@ -11765,7 +11774,7 @@ class Call {
11765
11774
  * @param custom Custom data
11766
11775
  */
11767
11776
  this.submitFeedback = async (rating, { reason, custom, } = {}) => {
11768
- const { sdkName, sdkVersion, ...platform } = getSdkSignature(getClientDetails());
11777
+ const { sdkName, sdkVersion, ...platform } = getSdkSignature(await getClientDetails());
11769
11778
  return this.streamClient.post(`${this.streamClientBasePath}/feedback`, {
11770
11779
  rating,
11771
11780
  reason,
@@ -12451,7 +12460,7 @@ class StableWSConnection {
12451
12460
  }
12452
12461
  }
12453
12462
  catch (err) {
12454
- await this.client._setupConnectionIdPromise();
12463
+ this.client._setupConnectionIdPromise();
12455
12464
  this.isConnecting = false;
12456
12465
  // @ts-ignore
12457
12466
  this._log(`_connect() - Error - `, err);
@@ -12764,8 +12773,7 @@ class StreamClient {
12764
12773
  if (this.userID) {
12765
12774
  throw new Error('Use client.disconnect() before trying to connect as a different user. connectUser was called twice.');
12766
12775
  }
12767
- if ((this._isUsingServerAuth() || this.node) &&
12768
- !this.options.allowServerSideConnect) {
12776
+ if ((this.secret || this.node) && !this.options.allowServerSideConnect) {
12769
12777
  this.logger('warn', 'Please do not use connectUser server side. Use our @stream-io/node-sdk instead: https://getstream.io/video/docs/api/');
12770
12778
  }
12771
12779
  // we generate the client id client side
@@ -12833,7 +12841,7 @@ class StreamClient {
12833
12841
  this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
12834
12842
  return;
12835
12843
  }
12836
- await this._setupConnectionIdPromise();
12844
+ this._setupConnectionIdPromise();
12837
12845
  this.clientID = `${this.userID}--${randomId()}`;
12838
12846
  const newWsPromise = this.connect();
12839
12847
  this.wsPromiseSafe = makeSafePromise(newWsPromise);
@@ -12870,7 +12878,7 @@ class StreamClient {
12870
12878
  */
12871
12879
  this.connectAnonymousUser = async (user, tokenOrProvider) => {
12872
12880
  addConnectionEventListeners(this.updateNetworkConnectionStatus);
12873
- await this._setupConnectionIdPromise();
12881
+ this._setupConnectionIdPromise();
12874
12882
  this.anonymous = true;
12875
12883
  await this._setToken(user, tokenOrProvider, this.anonymous);
12876
12884
  this._setUser(user);
@@ -12920,12 +12928,16 @@ class StreamClient {
12920
12928
  }));
12921
12929
  };
12922
12930
  this._logApiRequest = (type, url, data, config) => {
12931
+ if (getLogLevel() !== 'trace')
12932
+ return;
12923
12933
  this.logger('trace', `client: ${type} - Request - ${url}`, {
12924
12934
  payload: data,
12925
12935
  config,
12926
12936
  });
12927
12937
  };
12928
12938
  this._logApiResponse = (type, url, response) => {
12939
+ if (getLogLevel() !== 'trace')
12940
+ return;
12929
12941
  this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
12930
12942
  response,
12931
12943
  });
@@ -13074,17 +13086,17 @@ class StreamClient {
13074
13086
  return await this.wsConnection.connect(this.defaultWSTimeout);
13075
13087
  };
13076
13088
  this.getUserAgent = () => {
13077
- const version = "1.17.0";
13078
- return (this.userAgent ||
13079
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
13080
- };
13081
- this.setUserAgent = (userAgent) => {
13082
- this.userAgent = userAgent;
13089
+ if (!this.cachedUserAgent) {
13090
+ const { clientAppIdentifier = {} } = this.options;
13091
+ const { sdkName = 'js', sdkVersion = "1.18.0", ...extras } = clientAppIdentifier;
13092
+ this.cachedUserAgent = [
13093
+ `stream-video-${sdkName}-v${sdkVersion}`,
13094
+ ...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
13095
+ `client_bundle=${"browser-esm"}`,
13096
+ ].join('|');
13097
+ }
13098
+ return this.cachedUserAgent;
13083
13099
  };
13084
- /**
13085
- * _isUsingServerAuth - Returns true if we're using server side auth
13086
- */
13087
- this._isUsingServerAuth = () => !!this.secret;
13088
13100
  this._enrichAxiosOptions = (options = {
13089
13101
  params: {},
13090
13102
  headers: {},
@@ -13197,24 +13209,32 @@ class StreamClient {
13197
13209
  const getInstanceKey = (apiKey, user) => {
13198
13210
  return `${apiKey}/${user.id}`;
13199
13211
  };
13212
+ /**
13213
+ * Utility function to get the client app identifier.
13214
+ */
13215
+ const getClientAppIdentifier = (options) => {
13216
+ const appId = options?.clientAppIdentifier || {};
13217
+ const sdkInfo = getSdkInfo();
13218
+ if (sdkInfo) {
13219
+ // ensure the sdk name and version are set correctly,
13220
+ // overriding any user-provided values
13221
+ appId.sdkName = SdkType[sdkInfo.type].toLowerCase();
13222
+ appId.sdkVersion = `${sdkInfo.major}.${sdkInfo.minor}.${sdkInfo.patch}`;
13223
+ }
13224
+ return appId;
13225
+ };
13200
13226
  /**
13201
13227
  * Creates a coordinator client.
13202
13228
  */
13203
13229
  const createCoordinatorClient = (apiKey, options) => {
13230
+ const clientAppIdentifier = getClientAppIdentifier(options);
13204
13231
  const coordinatorLogger = getLogger(['coordinator']);
13205
- const streamClient = new StreamClient(apiKey, {
13232
+ return new StreamClient(apiKey, {
13206
13233
  persistUserOnConnectionFailure: true,
13207
13234
  ...options,
13235
+ clientAppIdentifier,
13208
13236
  logger: coordinatorLogger,
13209
13237
  });
13210
- const sdkInfo = getSdkInfo();
13211
- if (sdkInfo) {
13212
- const sdkName = SdkType[sdkInfo.type].toLowerCase();
13213
- const sdkVersion = `${sdkInfo.major}.${sdkInfo.minor}.${sdkInfo.patch}`;
13214
- const userAgent = streamClient.getUserAgent();
13215
- streamClient.setUserAgent(`${userAgent}-video-${sdkName}-sdk-${sdkVersion}`);
13216
- }
13217
- return streamClient;
13218
13238
  };
13219
13239
  /**
13220
13240
  * Creates a token provider and allows integrators to provide
@@ -13581,5 +13601,5 @@ class StreamVideoClient {
13581
13601
  }
13582
13602
  StreamVideoClient._instances = new Map();
13583
13603
 
13584
- export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, FrameRecordingSettingsRequestModeEnum, FrameRecordingSettingsResponseModeEnum, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RTMPBroadcastRequestQualityEnum, RTMPSettingsRequestQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestClosedCaptionModeEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseClosedCaptionModeEnum, TranscriptionSettingsResponseLanguageEnum, TranscriptionSettingsResponseModeEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceInfo, getDeviceState, getLogLevel, getLogger, getOSInfo, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio, hasScreenShare, hasScreenShareAudio, hasVideo, isPinned, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setPowerState, setSdkInfo, setThermalState, setWebRTCInfo, speakerLayoutSortPreset, speaking };
13604
+ export { AudioSettingsRequestDefaultDeviceEnum, AudioSettingsResponseDefaultDeviceEnum, browsers as Browsers, Call, CallState, CallType, CallTypes, CallingState, CameraManager, CameraManagerState, CreateDeviceRequestPushProviderEnum, DebounceType, DynascaleManager, ErrorFromResponse, FrameRecordingSettingsRequestModeEnum, FrameRecordingSettingsResponseModeEnum, InputMediaDeviceManager, InputMediaDeviceManagerState, LayoutSettingsRequestNameEnum, MicrophoneManager, MicrophoneManagerState, NoiseCancellationSettingsModeEnum, OwnCapability, RTMPBroadcastRequestQualityEnum, RTMPSettingsRequestQualityEnum, RecordSettingsRequestModeEnum, RecordSettingsRequestQualityEnum, rxUtils as RxUtils, ScreenShareManager, ScreenShareState, events as SfuEvents, models as SfuModels, SpeakerManager, SpeakerState, StreamSfuClient, StreamVideoClient, StreamVideoReadOnlyStateStore, StreamVideoWriteableStateStore, TranscriptionSettingsRequestClosedCaptionModeEnum, TranscriptionSettingsRequestLanguageEnum, TranscriptionSettingsRequestModeEnum, TranscriptionSettingsResponseClosedCaptionModeEnum, TranscriptionSettingsResponseLanguageEnum, TranscriptionSettingsResponseModeEnum, VideoSettingsRequestCameraFacingEnum, VideoSettingsResponseCameraFacingEnum, ViewportTracker, VisibilityState, checkIfAudioOutputChangeSupported, combineComparators, conditional, createSoundDetector, defaultSortPreset, descending, deviceIds$, disposeOfMediaStream, dominantSpeaker, getAudioBrowserPermission, getAudioDevices, getAudioOutputDevices, getAudioStream, getClientDetails, getDeviceState, getLogLevel, getLogger, getScreenShareStream, getSdkInfo, getVideoBrowserPermission, getVideoDevices, getVideoStream, getWebRTCInfo, hasAudio, hasScreenShare, hasScreenShareAudio, hasVideo, isPinned, livestreamOrAudioRoomSortPreset, logLevels, logToConsole, name, noopComparator, paginatedLayoutSortPreset, pinned, publishingAudio, publishingVideo, reactionType, role, screenSharing, setDeviceInfo, setLogLevel, setLogger, setOSInfo, setPowerState, setSdkInfo, setThermalState, setWebRTCInfo, speakerLayoutSortPreset, speaking };
13585
13605
  //# sourceMappingURL=index.browser.es.js.map