@stream-io/video-client 1.16.1 → 1.16.2

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,13 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.16.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.16.1...@stream-io/video-client-1.16.2) (2025-02-05)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * race condition with unrecoverable error handling ([#1672](https://github.com/GetStream/stream-video-js/issues/1672)) ([be8095c](https://github.com/GetStream/stream-video-js/commit/be8095ce946cf98a0dfc1f3ea3391376cc7d2896)), closes [#1649](https://github.com/GetStream/stream-video-js/issues/1649) [#1618](https://github.com/GetStream/stream-video-js/issues/1618)
11
+
5
12
  ## [1.16.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.16.0...@stream-io/video-client-1.16.1) (2025-02-05)
6
13
 
7
14
 
@@ -5183,11 +5183,14 @@ class BasePeerConnection {
5183
5183
  */
5184
5184
  constructor(peerType, { sfuClient, connectionConfig, state, dispatcher, onUnrecoverableError, logTag, }) {
5185
5185
  this.isIceRestarting = false;
5186
+ this.isDisposed = false;
5186
5187
  this.subscriptions = [];
5187
5188
  /**
5188
5189
  * Disposes the `RTCPeerConnection` instance.
5189
5190
  */
5190
5191
  this.dispose = () => {
5192
+ this.onUnrecoverableError = undefined;
5193
+ this.isDisposed = true;
5191
5194
  this.detachEventHandlers();
5192
5195
  this.pc.close();
5193
5196
  };
@@ -5198,6 +5201,8 @@ class BasePeerConnection {
5198
5201
  this.on = (event, fn) => {
5199
5202
  this.subscriptions.push(this.dispatcher.on(event, (e) => {
5200
5203
  withoutConcurrency(`pc.${event}`, async () => fn(e)).catch((err) => {
5204
+ if (this.isDisposed)
5205
+ return;
5201
5206
  this.logger('warn', `Error handling ${event}`, err);
5202
5207
  });
5203
5208
  }));
@@ -5213,6 +5218,8 @@ class BasePeerConnection {
5213
5218
  this.unsubscribeIceTrickle?.();
5214
5219
  this.unsubscribeIceTrickle = createSafeAsyncSubscription(observable, async (candidate) => {
5215
5220
  return this.pc.addIceCandidate(candidate).catch((e) => {
5221
+ if (this.isDisposed)
5222
+ return;
5216
5223
  this.logger('warn', `ICE candidate error`, e, candidate);
5217
5224
  });
5218
5225
  });
@@ -5245,7 +5252,11 @@ class BasePeerConnection {
5245
5252
  const iceCandidate = this.toJSON(candidate);
5246
5253
  this.sfuClient
5247
5254
  .iceTrickle({ peerType: this.peerType, iceCandidate })
5248
- .catch((err) => this.logger('warn', `ICETrickle failed`, err));
5255
+ .catch((err) => {
5256
+ if (this.isDisposed)
5257
+ return;
5258
+ this.logger('warn', `ICETrickle failed`, err);
5259
+ });
5249
5260
  };
5250
5261
  /**
5251
5262
  * Converts the ICE candidate to a JSON string.
@@ -5274,6 +5285,8 @@ class BasePeerConnection {
5274
5285
  if (state === 'failed' || state === 'disconnected') {
5275
5286
  this.logger('debug', `Attempting to restart ICE`);
5276
5287
  this.restartIce().catch((e) => {
5288
+ if (this.isDisposed)
5289
+ return;
5277
5290
  this.logger('error', `ICE restart failed`, e);
5278
5291
  this.onUnrecoverableError?.();
5279
5292
  });
@@ -5325,6 +5338,8 @@ class BasePeerConnection {
5325
5338
  this.pc.removeEventListener('icecandidateerror', this.onIceCandidateError);
5326
5339
  this.pc.removeEventListener('signalingstatechange', this.onSignalingChange);
5327
5340
  this.pc.removeEventListener('iceconnectionstatechange', this.onIceConnectionStateChange);
5341
+ // cancel any ongoing ICE restart process
5342
+ withCancellation('onIceConnectionStateChange', () => Promise.resolve());
5328
5343
  this.pc.removeEventListener('icegatheringstatechange', this.onIceGatherChange);
5329
5344
  this.unsubscribeIceTrickle?.();
5330
5345
  this.subscriptions.forEach((unsubscribe) => unsubscribe());
@@ -5840,10 +5855,12 @@ class Publisher extends BasePeerConnection {
5840
5855
  await this.negotiate({ iceRestart: true });
5841
5856
  };
5842
5857
  this.onNegotiationNeeded = () => {
5843
- withoutConcurrency('publisher.negotiate', () => this.negotiate()).catch((err) => {
5858
+ withCancellation('publisher.negotiate', (signal) => this.negotiate().catch((err) => {
5859
+ if (signal.aborted)
5860
+ return;
5844
5861
  this.logger('error', `Negotiation failed.`, err);
5845
5862
  this.onUnrecoverableError?.();
5846
- });
5863
+ }));
5847
5864
  };
5848
5865
  /**
5849
5866
  * Initiates a new offer/answer exchange with the currently connected SFU.
@@ -5970,6 +5987,8 @@ class Publisher extends BasePeerConnection {
5970
5987
  detachEventHandlers() {
5971
5988
  super.detachEventHandlers();
5972
5989
  this.pc.removeEventListener('negotiationneeded', this.onNegotiationNeeded);
5990
+ // abort any ongoing negotiation
5991
+ withCancellation('publisher.negotiate', () => Promise.resolve());
5973
5992
  }
5974
5993
  }
5975
5994
 
@@ -7394,7 +7413,7 @@ const aggregate = (stats) => {
7394
7413
  return report;
7395
7414
  };
7396
7415
 
7397
- const version = "1.16.1";
7416
+ const version = "1.16.2";
7398
7417
  const [major, minor, patch] = version.split('.');
7399
7418
  let sdkInfo = {
7400
7419
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -13001,7 +13020,7 @@ class StreamClient {
13001
13020
  return await this.wsConnection.connect(this.defaultWSTimeout);
13002
13021
  };
13003
13022
  this.getUserAgent = () => {
13004
- const version = "1.16.1";
13023
+ const version = "1.16.2";
13005
13024
  return (this.userAgent ||
13006
13025
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
13007
13026
  };