@stream-io/video-client 0.0.39 → 0.0.41

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/dist/index.cjs.js CHANGED
@@ -6303,7 +6303,7 @@ class Publisher {
6303
6303
  this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
6304
6304
  const { candidate } = e;
6305
6305
  if (!candidate) {
6306
- this.logger('warn', 'null ice candidate');
6306
+ this.logger('debug', 'null ice candidate');
6307
6307
  return;
6308
6308
  }
6309
6309
  yield this.sfuClient.iceTrickle({
@@ -6463,10 +6463,10 @@ class Publisher {
6463
6463
  this.logger('error', `ICE Candidate error`, errorMessage);
6464
6464
  };
6465
6465
  this.onIceConnectionStateChange = () => {
6466
- this.logger('error', `ICE Connection state changed`, this.pc.iceConnectionState);
6466
+ this.logger('debug', `ICE Connection state changed`, this.pc.iceConnectionState);
6467
6467
  };
6468
6468
  this.onIceGatheringStateChange = () => {
6469
- this.logger('error', `ICE Gathering State`, this.pc.iceGatheringState);
6469
+ this.logger('debug', `ICE Gathering State`, this.pc.iceGatheringState);
6470
6470
  };
6471
6471
  this.onSignalingStateChange = () => {
6472
6472
  this.logger('debug', `Signaling state changed`, this.pc.signalingState);
@@ -6633,7 +6633,7 @@ class Subscriber {
6633
6633
  this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
6634
6634
  const { candidate } = e;
6635
6635
  if (!candidate) {
6636
- logger$1('warn', 'null ice candidate');
6636
+ logger$1('debug', 'null ice candidate');
6637
6637
  return;
6638
6638
  }
6639
6639
  yield this.sfuClient.iceTrickle({
@@ -6868,7 +6868,7 @@ class StreamSfuClient {
6868
6868
  * from this SFU.
6869
6869
  */
6870
6870
  this.isMigratingAway = false;
6871
- this.pingIntervalInMs = 25 * 1000;
6871
+ this.pingIntervalInMs = 10 * 1000;
6872
6872
  this.unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
6873
6873
  this.close = (code = 1000, reason = 'Requested signal connection close') => {
6874
6874
  this.signalWs.close(code, reason);
@@ -6942,7 +6942,7 @@ class StreamSfuClient {
6942
6942
  if (this.lastMessageTimestamp) {
6943
6943
  const timeSinceLastMessage = new Date().getTime() - this.lastMessageTimestamp.getTime();
6944
6944
  if (timeSinceLastMessage > this.unhealthyTimeoutInMs) {
6945
- this.logger('error', 'SFU connection unhealthy, closing');
6945
+ this.logger('debug', 'SFU connection unhealthy, closing');
6946
6946
  this.close(4001, `SFU connection unhealthy. Didn't receive any healthcheck messages for ${this.unhealthyTimeoutInMs}ms`);
6947
6947
  }
6948
6948
  }
@@ -8049,6 +8049,16 @@ const watchParticipantCountChanged = (dispatcher, state) => {
8049
8049
  }
8050
8050
  });
8051
8051
  };
8052
+ const watchLiveEnded = (dispatcher, call) => {
8053
+ return dispatcher.on('error', (e) => {
8054
+ if (e.eventPayload.oneofKind !== 'error' ||
8055
+ !e.eventPayload.error.error ||
8056
+ e.eventPayload.error.error.code !== ErrorCode.LIVE_ENDED)
8057
+ return;
8058
+ if (!call.permissionsContext.hasPermission(OwnCapability.JOIN_BACKSTAGE))
8059
+ call.leave();
8060
+ });
8061
+ };
8052
8062
  /**
8053
8063
  * Watches and logs the errors reported by the currently connected SFU.
8054
8064
  */
@@ -8438,6 +8448,7 @@ const registerEventHandlers = (call, state, dispatcher) => {
8438
8448
  'call.user_muted': () => console.log('call.user_muted received'),
8439
8449
  };
8440
8450
  const eventHandlers = [
8451
+ watchLiveEnded(dispatcher, call),
8441
8452
  watchSfuErrorReports(dispatcher),
8442
8453
  watchChangePublishQuality(dispatcher, call),
8443
8454
  watchConnectionQualityChanged(dispatcher, state),
@@ -8696,7 +8707,7 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
8696
8707
  if (pollingIntervalInMs > 0) {
8697
8708
  const loop = () => __awaiter(void 0, void 0, void 0, function* () {
8698
8709
  yield run().catch((e) => {
8699
- logger('warn', 'Failed to collect stats', e);
8710
+ logger('debug', 'Failed to collect stats', e);
8700
8711
  });
8701
8712
  timeoutId = setTimeout(loop, pollingIntervalInMs);
8702
8713
  });
@@ -9104,13 +9115,6 @@ const getClientDetails = () => {
9104
9115
  * An object representation of a `Call`.
9105
9116
  */
9106
9117
  class Call {
9107
- /**
9108
- * A promise that exposes the reconnection logic
9109
- * The use-case is for the react-native platform where online/offline events are not available in the window
9110
- */
9111
- get rejoin() {
9112
- return this.rejoinPromise;
9113
- }
9114
9118
  /**
9115
9119
  * Constructs a new `Call` instance.
9116
9120
  *
@@ -9156,7 +9160,6 @@ class Call {
9156
9160
  if (callingState === exports.CallingState.LEFT) {
9157
9161
  throw new Error('Cannot leave call that has already been left.');
9158
9162
  }
9159
- this.rejoinPromise = undefined;
9160
9163
  if (this.ringing) {
9161
9164
  // I'm the one who started the call, so I should cancel it.
9162
9165
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
@@ -9360,7 +9363,7 @@ class Call {
9360
9363
  // we shouldn't be republishing the streams if we're migrating
9361
9364
  // as the underlying peer connection will take care of it as part
9362
9365
  // of the ice-restart process
9363
- if (localParticipant && !isReactNative() && !migrate) {
9366
+ if (localParticipant && !migrate) {
9364
9367
  const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
9365
9368
  // restore previous publishing state
9366
9369
  if (audioStream)
@@ -9372,7 +9375,6 @@ class Call {
9372
9375
  }
9373
9376
  this.logger('info', `[Rejoin]: State restored. Attempt: ${this.reconnectAttempts}`);
9374
9377
  });
9375
- this.rejoinPromise = rejoin;
9376
9378
  // reconnect if the connection was closed unexpectedly. example:
9377
9379
  // - SFU crash or restart
9378
9380
  // - network change
@@ -9405,9 +9407,6 @@ class Call {
9405
9407
  if (e.code === KnownCodes.WS_CLOSED_ABRUPTLY &&
9406
9408
  sfuClient.isMigratingAway)
9407
9409
  return;
9408
- // do nothing for react-native as it is handled by SDK
9409
- if (isReactNative())
9410
- return;
9411
9410
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
9412
9411
  rejoin().catch((err) => {
9413
9412
  this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
@@ -9421,28 +9420,34 @@ class Call {
9421
9420
  });
9422
9421
  });
9423
9422
  // handlers for connection online/offline events
9424
- // Note: window.addEventListener is not available in React Native, hence the check
9425
- if (typeof window !== 'undefined' && window.addEventListener) {
9426
- const handleOnOffline = () => {
9427
- window.removeEventListener('offline', handleOnOffline);
9428
- this.logger('warn', '[Rejoin]: Going offline...');
9429
- this.state.setCallingState(exports.CallingState.OFFLINE);
9430
- };
9431
- const handleOnOnline = () => {
9432
- window.removeEventListener('online', handleOnOnline);
9433
- if (this.state.callingState === exports.CallingState.OFFLINE) {
9434
- this.logger('info', '[Rejoin]: Going online...');
9435
- rejoin().catch((err) => {
9436
- this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9437
- this.state.setCallingState(exports.CallingState.RECONNECTING_FAILED);
9438
- });
9439
- }
9440
- };
9441
- window.addEventListener('offline', handleOnOffline);
9442
- window.addEventListener('online', handleOnOnline);
9443
- // register cleanup hooks
9444
- this.leaveCallHooks.push(() => window.removeEventListener('offline', handleOnOffline), () => window.removeEventListener('online', handleOnOnline));
9445
- }
9423
+ const unsubscribeOnlineEvent = this.streamClient.on('connection.changed', (e) => {
9424
+ if (e.type !== 'connection.changed')
9425
+ return;
9426
+ if (!e.online)
9427
+ return;
9428
+ unsubscribeOnlineEvent();
9429
+ const currentCallingState = this.state.callingState;
9430
+ if (currentCallingState === exports.CallingState.OFFLINE ||
9431
+ currentCallingState === exports.CallingState.RECONNECTING_FAILED) {
9432
+ this.logger('info', '[Rejoin]: Going online...');
9433
+ rejoin().catch((err) => {
9434
+ this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9435
+ this.state.setCallingState(exports.CallingState.RECONNECTING_FAILED);
9436
+ });
9437
+ }
9438
+ });
9439
+ const unsubscribeOfflineEvent = this.streamClient.on('connection.changed', (e) => {
9440
+ if (e.type !== 'connection.changed')
9441
+ return;
9442
+ if (e.online)
9443
+ return;
9444
+ unsubscribeOfflineEvent();
9445
+ this.state.setCallingState(exports.CallingState.OFFLINE);
9446
+ });
9447
+ this.leaveCallHooks.push(() => {
9448
+ unsubscribeOnlineEvent();
9449
+ unsubscribeOfflineEvent();
9450
+ });
9446
9451
  if (!this.subscriber) {
9447
9452
  this.subscriber = new Subscriber({
9448
9453
  sfuClient,
@@ -10291,6 +10296,9 @@ const isErrorEvent = (res) => res.error !== undefined;
10291
10296
  */
10292
10297
  class StableWSConnection {
10293
10298
  constructor(client) {
10299
+ this._log = (msg, extra = {}, level = 'info') => {
10300
+ this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10301
+ };
10294
10302
  this.setClient = (client) => {
10295
10303
  this.client = client;
10296
10304
  };
@@ -10319,7 +10327,8 @@ class StableWSConnection {
10319
10327
  if (event.type === 'offline') {
10320
10328
  // mark the connection as down
10321
10329
  this._log('onlineStatusChanged() - Status changing to offline');
10322
- this._setHealth(false);
10330
+ // we know that the app is offline so dispatch the unhealthy connection event immediately
10331
+ this._setHealth(false, true);
10323
10332
  }
10324
10333
  else if (event.type === 'online') {
10325
10334
  // retry right now...
@@ -10447,13 +10456,14 @@ class StableWSConnection {
10447
10456
  * Broadcasts an event in case the connection status changed.
10448
10457
  *
10449
10458
  * @param {boolean} healthy boolean indicating if the connection is healthy or not
10459
+ * @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
10450
10460
  *
10451
10461
  */
10452
- this._setHealth = (healthy) => {
10462
+ this._setHealth = (healthy, dispatchImmediately = false) => {
10453
10463
  if (healthy === this.isHealthy)
10454
10464
  return;
10455
10465
  this.isHealthy = healthy;
10456
- if (this.isHealthy) {
10466
+ if (this.isHealthy || dispatchImmediately) {
10457
10467
  this.client.dispatchEvent({
10458
10468
  type: 'connection.changed',
10459
10469
  online: this.isHealthy,
@@ -10575,9 +10585,6 @@ class StableWSConnection {
10575
10585
  this.connectionCheckTimeout = this.pingInterval + 10 * 1000;
10576
10586
  addConnectionEventListeners(this.onlineStatusChanged);
10577
10587
  }
10578
- _log(msg, extra = {}, level = 'info') {
10579
- this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10580
- }
10581
10588
  /**
10582
10589
  * connect - Connect to the WS URL
10583
10590
  * the default 15s timeout allows between 2~3 tries
@@ -11329,6 +11336,18 @@ class StreamClient {
11329
11336
  constructor(key, options) {
11330
11337
  var _a;
11331
11338
  this.nextRequestAbortController = null;
11339
+ this.devToken = (userID) => {
11340
+ return DevToken(userID);
11341
+ };
11342
+ this.getAuthType = () => {
11343
+ return this.anonymous ? 'anonymous' : 'jwt';
11344
+ };
11345
+ this.setBaseURL = (baseURL) => {
11346
+ this.baseURL = baseURL;
11347
+ this.wsBaseURL = this.baseURL
11348
+ .replace('http', 'ws')
11349
+ .replace(':3030', ':8800');
11350
+ };
11332
11351
  this._getConnectionID = () => { var _a, _b; return ((_a = this.wsConnection) === null || _a === void 0 ? void 0 : _a.connectionID) || ((_b = this.wsFallback) === null || _b === void 0 ? void 0 : _b.connectionID); };
11333
11352
  this._hasConnectionID = () => Boolean(this._getConnectionID());
11334
11353
  /**
@@ -11393,6 +11412,16 @@ class StreamClient {
11393
11412
  }
11394
11413
  });
11395
11414
  this._setToken = (user, userTokenOrProvider, isAnonymous) => this.tokenManager.setTokenOrProvider(userTokenOrProvider, user, isAnonymous);
11415
+ this._setUser = (user) => {
11416
+ /**
11417
+ * This one is used by the frontend. This is a copy of the current user object stored on backend.
11418
+ * It contains reserved properties and own user properties which are not present in `this._user`.
11419
+ */
11420
+ this.user = user;
11421
+ this.userID = user.id;
11422
+ // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11423
+ this._user = Object.assign({}, user);
11424
+ };
11396
11425
  /**
11397
11426
  * Disconnects the websocket connection, without removing the user set on client.
11398
11427
  * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need
@@ -11481,6 +11510,66 @@ class StreamClient {
11481
11510
  // resolve the connection_id here.
11482
11511
  this.resolveConnectionId();
11483
11512
  });
11513
+ /**
11514
+ * on - Listen to events on all channels and users your watching
11515
+ *
11516
+ * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11517
+ * or
11518
+ * client.on(event => {console.log(event.type)})
11519
+ *
11520
+ * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11521
+ * @param {EventHandler} [callbackOrNothing] The callback to call
11522
+ *
11523
+ * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11524
+ */
11525
+ this.on = (callbackOrEventName, callbackOrNothing) => {
11526
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11527
+ const callback = callbackOrNothing
11528
+ ? callbackOrNothing
11529
+ : callbackOrEventName;
11530
+ if (!(key in this.listeners)) {
11531
+ this.listeners[key] = [];
11532
+ }
11533
+ this.listeners[key].push(callback);
11534
+ return () => {
11535
+ this.off(key, callback);
11536
+ };
11537
+ };
11538
+ /**
11539
+ * off - Remove the event handler
11540
+ *
11541
+ */
11542
+ this.off = (callbackOrEventName, callbackOrNothing) => {
11543
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11544
+ const callback = callbackOrNothing
11545
+ ? callbackOrNothing
11546
+ : callbackOrEventName;
11547
+ if (!(key in this.listeners)) {
11548
+ this.listeners[key] = [];
11549
+ }
11550
+ this.logger('debug', `Removing listener for ${key} event`);
11551
+ this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11552
+ };
11553
+ this._logApiRequest = (type, url, data, config) => {
11554
+ this.logger('trace', `client: ${type} - Request - ${url}`, {
11555
+ payload: data,
11556
+ config,
11557
+ });
11558
+ };
11559
+ this._logApiResponse = (type, url, response) => {
11560
+ this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11561
+ response,
11562
+ });
11563
+ this.logger('trace', `client:${type} - Response payload`, {
11564
+ response,
11565
+ });
11566
+ };
11567
+ this._logApiError = (type, url, error) => {
11568
+ this.logger('error', `client:${type} - Error - url: ${url}`, {
11569
+ url,
11570
+ error,
11571
+ });
11572
+ };
11484
11573
  this.doAxiosRequest = (type, url, data, options = {}) => __awaiter(this, void 0, void 0, function* () {
11485
11574
  var _g;
11486
11575
  if (!options.publicEndpoint || this.user) {
@@ -11545,6 +11634,43 @@ class StreamClient {
11545
11634
  }
11546
11635
  }
11547
11636
  });
11637
+ this.get = (url, params) => {
11638
+ return this.doAxiosRequest('get', url, null, {
11639
+ params,
11640
+ });
11641
+ };
11642
+ this.put = (url, data) => {
11643
+ return this.doAxiosRequest('put', url, data);
11644
+ };
11645
+ this.post = (url, data) => {
11646
+ return this.doAxiosRequest('post', url, data);
11647
+ };
11648
+ this.patch = (url, data) => {
11649
+ return this.doAxiosRequest('patch', url, data);
11650
+ };
11651
+ this.delete = (url, params) => {
11652
+ return this.doAxiosRequest('delete', url, null, {
11653
+ params,
11654
+ });
11655
+ };
11656
+ this.errorFromResponse = (response) => {
11657
+ let err;
11658
+ err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11659
+ if (response.data && response.data.code) {
11660
+ err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11661
+ err.code = response.data.code;
11662
+ }
11663
+ err.response = response;
11664
+ err.status = response.status;
11665
+ return err;
11666
+ };
11667
+ this.handleResponse = (response) => {
11668
+ const data = response.data;
11669
+ if (isErrorResponse(response)) {
11670
+ throw this.errorFromResponse(response);
11671
+ }
11672
+ return data;
11673
+ };
11548
11674
  this.dispatchEvent = (event) => {
11549
11675
  if (!event.received_at)
11550
11676
  event.received_at = new Date();
@@ -11572,10 +11698,119 @@ class StreamClient {
11572
11698
  listener(event);
11573
11699
  }
11574
11700
  };
11701
+ /**
11702
+ * @private
11703
+ */
11704
+ this.connect = () => __awaiter(this, void 0, void 0, function* () {
11705
+ if (!this.userID || !this._user) {
11706
+ throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11707
+ }
11708
+ if (!this.wsBaseURL) {
11709
+ throw Error('Websocket base url not set');
11710
+ }
11711
+ if (!this.clientID) {
11712
+ throw Error('clientID is not set');
11713
+ }
11714
+ if (!this.wsConnection &&
11715
+ (this.options.warmUp || this.options.enableInsights)) {
11716
+ this._sayHi();
11717
+ }
11718
+ // The StableWSConnection handles all the reconnection logic.
11719
+ if (this.options.wsConnection && this.node) {
11720
+ // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11721
+ this.options.wsConnection.setClient(this);
11722
+ this.wsConnection = this.options
11723
+ .wsConnection;
11724
+ }
11725
+ else {
11726
+ this.wsConnection = new StableWSConnection(this);
11727
+ }
11728
+ try {
11729
+ // if fallback is used before, continue using it instead of waiting for WS to fail
11730
+ if (this.wsFallback) {
11731
+ return yield this.wsFallback.connect();
11732
+ }
11733
+ this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11734
+ // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11735
+ return yield this.wsConnection.connect(this.options.enableWSFallback
11736
+ ? this.defaultWSTimeoutWithFallback
11737
+ : this.defaultWSTimeout);
11738
+ }
11739
+ catch (err) {
11740
+ // run fallback only if it's WS/Network error and not a normal API error
11741
+ // make sure browser is online before even trying the longpoll
11742
+ if (this.options.enableWSFallback &&
11743
+ // @ts-ignore
11744
+ isWSFailure(err) &&
11745
+ isOnline(this.logger)) {
11746
+ this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11747
+ this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11748
+ this.wsConnection._destroyCurrentWSConnection();
11749
+ this.wsConnection.disconnect().then(); // close WS so no retry
11750
+ this.wsFallback = new WSConnectionFallback(this);
11751
+ return yield this.wsFallback.connect();
11752
+ }
11753
+ throw err;
11754
+ }
11755
+ });
11756
+ /**
11757
+ * Check the connectivity with server for warmup purpose.
11758
+ *
11759
+ * @private
11760
+ */
11761
+ this._sayHi = () => {
11762
+ const client_request_id = randomId();
11763
+ const opts = {
11764
+ headers: axios.AxiosHeaders.from({
11765
+ 'x-client-request-id': client_request_id,
11766
+ }),
11767
+ };
11768
+ this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11769
+ if (this.options.enableInsights) {
11770
+ postInsights('http_hi_failed', {
11771
+ api_key: this.key,
11772
+ err: e,
11773
+ client_request_id,
11774
+ });
11775
+ }
11776
+ });
11777
+ };
11778
+ this.getUserAgent = () => {
11779
+ return (this.userAgent ||
11780
+ `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.40"}`);
11781
+ };
11782
+ this.setUserAgent = (userAgent) => {
11783
+ this.userAgent = userAgent;
11784
+ };
11575
11785
  /**
11576
11786
  * _isUsingServerAuth - Returns true if we're using server side auth
11577
11787
  */
11578
11788
  this._isUsingServerAuth = () => !!this.secret;
11789
+ this._enrichAxiosOptions = (options = {
11790
+ params: {},
11791
+ headers: {},
11792
+ config: {},
11793
+ }) => {
11794
+ var _a;
11795
+ const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11796
+ const authorization = token ? { Authorization: token } : undefined;
11797
+ let signal = null;
11798
+ if (this.nextRequestAbortController !== null) {
11799
+ signal = this.nextRequestAbortController.signal;
11800
+ this.nextRequestAbortController = null;
11801
+ }
11802
+ if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11803
+ options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11804
+ }
11805
+ return Object.assign(Object.assign(Object.assign({ params: Object.assign({ user_id: this.userID, connection_id: this._getConnectionID(), api_key: this.key }, options.params), headers: Object.assign(Object.assign(Object.assign({}, authorization), { 'stream-auth-type': options.publicEndpoint && !this.user
11806
+ ? 'anonymous'
11807
+ : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11808
+ };
11809
+ this._getToken = () => {
11810
+ if (!this.tokenManager)
11811
+ return null;
11812
+ return this.tokenManager.getToken();
11813
+ };
11579
11814
  /**
11580
11815
  * encode ws url payload
11581
11816
  * @private
@@ -11588,6 +11823,38 @@ class StreamClient {
11588
11823
  client_request_id,
11589
11824
  });
11590
11825
  };
11826
+ /**
11827
+ * creates an abort controller that will be used by the next HTTP Request.
11828
+ */
11829
+ this.createAbortControllerForNextRequest = () => {
11830
+ return (this.nextRequestAbortController = new AbortController());
11831
+ };
11832
+ /**
11833
+ * createToken - Creates a token to authenticate this user. This function is used server side.
11834
+ * The resulting token should be passed to the client side when the users registers or logs in.
11835
+ *
11836
+ * @param {string} userID The UserWithId ID
11837
+ * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11838
+ * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11839
+ *
11840
+ * @return {string} Returns a token
11841
+ */
11842
+ this.createToken = (userID, exp, iat, call_cids) => {
11843
+ if (this.secret == null) {
11844
+ throw Error(`tokens can only be created server-side using the API Secret`);
11845
+ }
11846
+ const extra = {};
11847
+ if (exp) {
11848
+ extra.exp = exp;
11849
+ }
11850
+ if (iat) {
11851
+ extra.iat = iat;
11852
+ }
11853
+ if (call_cids) {
11854
+ extra.call_cids = call_cids;
11855
+ }
11856
+ return JWTUserToken(this.secret, userID, extra, {});
11857
+ };
11591
11858
  // set the key
11592
11859
  this.key = key;
11593
11860
  this.listeners = {};
@@ -11639,268 +11906,6 @@ class StreamClient {
11639
11906
  ? inputOptions.logger
11640
11907
  : () => null;
11641
11908
  }
11642
- devToken(userID) {
11643
- return DevToken(userID);
11644
- }
11645
- getAuthType() {
11646
- return this.anonymous ? 'anonymous' : 'jwt';
11647
- }
11648
- setBaseURL(baseURL) {
11649
- this.baseURL = baseURL;
11650
- this.wsBaseURL = this.baseURL
11651
- .replace('http', 'ws')
11652
- .replace(':3030', ':8800');
11653
- }
11654
- _setUser(user) {
11655
- /**
11656
- * This one is used by the frontend. This is a copy of the current user object stored on backend.
11657
- * It contains reserved properties and own user properties which are not present in `this._user`.
11658
- */
11659
- this.user = user;
11660
- this.userID = user.id;
11661
- // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11662
- this._user = Object.assign({}, user);
11663
- }
11664
- /**
11665
- * on - Listen to events on all channels and users your watching
11666
- *
11667
- * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11668
- * or
11669
- * client.on(event => {console.log(event.type)})
11670
- *
11671
- * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11672
- * @param {EventHandler} [callbackOrNothing] The callback to call
11673
- *
11674
- * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11675
- */
11676
- on(callbackOrEventName, callbackOrNothing) {
11677
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11678
- const callback = callbackOrNothing
11679
- ? callbackOrNothing
11680
- : callbackOrEventName;
11681
- if (!(key in this.listeners)) {
11682
- this.listeners[key] = [];
11683
- }
11684
- this.listeners[key].push(callback);
11685
- return () => {
11686
- this.off(key, callback);
11687
- };
11688
- }
11689
- /**
11690
- * off - Remove the event handler
11691
- *
11692
- */
11693
- off(callbackOrEventName, callbackOrNothing) {
11694
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11695
- const callback = callbackOrNothing
11696
- ? callbackOrNothing
11697
- : callbackOrEventName;
11698
- if (!(key in this.listeners)) {
11699
- this.listeners[key] = [];
11700
- }
11701
- this.logger('debug', `Removing listener for ${key} event`);
11702
- this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11703
- }
11704
- _logApiRequest(type, url, data, config) {
11705
- this.logger('trace', `client: ${type} - Request - ${url}`, {
11706
- payload: data,
11707
- config,
11708
- });
11709
- }
11710
- _logApiResponse(type, url, response) {
11711
- this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11712
- response,
11713
- });
11714
- this.logger('trace', `client:${type} - Response payload`, {
11715
- response,
11716
- });
11717
- }
11718
- _logApiError(type, url, error) {
11719
- this.logger('error', `client:${type} - Error - url: ${url}`, {
11720
- url,
11721
- error,
11722
- });
11723
- }
11724
- get(url, params) {
11725
- return this.doAxiosRequest('get', url, null, {
11726
- params,
11727
- });
11728
- }
11729
- put(url, data) {
11730
- return this.doAxiosRequest('put', url, data);
11731
- }
11732
- post(url, data) {
11733
- return this.doAxiosRequest('post', url, data);
11734
- }
11735
- patch(url, data) {
11736
- return this.doAxiosRequest('patch', url, data);
11737
- }
11738
- delete(url, params) {
11739
- return this.doAxiosRequest('delete', url, null, {
11740
- params,
11741
- });
11742
- }
11743
- errorFromResponse(response) {
11744
- let err;
11745
- err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11746
- if (response.data && response.data.code) {
11747
- err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11748
- err.code = response.data.code;
11749
- }
11750
- err.response = response;
11751
- err.status = response.status;
11752
- return err;
11753
- }
11754
- handleResponse(response) {
11755
- const data = response.data;
11756
- if (isErrorResponse(response)) {
11757
- throw this.errorFromResponse(response);
11758
- }
11759
- return data;
11760
- }
11761
- /**
11762
- * @private
11763
- */
11764
- connect() {
11765
- return __awaiter(this, void 0, void 0, function* () {
11766
- if (!this.userID || !this._user) {
11767
- throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11768
- }
11769
- if (!this.wsBaseURL) {
11770
- throw Error('Websocket base url not set');
11771
- }
11772
- if (!this.clientID) {
11773
- throw Error('clientID is not set');
11774
- }
11775
- if (!this.wsConnection &&
11776
- (this.options.warmUp || this.options.enableInsights)) {
11777
- this._sayHi();
11778
- }
11779
- // The StableWSConnection handles all the reconnection logic.
11780
- if (this.options.wsConnection && this.node) {
11781
- // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11782
- this.options.wsConnection.setClient(this);
11783
- this.wsConnection = this.options
11784
- .wsConnection;
11785
- }
11786
- else {
11787
- this.wsConnection = new StableWSConnection(this);
11788
- }
11789
- try {
11790
- // if fallback is used before, continue using it instead of waiting for WS to fail
11791
- if (this.wsFallback) {
11792
- return yield this.wsFallback.connect();
11793
- }
11794
- this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11795
- // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11796
- return yield this.wsConnection.connect(this.options.enableWSFallback
11797
- ? this.defaultWSTimeoutWithFallback
11798
- : this.defaultWSTimeout);
11799
- }
11800
- catch (err) {
11801
- // run fallback only if it's WS/Network error and not a normal API error
11802
- // make sure browser is online before even trying the longpoll
11803
- if (this.options.enableWSFallback &&
11804
- // @ts-ignore
11805
- isWSFailure(err) &&
11806
- isOnline(this.logger)) {
11807
- this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11808
- this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11809
- this.wsConnection._destroyCurrentWSConnection();
11810
- this.wsConnection.disconnect().then(); // close WS so no retry
11811
- this.wsFallback = new WSConnectionFallback(this);
11812
- return yield this.wsFallback.connect();
11813
- }
11814
- throw err;
11815
- }
11816
- });
11817
- }
11818
- /**
11819
- * Check the connectivity with server for warmup purpose.
11820
- *
11821
- * @private
11822
- */
11823
- _sayHi() {
11824
- const client_request_id = randomId();
11825
- const opts = {
11826
- headers: axios.AxiosHeaders.from({
11827
- 'x-client-request-id': client_request_id,
11828
- }),
11829
- };
11830
- this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11831
- if (this.options.enableInsights) {
11832
- postInsights('http_hi_failed', {
11833
- api_key: this.key,
11834
- err: e,
11835
- client_request_id,
11836
- });
11837
- }
11838
- });
11839
- }
11840
- getUserAgent() {
11841
- return (this.userAgent ||
11842
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.38"}`);
11843
- }
11844
- setUserAgent(userAgent) {
11845
- this.userAgent = userAgent;
11846
- }
11847
- _enrichAxiosOptions(options = {
11848
- params: {},
11849
- headers: {},
11850
- config: {},
11851
- }) {
11852
- var _a;
11853
- const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11854
- const authorization = token ? { Authorization: token } : undefined;
11855
- let signal = null;
11856
- if (this.nextRequestAbortController !== null) {
11857
- signal = this.nextRequestAbortController.signal;
11858
- this.nextRequestAbortController = null;
11859
- }
11860
- if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11861
- options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11862
- }
11863
- return Object.assign(Object.assign(Object.assign({ params: Object.assign({ user_id: this.userID, connection_id: this._getConnectionID(), api_key: this.key }, options.params), headers: Object.assign(Object.assign(Object.assign({}, authorization), { 'stream-auth-type': options.publicEndpoint && !this.user
11864
- ? 'anonymous'
11865
- : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11866
- }
11867
- _getToken() {
11868
- if (!this.tokenManager)
11869
- return null;
11870
- return this.tokenManager.getToken();
11871
- }
11872
- /**
11873
- * creates an abort controller that will be used by the next HTTP Request.
11874
- */
11875
- createAbortControllerForNextRequest() {
11876
- return (this.nextRequestAbortController = new AbortController());
11877
- }
11878
- /**
11879
- * createToken - Creates a token to authenticate this user. This function is used server side.
11880
- * The resulting token should be passed to the client side when the users registers or logs in.
11881
- *
11882
- * @param {string} userID The UserWithId ID
11883
- * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11884
- * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11885
- *
11886
- * @return {string} Returns a token
11887
- */
11888
- createToken(userID, exp, iat, call_cids) {
11889
- if (this.secret == null) {
11890
- throw Error(`tokens can only be created server-side using the API Secret`);
11891
- }
11892
- const extra = {};
11893
- if (exp) {
11894
- extra.exp = exp;
11895
- }
11896
- if (iat) {
11897
- extra.iat = iat;
11898
- }
11899
- if (call_cids) {
11900
- extra.call_cids = call_cids;
11901
- }
11902
- return JWTUserToken(this.secret, userID, extra, {});
11903
- }
11904
11909
  }
11905
11910
 
11906
11911
  /**
@@ -12197,7 +12202,7 @@ class StreamVideoClient {
12197
12202
  return;
12198
12203
  const { call, members } = event;
12199
12204
  if (userToConnect.id === call.created_by.id) {
12200
- this.logger('warn', 'Received `call.ring` sent by the current user');
12205
+ this.logger('debug', 'Received `call.ring` sent by the current user so ignoring the event');
12201
12206
  return;
12202
12207
  }
12203
12208
  // The call might already be tracked by the client,