@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.
@@ -6280,7 +6280,7 @@ class Publisher {
6280
6280
  this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
6281
6281
  const { candidate } = e;
6282
6282
  if (!candidate) {
6283
- this.logger('warn', 'null ice candidate');
6283
+ this.logger('debug', 'null ice candidate');
6284
6284
  return;
6285
6285
  }
6286
6286
  yield this.sfuClient.iceTrickle({
@@ -6440,10 +6440,10 @@ class Publisher {
6440
6440
  this.logger('error', `ICE Candidate error`, errorMessage);
6441
6441
  };
6442
6442
  this.onIceConnectionStateChange = () => {
6443
- this.logger('error', `ICE Connection state changed`, this.pc.iceConnectionState);
6443
+ this.logger('debug', `ICE Connection state changed`, this.pc.iceConnectionState);
6444
6444
  };
6445
6445
  this.onIceGatheringStateChange = () => {
6446
- this.logger('error', `ICE Gathering State`, this.pc.iceGatheringState);
6446
+ this.logger('debug', `ICE Gathering State`, this.pc.iceGatheringState);
6447
6447
  };
6448
6448
  this.onSignalingStateChange = () => {
6449
6449
  this.logger('debug', `Signaling state changed`, this.pc.signalingState);
@@ -6610,7 +6610,7 @@ class Subscriber {
6610
6610
  this.onIceCandidate = (e) => __awaiter(this, void 0, void 0, function* () {
6611
6611
  const { candidate } = e;
6612
6612
  if (!candidate) {
6613
- logger$1('warn', 'null ice candidate');
6613
+ logger$1('debug', 'null ice candidate');
6614
6614
  return;
6615
6615
  }
6616
6616
  yield this.sfuClient.iceTrickle({
@@ -6845,7 +6845,7 @@ class StreamSfuClient {
6845
6845
  * from this SFU.
6846
6846
  */
6847
6847
  this.isMigratingAway = false;
6848
- this.pingIntervalInMs = 25 * 1000;
6848
+ this.pingIntervalInMs = 10 * 1000;
6849
6849
  this.unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
6850
6850
  this.close = (code = 1000, reason = 'Requested signal connection close') => {
6851
6851
  this.signalWs.close(code, reason);
@@ -6919,7 +6919,7 @@ class StreamSfuClient {
6919
6919
  if (this.lastMessageTimestamp) {
6920
6920
  const timeSinceLastMessage = new Date().getTime() - this.lastMessageTimestamp.getTime();
6921
6921
  if (timeSinceLastMessage > this.unhealthyTimeoutInMs) {
6922
- this.logger('error', 'SFU connection unhealthy, closing');
6922
+ this.logger('debug', 'SFU connection unhealthy, closing');
6923
6923
  this.close(4001, `SFU connection unhealthy. Didn't receive any healthcheck messages for ${this.unhealthyTimeoutInMs}ms`);
6924
6924
  }
6925
6925
  }
@@ -8026,6 +8026,16 @@ const watchParticipantCountChanged = (dispatcher, state) => {
8026
8026
  }
8027
8027
  });
8028
8028
  };
8029
+ const watchLiveEnded = (dispatcher, call) => {
8030
+ return dispatcher.on('error', (e) => {
8031
+ if (e.eventPayload.oneofKind !== 'error' ||
8032
+ !e.eventPayload.error.error ||
8033
+ e.eventPayload.error.error.code !== ErrorCode.LIVE_ENDED)
8034
+ return;
8035
+ if (!call.permissionsContext.hasPermission(OwnCapability.JOIN_BACKSTAGE))
8036
+ call.leave();
8037
+ });
8038
+ };
8029
8039
  /**
8030
8040
  * Watches and logs the errors reported by the currently connected SFU.
8031
8041
  */
@@ -8415,6 +8425,7 @@ const registerEventHandlers = (call, state, dispatcher) => {
8415
8425
  'call.user_muted': () => console.log('call.user_muted received'),
8416
8426
  };
8417
8427
  const eventHandlers = [
8428
+ watchLiveEnded(dispatcher, call),
8418
8429
  watchSfuErrorReports(dispatcher),
8419
8430
  watchChangePublishQuality(dispatcher, call),
8420
8431
  watchConnectionQualityChanged(dispatcher, state),
@@ -8673,7 +8684,7 @@ const createStatsReporter = ({ subscriber, publisher, state, pollingIntervalInMs
8673
8684
  if (pollingIntervalInMs > 0) {
8674
8685
  const loop = () => __awaiter(void 0, void 0, void 0, function* () {
8675
8686
  yield run().catch((e) => {
8676
- logger('warn', 'Failed to collect stats', e);
8687
+ logger('debug', 'Failed to collect stats', e);
8677
8688
  });
8678
8689
  timeoutId = setTimeout(loop, pollingIntervalInMs);
8679
8690
  });
@@ -9081,13 +9092,6 @@ const getClientDetails = () => {
9081
9092
  * An object representation of a `Call`.
9082
9093
  */
9083
9094
  class Call {
9084
- /**
9085
- * A promise that exposes the reconnection logic
9086
- * The use-case is for the react-native platform where online/offline events are not available in the window
9087
- */
9088
- get rejoin() {
9089
- return this.rejoinPromise;
9090
- }
9091
9095
  /**
9092
9096
  * Constructs a new `Call` instance.
9093
9097
  *
@@ -9133,7 +9137,6 @@ class Call {
9133
9137
  if (callingState === CallingState.LEFT) {
9134
9138
  throw new Error('Cannot leave call that has already been left.');
9135
9139
  }
9136
- this.rejoinPromise = undefined;
9137
9140
  if (this.ringing) {
9138
9141
  // I'm the one who started the call, so I should cancel it.
9139
9142
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
@@ -9337,7 +9340,7 @@ class Call {
9337
9340
  // we shouldn't be republishing the streams if we're migrating
9338
9341
  // as the underlying peer connection will take care of it as part
9339
9342
  // of the ice-restart process
9340
- if (localParticipant && !isReactNative() && !migrate) {
9343
+ if (localParticipant && !migrate) {
9341
9344
  const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
9342
9345
  // restore previous publishing state
9343
9346
  if (audioStream)
@@ -9349,7 +9352,6 @@ class Call {
9349
9352
  }
9350
9353
  this.logger('info', `[Rejoin]: State restored. Attempt: ${this.reconnectAttempts}`);
9351
9354
  });
9352
- this.rejoinPromise = rejoin;
9353
9355
  // reconnect if the connection was closed unexpectedly. example:
9354
9356
  // - SFU crash or restart
9355
9357
  // - network change
@@ -9382,9 +9384,6 @@ class Call {
9382
9384
  if (e.code === KnownCodes.WS_CLOSED_ABRUPTLY &&
9383
9385
  sfuClient.isMigratingAway)
9384
9386
  return;
9385
- // do nothing for react-native as it is handled by SDK
9386
- if (isReactNative())
9387
- return;
9388
9387
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
9389
9388
  rejoin().catch((err) => {
9390
9389
  this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
@@ -9398,28 +9397,34 @@ class Call {
9398
9397
  });
9399
9398
  });
9400
9399
  // handlers for connection online/offline events
9401
- // Note: window.addEventListener is not available in React Native, hence the check
9402
- if (typeof window !== 'undefined' && window.addEventListener) {
9403
- const handleOnOffline = () => {
9404
- window.removeEventListener('offline', handleOnOffline);
9405
- this.logger('warn', '[Rejoin]: Going offline...');
9406
- this.state.setCallingState(CallingState.OFFLINE);
9407
- };
9408
- const handleOnOnline = () => {
9409
- window.removeEventListener('online', handleOnOnline);
9410
- if (this.state.callingState === CallingState.OFFLINE) {
9411
- this.logger('info', '[Rejoin]: Going online...');
9412
- rejoin().catch((err) => {
9413
- this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9414
- this.state.setCallingState(CallingState.RECONNECTING_FAILED);
9415
- });
9416
- }
9417
- };
9418
- window.addEventListener('offline', handleOnOffline);
9419
- window.addEventListener('online', handleOnOnline);
9420
- // register cleanup hooks
9421
- this.leaveCallHooks.push(() => window.removeEventListener('offline', handleOnOffline), () => window.removeEventListener('online', handleOnOnline));
9422
- }
9400
+ const unsubscribeOnlineEvent = this.streamClient.on('connection.changed', (e) => {
9401
+ if (e.type !== 'connection.changed')
9402
+ return;
9403
+ if (!e.online)
9404
+ return;
9405
+ unsubscribeOnlineEvent();
9406
+ const currentCallingState = this.state.callingState;
9407
+ if (currentCallingState === CallingState.OFFLINE ||
9408
+ currentCallingState === CallingState.RECONNECTING_FAILED) {
9409
+ this.logger('info', '[Rejoin]: Going online...');
9410
+ rejoin().catch((err) => {
9411
+ this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9412
+ this.state.setCallingState(CallingState.RECONNECTING_FAILED);
9413
+ });
9414
+ }
9415
+ });
9416
+ const unsubscribeOfflineEvent = this.streamClient.on('connection.changed', (e) => {
9417
+ if (e.type !== 'connection.changed')
9418
+ return;
9419
+ if (e.online)
9420
+ return;
9421
+ unsubscribeOfflineEvent();
9422
+ this.state.setCallingState(CallingState.OFFLINE);
9423
+ });
9424
+ this.leaveCallHooks.push(() => {
9425
+ unsubscribeOnlineEvent();
9426
+ unsubscribeOfflineEvent();
9427
+ });
9423
9428
  if (!this.subscriber) {
9424
9429
  this.subscriber = new Subscriber({
9425
9430
  sfuClient,
@@ -10270,6 +10275,9 @@ const isErrorEvent = (res) => res.error !== undefined;
10270
10275
  */
10271
10276
  class StableWSConnection {
10272
10277
  constructor(client) {
10278
+ this._log = (msg, extra = {}, level = 'info') => {
10279
+ this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10280
+ };
10273
10281
  this.setClient = (client) => {
10274
10282
  this.client = client;
10275
10283
  };
@@ -10298,7 +10306,8 @@ class StableWSConnection {
10298
10306
  if (event.type === 'offline') {
10299
10307
  // mark the connection as down
10300
10308
  this._log('onlineStatusChanged() - Status changing to offline');
10301
- this._setHealth(false);
10309
+ // we know that the app is offline so dispatch the unhealthy connection event immediately
10310
+ this._setHealth(false, true);
10302
10311
  }
10303
10312
  else if (event.type === 'online') {
10304
10313
  // retry right now...
@@ -10426,13 +10435,14 @@ class StableWSConnection {
10426
10435
  * Broadcasts an event in case the connection status changed.
10427
10436
  *
10428
10437
  * @param {boolean} healthy boolean indicating if the connection is healthy or not
10438
+ * @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
10429
10439
  *
10430
10440
  */
10431
- this._setHealth = (healthy) => {
10441
+ this._setHealth = (healthy, dispatchImmediately = false) => {
10432
10442
  if (healthy === this.isHealthy)
10433
10443
  return;
10434
10444
  this.isHealthy = healthy;
10435
- if (this.isHealthy) {
10445
+ if (this.isHealthy || dispatchImmediately) {
10436
10446
  this.client.dispatchEvent({
10437
10447
  type: 'connection.changed',
10438
10448
  online: this.isHealthy,
@@ -10554,9 +10564,6 @@ class StableWSConnection {
10554
10564
  this.connectionCheckTimeout = this.pingInterval + 10 * 1000;
10555
10565
  addConnectionEventListeners(this.onlineStatusChanged);
10556
10566
  }
10557
- _log(msg, extra = {}, level = 'info') {
10558
- this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10559
- }
10560
10567
  /**
10561
10568
  * connect - Connect to the WS URL
10562
10569
  * the default 15s timeout allows between 2~3 tries
@@ -11305,6 +11312,18 @@ class StreamClient {
11305
11312
  constructor(key, options) {
11306
11313
  var _a;
11307
11314
  this.nextRequestAbortController = null;
11315
+ this.devToken = (userID) => {
11316
+ return DevToken(userID);
11317
+ };
11318
+ this.getAuthType = () => {
11319
+ return this.anonymous ? 'anonymous' : 'jwt';
11320
+ };
11321
+ this.setBaseURL = (baseURL) => {
11322
+ this.baseURL = baseURL;
11323
+ this.wsBaseURL = this.baseURL
11324
+ .replace('http', 'ws')
11325
+ .replace(':3030', ':8800');
11326
+ };
11308
11327
  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); };
11309
11328
  this._hasConnectionID = () => Boolean(this._getConnectionID());
11310
11329
  /**
@@ -11369,6 +11388,16 @@ class StreamClient {
11369
11388
  }
11370
11389
  });
11371
11390
  this._setToken = (user, userTokenOrProvider, isAnonymous) => this.tokenManager.setTokenOrProvider(userTokenOrProvider, user, isAnonymous);
11391
+ this._setUser = (user) => {
11392
+ /**
11393
+ * This one is used by the frontend. This is a copy of the current user object stored on backend.
11394
+ * It contains reserved properties and own user properties which are not present in `this._user`.
11395
+ */
11396
+ this.user = user;
11397
+ this.userID = user.id;
11398
+ // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11399
+ this._user = Object.assign({}, user);
11400
+ };
11372
11401
  /**
11373
11402
  * Disconnects the websocket connection, without removing the user set on client.
11374
11403
  * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need
@@ -11457,6 +11486,66 @@ class StreamClient {
11457
11486
  // resolve the connection_id here.
11458
11487
  this.resolveConnectionId();
11459
11488
  });
11489
+ /**
11490
+ * on - Listen to events on all channels and users your watching
11491
+ *
11492
+ * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11493
+ * or
11494
+ * client.on(event => {console.log(event.type)})
11495
+ *
11496
+ * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11497
+ * @param {EventHandler} [callbackOrNothing] The callback to call
11498
+ *
11499
+ * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11500
+ */
11501
+ this.on = (callbackOrEventName, callbackOrNothing) => {
11502
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11503
+ const callback = callbackOrNothing
11504
+ ? callbackOrNothing
11505
+ : callbackOrEventName;
11506
+ if (!(key in this.listeners)) {
11507
+ this.listeners[key] = [];
11508
+ }
11509
+ this.listeners[key].push(callback);
11510
+ return () => {
11511
+ this.off(key, callback);
11512
+ };
11513
+ };
11514
+ /**
11515
+ * off - Remove the event handler
11516
+ *
11517
+ */
11518
+ this.off = (callbackOrEventName, callbackOrNothing) => {
11519
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11520
+ const callback = callbackOrNothing
11521
+ ? callbackOrNothing
11522
+ : callbackOrEventName;
11523
+ if (!(key in this.listeners)) {
11524
+ this.listeners[key] = [];
11525
+ }
11526
+ this.logger('debug', `Removing listener for ${key} event`);
11527
+ this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11528
+ };
11529
+ this._logApiRequest = (type, url, data, config) => {
11530
+ this.logger('trace', `client: ${type} - Request - ${url}`, {
11531
+ payload: data,
11532
+ config,
11533
+ });
11534
+ };
11535
+ this._logApiResponse = (type, url, response) => {
11536
+ this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11537
+ response,
11538
+ });
11539
+ this.logger('trace', `client:${type} - Response payload`, {
11540
+ response,
11541
+ });
11542
+ };
11543
+ this._logApiError = (type, url, error) => {
11544
+ this.logger('error', `client:${type} - Error - url: ${url}`, {
11545
+ url,
11546
+ error,
11547
+ });
11548
+ };
11460
11549
  this.doAxiosRequest = (type, url, data, options = {}) => __awaiter(this, void 0, void 0, function* () {
11461
11550
  var _g;
11462
11551
  if (!options.publicEndpoint || this.user) {
@@ -11521,6 +11610,43 @@ class StreamClient {
11521
11610
  }
11522
11611
  }
11523
11612
  });
11613
+ this.get = (url, params) => {
11614
+ return this.doAxiosRequest('get', url, null, {
11615
+ params,
11616
+ });
11617
+ };
11618
+ this.put = (url, data) => {
11619
+ return this.doAxiosRequest('put', url, data);
11620
+ };
11621
+ this.post = (url, data) => {
11622
+ return this.doAxiosRequest('post', url, data);
11623
+ };
11624
+ this.patch = (url, data) => {
11625
+ return this.doAxiosRequest('patch', url, data);
11626
+ };
11627
+ this.delete = (url, params) => {
11628
+ return this.doAxiosRequest('delete', url, null, {
11629
+ params,
11630
+ });
11631
+ };
11632
+ this.errorFromResponse = (response) => {
11633
+ let err;
11634
+ err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11635
+ if (response.data && response.data.code) {
11636
+ err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11637
+ err.code = response.data.code;
11638
+ }
11639
+ err.response = response;
11640
+ err.status = response.status;
11641
+ return err;
11642
+ };
11643
+ this.handleResponse = (response) => {
11644
+ const data = response.data;
11645
+ if (isErrorResponse(response)) {
11646
+ throw this.errorFromResponse(response);
11647
+ }
11648
+ return data;
11649
+ };
11524
11650
  this.dispatchEvent = (event) => {
11525
11651
  if (!event.received_at)
11526
11652
  event.received_at = new Date();
@@ -11548,10 +11674,119 @@ class StreamClient {
11548
11674
  listener(event);
11549
11675
  }
11550
11676
  };
11677
+ /**
11678
+ * @private
11679
+ */
11680
+ this.connect = () => __awaiter(this, void 0, void 0, function* () {
11681
+ if (!this.userID || !this._user) {
11682
+ throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11683
+ }
11684
+ if (!this.wsBaseURL) {
11685
+ throw Error('Websocket base url not set');
11686
+ }
11687
+ if (!this.clientID) {
11688
+ throw Error('clientID is not set');
11689
+ }
11690
+ if (!this.wsConnection &&
11691
+ (this.options.warmUp || this.options.enableInsights)) {
11692
+ this._sayHi();
11693
+ }
11694
+ // The StableWSConnection handles all the reconnection logic.
11695
+ if (this.options.wsConnection && this.node) {
11696
+ // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11697
+ this.options.wsConnection.setClient(this);
11698
+ this.wsConnection = this.options
11699
+ .wsConnection;
11700
+ }
11701
+ else {
11702
+ this.wsConnection = new StableWSConnection(this);
11703
+ }
11704
+ try {
11705
+ // if fallback is used before, continue using it instead of waiting for WS to fail
11706
+ if (this.wsFallback) {
11707
+ return yield this.wsFallback.connect();
11708
+ }
11709
+ this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11710
+ // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11711
+ return yield this.wsConnection.connect(this.options.enableWSFallback
11712
+ ? this.defaultWSTimeoutWithFallback
11713
+ : this.defaultWSTimeout);
11714
+ }
11715
+ catch (err) {
11716
+ // run fallback only if it's WS/Network error and not a normal API error
11717
+ // make sure browser is online before even trying the longpoll
11718
+ if (this.options.enableWSFallback &&
11719
+ // @ts-ignore
11720
+ isWSFailure(err) &&
11721
+ isOnline(this.logger)) {
11722
+ this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11723
+ this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11724
+ this.wsConnection._destroyCurrentWSConnection();
11725
+ this.wsConnection.disconnect().then(); // close WS so no retry
11726
+ this.wsFallback = new WSConnectionFallback(this);
11727
+ return yield this.wsFallback.connect();
11728
+ }
11729
+ throw err;
11730
+ }
11731
+ });
11732
+ /**
11733
+ * Check the connectivity with server for warmup purpose.
11734
+ *
11735
+ * @private
11736
+ */
11737
+ this._sayHi = () => {
11738
+ const client_request_id = randomId();
11739
+ const opts = {
11740
+ headers: AxiosHeaders.from({
11741
+ 'x-client-request-id': client_request_id,
11742
+ }),
11743
+ };
11744
+ this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11745
+ if (this.options.enableInsights) {
11746
+ postInsights('http_hi_failed', {
11747
+ api_key: this.key,
11748
+ err: e,
11749
+ client_request_id,
11750
+ });
11751
+ }
11752
+ });
11753
+ };
11754
+ this.getUserAgent = () => {
11755
+ return (this.userAgent ||
11756
+ `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.40"}`);
11757
+ };
11758
+ this.setUserAgent = (userAgent) => {
11759
+ this.userAgent = userAgent;
11760
+ };
11551
11761
  /**
11552
11762
  * _isUsingServerAuth - Returns true if we're using server side auth
11553
11763
  */
11554
11764
  this._isUsingServerAuth = () => !!this.secret;
11765
+ this._enrichAxiosOptions = (options = {
11766
+ params: {},
11767
+ headers: {},
11768
+ config: {},
11769
+ }) => {
11770
+ var _a;
11771
+ const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11772
+ const authorization = token ? { Authorization: token } : undefined;
11773
+ let signal = null;
11774
+ if (this.nextRequestAbortController !== null) {
11775
+ signal = this.nextRequestAbortController.signal;
11776
+ this.nextRequestAbortController = null;
11777
+ }
11778
+ if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11779
+ options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11780
+ }
11781
+ 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
11782
+ ? 'anonymous'
11783
+ : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11784
+ };
11785
+ this._getToken = () => {
11786
+ if (!this.tokenManager)
11787
+ return null;
11788
+ return this.tokenManager.getToken();
11789
+ };
11555
11790
  /**
11556
11791
  * encode ws url payload
11557
11792
  * @private
@@ -11564,6 +11799,38 @@ class StreamClient {
11564
11799
  client_request_id,
11565
11800
  });
11566
11801
  };
11802
+ /**
11803
+ * creates an abort controller that will be used by the next HTTP Request.
11804
+ */
11805
+ this.createAbortControllerForNextRequest = () => {
11806
+ return (this.nextRequestAbortController = new AbortController());
11807
+ };
11808
+ /**
11809
+ * createToken - Creates a token to authenticate this user. This function is used server side.
11810
+ * The resulting token should be passed to the client side when the users registers or logs in.
11811
+ *
11812
+ * @param {string} userID The UserWithId ID
11813
+ * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11814
+ * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11815
+ *
11816
+ * @return {string} Returns a token
11817
+ */
11818
+ this.createToken = (userID, exp, iat, call_cids) => {
11819
+ if (this.secret == null) {
11820
+ throw Error(`tokens can only be created server-side using the API Secret`);
11821
+ }
11822
+ const extra = {};
11823
+ if (exp) {
11824
+ extra.exp = exp;
11825
+ }
11826
+ if (iat) {
11827
+ extra.iat = iat;
11828
+ }
11829
+ if (call_cids) {
11830
+ extra.call_cids = call_cids;
11831
+ }
11832
+ return JWTUserToken(this.secret, userID, extra, {});
11833
+ };
11567
11834
  // set the key
11568
11835
  this.key = key;
11569
11836
  this.listeners = {};
@@ -11615,268 +11882,6 @@ class StreamClient {
11615
11882
  ? inputOptions.logger
11616
11883
  : () => null;
11617
11884
  }
11618
- devToken(userID) {
11619
- return DevToken(userID);
11620
- }
11621
- getAuthType() {
11622
- return this.anonymous ? 'anonymous' : 'jwt';
11623
- }
11624
- setBaseURL(baseURL) {
11625
- this.baseURL = baseURL;
11626
- this.wsBaseURL = this.baseURL
11627
- .replace('http', 'ws')
11628
- .replace(':3030', ':8800');
11629
- }
11630
- _setUser(user) {
11631
- /**
11632
- * This one is used by the frontend. This is a copy of the current user object stored on backend.
11633
- * It contains reserved properties and own user properties which are not present in `this._user`.
11634
- */
11635
- this.user = user;
11636
- this.userID = user.id;
11637
- // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11638
- this._user = Object.assign({}, user);
11639
- }
11640
- /**
11641
- * on - Listen to events on all channels and users your watching
11642
- *
11643
- * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11644
- * or
11645
- * client.on(event => {console.log(event.type)})
11646
- *
11647
- * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11648
- * @param {EventHandler} [callbackOrNothing] The callback to call
11649
- *
11650
- * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11651
- */
11652
- on(callbackOrEventName, callbackOrNothing) {
11653
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11654
- const callback = callbackOrNothing
11655
- ? callbackOrNothing
11656
- : callbackOrEventName;
11657
- if (!(key in this.listeners)) {
11658
- this.listeners[key] = [];
11659
- }
11660
- this.listeners[key].push(callback);
11661
- return () => {
11662
- this.off(key, callback);
11663
- };
11664
- }
11665
- /**
11666
- * off - Remove the event handler
11667
- *
11668
- */
11669
- off(callbackOrEventName, callbackOrNothing) {
11670
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11671
- const callback = callbackOrNothing
11672
- ? callbackOrNothing
11673
- : callbackOrEventName;
11674
- if (!(key in this.listeners)) {
11675
- this.listeners[key] = [];
11676
- }
11677
- this.logger('debug', `Removing listener for ${key} event`);
11678
- this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11679
- }
11680
- _logApiRequest(type, url, data, config) {
11681
- this.logger('trace', `client: ${type} - Request - ${url}`, {
11682
- payload: data,
11683
- config,
11684
- });
11685
- }
11686
- _logApiResponse(type, url, response) {
11687
- this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11688
- response,
11689
- });
11690
- this.logger('trace', `client:${type} - Response payload`, {
11691
- response,
11692
- });
11693
- }
11694
- _logApiError(type, url, error) {
11695
- this.logger('error', `client:${type} - Error - url: ${url}`, {
11696
- url,
11697
- error,
11698
- });
11699
- }
11700
- get(url, params) {
11701
- return this.doAxiosRequest('get', url, null, {
11702
- params,
11703
- });
11704
- }
11705
- put(url, data) {
11706
- return this.doAxiosRequest('put', url, data);
11707
- }
11708
- post(url, data) {
11709
- return this.doAxiosRequest('post', url, data);
11710
- }
11711
- patch(url, data) {
11712
- return this.doAxiosRequest('patch', url, data);
11713
- }
11714
- delete(url, params) {
11715
- return this.doAxiosRequest('delete', url, null, {
11716
- params,
11717
- });
11718
- }
11719
- errorFromResponse(response) {
11720
- let err;
11721
- err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11722
- if (response.data && response.data.code) {
11723
- err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11724
- err.code = response.data.code;
11725
- }
11726
- err.response = response;
11727
- err.status = response.status;
11728
- return err;
11729
- }
11730
- handleResponse(response) {
11731
- const data = response.data;
11732
- if (isErrorResponse(response)) {
11733
- throw this.errorFromResponse(response);
11734
- }
11735
- return data;
11736
- }
11737
- /**
11738
- * @private
11739
- */
11740
- connect() {
11741
- return __awaiter(this, void 0, void 0, function* () {
11742
- if (!this.userID || !this._user) {
11743
- throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11744
- }
11745
- if (!this.wsBaseURL) {
11746
- throw Error('Websocket base url not set');
11747
- }
11748
- if (!this.clientID) {
11749
- throw Error('clientID is not set');
11750
- }
11751
- if (!this.wsConnection &&
11752
- (this.options.warmUp || this.options.enableInsights)) {
11753
- this._sayHi();
11754
- }
11755
- // The StableWSConnection handles all the reconnection logic.
11756
- if (this.options.wsConnection && this.node) {
11757
- // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11758
- this.options.wsConnection.setClient(this);
11759
- this.wsConnection = this.options
11760
- .wsConnection;
11761
- }
11762
- else {
11763
- this.wsConnection = new StableWSConnection(this);
11764
- }
11765
- try {
11766
- // if fallback is used before, continue using it instead of waiting for WS to fail
11767
- if (this.wsFallback) {
11768
- return yield this.wsFallback.connect();
11769
- }
11770
- this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11771
- // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11772
- return yield this.wsConnection.connect(this.options.enableWSFallback
11773
- ? this.defaultWSTimeoutWithFallback
11774
- : this.defaultWSTimeout);
11775
- }
11776
- catch (err) {
11777
- // run fallback only if it's WS/Network error and not a normal API error
11778
- // make sure browser is online before even trying the longpoll
11779
- if (this.options.enableWSFallback &&
11780
- // @ts-ignore
11781
- isWSFailure(err) &&
11782
- isOnline(this.logger)) {
11783
- this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11784
- this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11785
- this.wsConnection._destroyCurrentWSConnection();
11786
- this.wsConnection.disconnect().then(); // close WS so no retry
11787
- this.wsFallback = new WSConnectionFallback(this);
11788
- return yield this.wsFallback.connect();
11789
- }
11790
- throw err;
11791
- }
11792
- });
11793
- }
11794
- /**
11795
- * Check the connectivity with server for warmup purpose.
11796
- *
11797
- * @private
11798
- */
11799
- _sayHi() {
11800
- const client_request_id = randomId();
11801
- const opts = {
11802
- headers: AxiosHeaders.from({
11803
- 'x-client-request-id': client_request_id,
11804
- }),
11805
- };
11806
- this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11807
- if (this.options.enableInsights) {
11808
- postInsights('http_hi_failed', {
11809
- api_key: this.key,
11810
- err: e,
11811
- client_request_id,
11812
- });
11813
- }
11814
- });
11815
- }
11816
- getUserAgent() {
11817
- return (this.userAgent ||
11818
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.38"}`);
11819
- }
11820
- setUserAgent(userAgent) {
11821
- this.userAgent = userAgent;
11822
- }
11823
- _enrichAxiosOptions(options = {
11824
- params: {},
11825
- headers: {},
11826
- config: {},
11827
- }) {
11828
- var _a;
11829
- const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11830
- const authorization = token ? { Authorization: token } : undefined;
11831
- let signal = null;
11832
- if (this.nextRequestAbortController !== null) {
11833
- signal = this.nextRequestAbortController.signal;
11834
- this.nextRequestAbortController = null;
11835
- }
11836
- if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11837
- options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11838
- }
11839
- 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
11840
- ? 'anonymous'
11841
- : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11842
- }
11843
- _getToken() {
11844
- if (!this.tokenManager)
11845
- return null;
11846
- return this.tokenManager.getToken();
11847
- }
11848
- /**
11849
- * creates an abort controller that will be used by the next HTTP Request.
11850
- */
11851
- createAbortControllerForNextRequest() {
11852
- return (this.nextRequestAbortController = new AbortController());
11853
- }
11854
- /**
11855
- * createToken - Creates a token to authenticate this user. This function is used server side.
11856
- * The resulting token should be passed to the client side when the users registers or logs in.
11857
- *
11858
- * @param {string} userID The UserWithId ID
11859
- * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11860
- * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11861
- *
11862
- * @return {string} Returns a token
11863
- */
11864
- createToken(userID, exp, iat, call_cids) {
11865
- if (this.secret == null) {
11866
- throw Error(`tokens can only be created server-side using the API Secret`);
11867
- }
11868
- const extra = {};
11869
- if (exp) {
11870
- extra.exp = exp;
11871
- }
11872
- if (iat) {
11873
- extra.iat = iat;
11874
- }
11875
- if (call_cids) {
11876
- extra.call_cids = call_cids;
11877
- }
11878
- return JWTUserToken(this.secret, userID, extra, {});
11879
- }
11880
11885
  }
11881
11886
 
11882
11887
  /**
@@ -12173,7 +12178,7 @@ class StreamVideoClient {
12173
12178
  return;
12174
12179
  const { call, members } = event;
12175
12180
  if (userToConnect.id === call.created_by.id) {
12176
- this.logger('warn', 'Received `call.ring` sent by the current user');
12181
+ this.logger('debug', 'Received `call.ring` sent by the current user so ignoring the event');
12177
12182
  return;
12178
12183
  }
12179
12184
  // The call might already be tracked by the client,