@stream-io/video-client 1.7.2 → 1.7.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,20 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [1.7.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.7.3...@stream-io/video-client-1.7.4) (2024-10-02)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * retryable location hint ([#1505](https://github.com/GetStream/stream-video-js/issues/1505)) ([087417f](https://github.com/GetStream/stream-video-js/commit/087417f926b3d43a5bcb814ac9bb5951c1e63479))
11
+
12
+ ## [1.7.3](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.7.2...@stream-io/video-client-1.7.3) (2024-09-24)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * do not always error out api calls when web socket initially failed ([#1495](https://github.com/GetStream/stream-video-js/issues/1495)) ([7cdb62e](https://github.com/GetStream/stream-video-js/commit/7cdb62e75cad56098ee81eabbcc63382f93fd218))
18
+
5
19
  ## [1.7.2](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.7.1...@stream-io/video-client-1.7.2) (2024-09-20)
6
20
 
7
21
 
@@ -2875,6 +2875,13 @@ function convertErrorToJson(err) {
2875
2875
  }
2876
2876
  return jsonObj;
2877
2877
  }
2878
+ /**
2879
+ * Informs if a promise is yet to be resolved or rejected
2880
+ */
2881
+ async function isPromisePending(promise) {
2882
+ const emptyObj = {};
2883
+ return Promise.race([promise, emptyObj]).then((value) => (value === emptyObj ? true : false), () => false);
2884
+ }
2878
2885
  /**
2879
2886
  * isOnline safely return the navigator.online value for browser env
2880
2887
  * if navigator is not in global object, it always return true
@@ -2928,7 +2935,7 @@ const logLevels = Object.freeze({
2928
2935
  warn: 3,
2929
2936
  error: 4,
2930
2937
  });
2931
- let logger$1;
2938
+ let logger;
2932
2939
  let level = 'info';
2933
2940
  const logToConsole = (logLevel, message, ...args) => {
2934
2941
  let logMethod;
@@ -2962,7 +2969,7 @@ const logToConsole = (logLevel, message, ...args) => {
2962
2969
  logMethod(message, ...args);
2963
2970
  };
2964
2971
  const setLogger = (l, lvl) => {
2965
- logger$1 = l;
2972
+ logger = l;
2966
2973
  if (lvl) {
2967
2974
  setLogLevel(lvl);
2968
2975
  }
@@ -2972,7 +2979,7 @@ const setLogLevel = (l) => {
2972
2979
  };
2973
2980
  const getLogLevel = () => level;
2974
2981
  const getLogger = (withTags) => {
2975
- const loggerMethod = logger$1 || logToConsole;
2982
+ const loggerMethod = logger || logToConsole;
2976
2983
  const tags = (withTags || []).filter(Boolean).join(':');
2977
2984
  const result = (logLevel, message, ...args) => {
2978
2985
  if (logLevels[logLevel] >= logLevels[level]) {
@@ -3013,7 +3020,7 @@ const retryable = async (rpc, signal) => {
3013
3020
  return result;
3014
3021
  };
3015
3022
 
3016
- const version = "1.7.2";
3023
+ const version = "1.7.4";
3017
3024
  const [major, minor, patch] = version.split('.');
3018
3025
  let sdkInfo = {
3019
3026
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -11365,6 +11372,15 @@ class StableWSConnection {
11365
11372
  this._log(`_connect() - tokenProvider failed before, so going to retry`);
11366
11373
  await this.client.tokenManager.loadToken();
11367
11374
  }
11375
+ let mustSetupConnectionIdPromise = true;
11376
+ if (this.client.connectionIdPromise) {
11377
+ if (await isPromisePending(this.client.connectionIdPromise)) {
11378
+ mustSetupConnectionIdPromise = false;
11379
+ }
11380
+ }
11381
+ if (mustSetupConnectionIdPromise) {
11382
+ this.client._setupConnectionIdPromise();
11383
+ }
11368
11384
  this._setupConnectionPromise();
11369
11385
  const wsURL = this._buildUrl();
11370
11386
  this._log(`_connect() - Connecting to ${wsURL}`, {
@@ -11390,6 +11406,7 @@ class StableWSConnection {
11390
11406
  }
11391
11407
  }
11392
11408
  catch (err) {
11409
+ await this.client._setupConnectionIdPromise();
11393
11410
  this.isConnecting = false;
11394
11411
  // @ts-ignore
11395
11412
  this._log(`_connect() - Error - `, err);
@@ -11891,27 +11908,31 @@ class WSConnectionFallback {
11891
11908
  }
11892
11909
  }
11893
11910
 
11894
- const logger = getLogger(['location']);
11895
- const HINT_URL = `https://hint.stream-io-video.com/`;
11896
- const getLocationHint = async (hintUrl = HINT_URL, timeout = 2000) => {
11897
- const abortController = new AbortController();
11898
- const timeoutId = setTimeout(() => abortController.abort(), timeout);
11899
- try {
11900
- const response = await fetch(hintUrl, {
11901
- method: 'HEAD',
11902
- signal: abortController.signal,
11903
- });
11904
- const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
11905
- logger('debug', `Location header: ${awsPop}`);
11906
- return awsPop.substring(0, 3); // AMS1-P2 -> AMS
11907
- }
11908
- catch (e) {
11909
- logger('warn', `Failed to get location hint from ${hintUrl}`, e);
11910
- return 'ERR';
11911
- }
11912
- finally {
11913
- clearTimeout(timeoutId);
11914
- }
11911
+ const getLocationHint = async (hintUrl = `https://hint.stream-io-video.com/`, timeout = 2000, maxAttempts = 3) => {
11912
+ const logger = getLogger(['location-hint']);
11913
+ let attempt = 0;
11914
+ let locationHint = 'ERR';
11915
+ do {
11916
+ const abortController = new AbortController();
11917
+ const timeoutId = setTimeout(() => abortController.abort(), timeout);
11918
+ try {
11919
+ const response = await fetch(hintUrl, {
11920
+ method: 'HEAD',
11921
+ signal: abortController.signal,
11922
+ });
11923
+ const awsPop = response.headers.get('x-amz-cf-pop') || 'ERR';
11924
+ logger('debug', `Location header: ${awsPop}`);
11925
+ locationHint = awsPop.substring(0, 3); // AMS1-P2 -> AMS
11926
+ }
11927
+ catch (e) {
11928
+ logger('warn', `Failed to get location hint from ${hintUrl}`, e);
11929
+ locationHint = 'ERR';
11930
+ }
11931
+ finally {
11932
+ clearTimeout(timeoutId);
11933
+ }
11934
+ } while (locationHint === 'ERR' && ++attempt < maxAttempts);
11935
+ return locationHint;
11915
11936
  };
11916
11937
 
11917
11938
  class StreamClient {
@@ -12047,10 +12068,7 @@ class StreamClient {
12047
12068
  this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
12048
12069
  return Promise.resolve();
12049
12070
  }
12050
- this.connectionIdPromise = new Promise((resolve, reject) => {
12051
- this.resolveConnectionId = resolve;
12052
- this.rejectConnectionId = reject;
12053
- });
12071
+ this._setupConnectionIdPromise();
12054
12072
  this.clientID = `${this.userID}--${randomId()}`;
12055
12073
  this.wsPromise = this.connect();
12056
12074
  return this.wsPromise;
@@ -12090,10 +12108,7 @@ class StreamClient {
12090
12108
  */
12091
12109
  this.connectAnonymousUser = async (user, tokenOrProvider) => {
12092
12110
  addConnectionEventListeners(this.updateNetworkConnectionStatus);
12093
- this.connectionIdPromise = new Promise((resolve, reject) => {
12094
- this.resolveConnectionId = resolve;
12095
- this.rejectConnectionId = reject;
12096
- });
12111
+ this._setupConnectionIdPromise();
12097
12112
  this.anonymous = true;
12098
12113
  await this._setToken(user, tokenOrProvider, this.anonymous);
12099
12114
  this._setUser(user);
@@ -12132,6 +12147,16 @@ class StreamClient {
12132
12147
  this.logger('debug', `Removing listener for ${eventName} event`);
12133
12148
  this.listeners[eventName] = this.listeners[eventName]?.filter((value) => value !== callback);
12134
12149
  };
12150
+ /**
12151
+ * sets up the this.connectionIdPromise
12152
+ */
12153
+ this._setupConnectionIdPromise = async () => {
12154
+ /** a promise that is resolved once connection id is set */
12155
+ this.connectionIdPromise = new Promise((resolve, reject) => {
12156
+ this.resolveConnectionId = resolve;
12157
+ this.rejectConnectionId = reject;
12158
+ });
12159
+ };
12135
12160
  this._logApiRequest = (type, url, data, config) => {
12136
12161
  this.logger('trace', `client: ${type} - Request - ${url}`, {
12137
12162
  payload: data,
@@ -12154,8 +12179,18 @@ class StreamClient {
12154
12179
  await Promise.all([
12155
12180
  this.tokenManager.tokenReady(),
12156
12181
  this.guestUserCreatePromise,
12157
- this.connectionIdPromise,
12158
12182
  ]);
12183
+ // we need to wait for presence of connection id before making requests
12184
+ try {
12185
+ await this.connectionIdPromise;
12186
+ }
12187
+ catch (e) {
12188
+ // in case connection id was rejected
12189
+ // reconnection maybe in progress
12190
+ // we can wait for healthy connection to resolve, which rejects when 15s timeout is reached
12191
+ await this.wsConnection?._waitForHealthy();
12192
+ await this.connectionIdPromise;
12193
+ }
12159
12194
  }
12160
12195
  const requestConfig = this._enrichAxiosOptions(options);
12161
12196
  try {
@@ -12338,7 +12373,7 @@ class StreamClient {
12338
12373
  });
12339
12374
  };
12340
12375
  this.getUserAgent = () => {
12341
- const version = "1.7.2";
12376
+ const version = "1.7.4";
12342
12377
  return (this.userAgent ||
12343
12378
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
12344
12379
  };
@@ -12421,7 +12456,7 @@ class StreamClient {
12421
12456
  this.browser = inputOptions.browser || typeof window !== 'undefined';
12422
12457
  this.node = !this.browser;
12423
12458
  if (this.browser) {
12424
- this.locationHint = getLocationHint(options?.locationHintUrl, options?.locationHintTimeout);
12459
+ this.locationHint = getLocationHint(options?.locationHintUrl, options?.locationHintTimeout, options?.locationHintMaxAttempts);
12425
12460
  }
12426
12461
  this.options = {
12427
12462
  timeout: 5000,