@stream-io/video-client 0.0.38 → 0.0.40

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.
@@ -6093,6 +6093,7 @@ class Publisher {
6093
6093
  this.trackLayersCache[trackType] = undefined;
6094
6094
  });
6095
6095
  }
6096
+ this.pc.removeEventListener('negotiationneeded', this.onNegotiationNeeded);
6096
6097
  this.pc.close();
6097
6098
  };
6098
6099
  /**
@@ -6844,7 +6845,7 @@ class StreamSfuClient {
6844
6845
  * from this SFU.
6845
6846
  */
6846
6847
  this.isMigratingAway = false;
6847
- this.pingIntervalInMs = 25 * 1000;
6848
+ this.pingIntervalInMs = 10 * 1000;
6848
6849
  this.unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
6849
6850
  this.close = (code = 1000, reason = 'Requested signal connection close') => {
6850
6851
  this.signalWs.close(code, reason);
@@ -9080,13 +9081,6 @@ const getClientDetails = () => {
9080
9081
  * An object representation of a `Call`.
9081
9082
  */
9082
9083
  class Call {
9083
- /**
9084
- * A promise that exposes the reconnection logic
9085
- * The use-case is for the react-native platform where online/offline events are not available in the window
9086
- */
9087
- get rejoin() {
9088
- return this.rejoinPromise;
9089
- }
9090
9084
  /**
9091
9085
  * Constructs a new `Call` instance.
9092
9086
  *
@@ -9132,7 +9126,6 @@ class Call {
9132
9126
  if (callingState === CallingState.LEFT) {
9133
9127
  throw new Error('Cannot leave call that has already been left.');
9134
9128
  }
9135
- this.rejoinPromise = undefined;
9136
9129
  if (this.ringing) {
9137
9130
  // I'm the one who started the call, so I should cancel it.
9138
9131
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
@@ -9336,7 +9329,7 @@ class Call {
9336
9329
  // we shouldn't be republishing the streams if we're migrating
9337
9330
  // as the underlying peer connection will take care of it as part
9338
9331
  // of the ice-restart process
9339
- if (localParticipant && !isReactNative() && !migrate) {
9332
+ if (localParticipant && !migrate) {
9340
9333
  const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
9341
9334
  // restore previous publishing state
9342
9335
  if (audioStream)
@@ -9348,7 +9341,6 @@ class Call {
9348
9341
  }
9349
9342
  this.logger('info', `[Rejoin]: State restored. Attempt: ${this.reconnectAttempts}`);
9350
9343
  });
9351
- this.rejoinPromise = rejoin;
9352
9344
  // reconnect if the connection was closed unexpectedly. example:
9353
9345
  // - SFU crash or restart
9354
9346
  // - network change
@@ -9381,9 +9373,6 @@ class Call {
9381
9373
  if (e.code === KnownCodes.WS_CLOSED_ABRUPTLY &&
9382
9374
  sfuClient.isMigratingAway)
9383
9375
  return;
9384
- // do nothing for react-native as it is handled by SDK
9385
- if (isReactNative())
9386
- return;
9387
9376
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
9388
9377
  rejoin().catch((err) => {
9389
9378
  this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
@@ -9397,28 +9386,34 @@ class Call {
9397
9386
  });
9398
9387
  });
9399
9388
  // handlers for connection online/offline events
9400
- // Note: window.addEventListener is not available in React Native, hence the check
9401
- if (typeof window !== 'undefined' && window.addEventListener) {
9402
- const handleOnOffline = () => {
9403
- window.removeEventListener('offline', handleOnOffline);
9404
- this.logger('warn', '[Rejoin]: Going offline...');
9405
- this.state.setCallingState(CallingState.OFFLINE);
9406
- };
9407
- const handleOnOnline = () => {
9408
- window.removeEventListener('online', handleOnOnline);
9409
- if (this.state.callingState === CallingState.OFFLINE) {
9410
- this.logger('info', '[Rejoin]: Going online...');
9411
- rejoin().catch((err) => {
9412
- this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9413
- this.state.setCallingState(CallingState.RECONNECTING_FAILED);
9414
- });
9415
- }
9416
- };
9417
- window.addEventListener('offline', handleOnOffline);
9418
- window.addEventListener('online', handleOnOnline);
9419
- // register cleanup hooks
9420
- this.leaveCallHooks.push(() => window.removeEventListener('offline', handleOnOffline), () => window.removeEventListener('online', handleOnOnline));
9421
- }
9389
+ const unsubscribeOnlineEvent = this.streamClient.on('connection.changed', (e) => {
9390
+ if (e.type !== 'connection.changed')
9391
+ return;
9392
+ if (!e.online)
9393
+ return;
9394
+ unsubscribeOnlineEvent();
9395
+ const currentCallingState = this.state.callingState;
9396
+ if (currentCallingState === CallingState.OFFLINE ||
9397
+ currentCallingState === CallingState.RECONNECTING_FAILED) {
9398
+ this.logger('info', '[Rejoin]: Going online...');
9399
+ rejoin().catch((err) => {
9400
+ this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
9401
+ this.state.setCallingState(CallingState.RECONNECTING_FAILED);
9402
+ });
9403
+ }
9404
+ });
9405
+ const unsubscribeOfflineEvent = this.streamClient.on('connection.changed', (e) => {
9406
+ if (e.type !== 'connection.changed')
9407
+ return;
9408
+ if (e.online)
9409
+ return;
9410
+ unsubscribeOfflineEvent();
9411
+ this.state.setCallingState(CallingState.OFFLINE);
9412
+ });
9413
+ this.leaveCallHooks.push(() => {
9414
+ unsubscribeOnlineEvent();
9415
+ unsubscribeOfflineEvent();
9416
+ });
9422
9417
  if (!this.subscriber) {
9423
9418
  this.subscriber = new Subscriber({
9424
9419
  sfuClient,
@@ -10269,6 +10264,9 @@ const isErrorEvent = (res) => res.error !== undefined;
10269
10264
  */
10270
10265
  class StableWSConnection {
10271
10266
  constructor(client) {
10267
+ this._log = (msg, extra = {}, level = 'info') => {
10268
+ this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10269
+ };
10272
10270
  this.setClient = (client) => {
10273
10271
  this.client = client;
10274
10272
  };
@@ -10297,7 +10295,8 @@ class StableWSConnection {
10297
10295
  if (event.type === 'offline') {
10298
10296
  // mark the connection as down
10299
10297
  this._log('onlineStatusChanged() - Status changing to offline');
10300
- this._setHealth(false);
10298
+ // we know that the app is offline so dispatch the unhealthy connection event immediately
10299
+ this._setHealth(false, true);
10301
10300
  }
10302
10301
  else if (event.type === 'online') {
10303
10302
  // retry right now...
@@ -10425,13 +10424,14 @@ class StableWSConnection {
10425
10424
  * Broadcasts an event in case the connection status changed.
10426
10425
  *
10427
10426
  * @param {boolean} healthy boolean indicating if the connection is healthy or not
10427
+ * @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
10428
10428
  *
10429
10429
  */
10430
- this._setHealth = (healthy) => {
10430
+ this._setHealth = (healthy, dispatchImmediately = false) => {
10431
10431
  if (healthy === this.isHealthy)
10432
10432
  return;
10433
10433
  this.isHealthy = healthy;
10434
- if (this.isHealthy) {
10434
+ if (this.isHealthy || dispatchImmediately) {
10435
10435
  this.client.dispatchEvent({
10436
10436
  type: 'connection.changed',
10437
10437
  online: this.isHealthy,
@@ -10553,9 +10553,6 @@ class StableWSConnection {
10553
10553
  this.connectionCheckTimeout = this.pingInterval + 10 * 1000;
10554
10554
  addConnectionEventListeners(this.onlineStatusChanged);
10555
10555
  }
10556
- _log(msg, extra = {}, level = 'info') {
10557
- this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10558
- }
10559
10556
  /**
10560
10557
  * connect - Connect to the WS URL
10561
10558
  * the default 15s timeout allows between 2~3 tries
@@ -11304,6 +11301,18 @@ class StreamClient {
11304
11301
  constructor(key, options) {
11305
11302
  var _a;
11306
11303
  this.nextRequestAbortController = null;
11304
+ this.devToken = (userID) => {
11305
+ return DevToken(userID);
11306
+ };
11307
+ this.getAuthType = () => {
11308
+ return this.anonymous ? 'anonymous' : 'jwt';
11309
+ };
11310
+ this.setBaseURL = (baseURL) => {
11311
+ this.baseURL = baseURL;
11312
+ this.wsBaseURL = this.baseURL
11313
+ .replace('http', 'ws')
11314
+ .replace(':3030', ':8800');
11315
+ };
11307
11316
  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); };
11308
11317
  this._hasConnectionID = () => Boolean(this._getConnectionID());
11309
11318
  /**
@@ -11368,6 +11377,16 @@ class StreamClient {
11368
11377
  }
11369
11378
  });
11370
11379
  this._setToken = (user, userTokenOrProvider, isAnonymous) => this.tokenManager.setTokenOrProvider(userTokenOrProvider, user, isAnonymous);
11380
+ this._setUser = (user) => {
11381
+ /**
11382
+ * This one is used by the frontend. This is a copy of the current user object stored on backend.
11383
+ * It contains reserved properties and own user properties which are not present in `this._user`.
11384
+ */
11385
+ this.user = user;
11386
+ this.userID = user.id;
11387
+ // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11388
+ this._user = Object.assign({}, user);
11389
+ };
11371
11390
  /**
11372
11391
  * Disconnects the websocket connection, without removing the user set on client.
11373
11392
  * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need
@@ -11456,6 +11475,66 @@ class StreamClient {
11456
11475
  // resolve the connection_id here.
11457
11476
  this.resolveConnectionId();
11458
11477
  });
11478
+ /**
11479
+ * on - Listen to events on all channels and users your watching
11480
+ *
11481
+ * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11482
+ * or
11483
+ * client.on(event => {console.log(event.type)})
11484
+ *
11485
+ * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11486
+ * @param {EventHandler} [callbackOrNothing] The callback to call
11487
+ *
11488
+ * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11489
+ */
11490
+ this.on = (callbackOrEventName, callbackOrNothing) => {
11491
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11492
+ const callback = callbackOrNothing
11493
+ ? callbackOrNothing
11494
+ : callbackOrEventName;
11495
+ if (!(key in this.listeners)) {
11496
+ this.listeners[key] = [];
11497
+ }
11498
+ this.listeners[key].push(callback);
11499
+ return () => {
11500
+ this.off(key, callback);
11501
+ };
11502
+ };
11503
+ /**
11504
+ * off - Remove the event handler
11505
+ *
11506
+ */
11507
+ this.off = (callbackOrEventName, callbackOrNothing) => {
11508
+ const key = callbackOrNothing ? callbackOrEventName : 'all';
11509
+ const callback = callbackOrNothing
11510
+ ? callbackOrNothing
11511
+ : callbackOrEventName;
11512
+ if (!(key in this.listeners)) {
11513
+ this.listeners[key] = [];
11514
+ }
11515
+ this.logger('debug', `Removing listener for ${key} event`);
11516
+ this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11517
+ };
11518
+ this._logApiRequest = (type, url, data, config) => {
11519
+ this.logger('trace', `client: ${type} - Request - ${url}`, {
11520
+ payload: data,
11521
+ config,
11522
+ });
11523
+ };
11524
+ this._logApiResponse = (type, url, response) => {
11525
+ this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11526
+ response,
11527
+ });
11528
+ this.logger('trace', `client:${type} - Response payload`, {
11529
+ response,
11530
+ });
11531
+ };
11532
+ this._logApiError = (type, url, error) => {
11533
+ this.logger('error', `client:${type} - Error - url: ${url}`, {
11534
+ url,
11535
+ error,
11536
+ });
11537
+ };
11459
11538
  this.doAxiosRequest = (type, url, data, options = {}) => __awaiter(this, void 0, void 0, function* () {
11460
11539
  var _g;
11461
11540
  if (!options.publicEndpoint || this.user) {
@@ -11520,6 +11599,43 @@ class StreamClient {
11520
11599
  }
11521
11600
  }
11522
11601
  });
11602
+ this.get = (url, params) => {
11603
+ return this.doAxiosRequest('get', url, null, {
11604
+ params,
11605
+ });
11606
+ };
11607
+ this.put = (url, data) => {
11608
+ return this.doAxiosRequest('put', url, data);
11609
+ };
11610
+ this.post = (url, data) => {
11611
+ return this.doAxiosRequest('post', url, data);
11612
+ };
11613
+ this.patch = (url, data) => {
11614
+ return this.doAxiosRequest('patch', url, data);
11615
+ };
11616
+ this.delete = (url, params) => {
11617
+ return this.doAxiosRequest('delete', url, null, {
11618
+ params,
11619
+ });
11620
+ };
11621
+ this.errorFromResponse = (response) => {
11622
+ let err;
11623
+ err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11624
+ if (response.data && response.data.code) {
11625
+ err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11626
+ err.code = response.data.code;
11627
+ }
11628
+ err.response = response;
11629
+ err.status = response.status;
11630
+ return err;
11631
+ };
11632
+ this.handleResponse = (response) => {
11633
+ const data = response.data;
11634
+ if (isErrorResponse(response)) {
11635
+ throw this.errorFromResponse(response);
11636
+ }
11637
+ return data;
11638
+ };
11523
11639
  this.dispatchEvent = (event) => {
11524
11640
  if (!event.received_at)
11525
11641
  event.received_at = new Date();
@@ -11547,10 +11663,119 @@ class StreamClient {
11547
11663
  listener(event);
11548
11664
  }
11549
11665
  };
11666
+ /**
11667
+ * @private
11668
+ */
11669
+ this.connect = () => __awaiter(this, void 0, void 0, function* () {
11670
+ if (!this.userID || !this._user) {
11671
+ throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11672
+ }
11673
+ if (!this.wsBaseURL) {
11674
+ throw Error('Websocket base url not set');
11675
+ }
11676
+ if (!this.clientID) {
11677
+ throw Error('clientID is not set');
11678
+ }
11679
+ if (!this.wsConnection &&
11680
+ (this.options.warmUp || this.options.enableInsights)) {
11681
+ this._sayHi();
11682
+ }
11683
+ // The StableWSConnection handles all the reconnection logic.
11684
+ if (this.options.wsConnection && this.node) {
11685
+ // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11686
+ this.options.wsConnection.setClient(this);
11687
+ this.wsConnection = this.options
11688
+ .wsConnection;
11689
+ }
11690
+ else {
11691
+ this.wsConnection = new StableWSConnection(this);
11692
+ }
11693
+ try {
11694
+ // if fallback is used before, continue using it instead of waiting for WS to fail
11695
+ if (this.wsFallback) {
11696
+ return yield this.wsFallback.connect();
11697
+ }
11698
+ this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11699
+ // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11700
+ return yield this.wsConnection.connect(this.options.enableWSFallback
11701
+ ? this.defaultWSTimeoutWithFallback
11702
+ : this.defaultWSTimeout);
11703
+ }
11704
+ catch (err) {
11705
+ // run fallback only if it's WS/Network error and not a normal API error
11706
+ // make sure browser is online before even trying the longpoll
11707
+ if (this.options.enableWSFallback &&
11708
+ // @ts-ignore
11709
+ isWSFailure(err) &&
11710
+ isOnline(this.logger)) {
11711
+ this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11712
+ this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11713
+ this.wsConnection._destroyCurrentWSConnection();
11714
+ this.wsConnection.disconnect().then(); // close WS so no retry
11715
+ this.wsFallback = new WSConnectionFallback(this);
11716
+ return yield this.wsFallback.connect();
11717
+ }
11718
+ throw err;
11719
+ }
11720
+ });
11721
+ /**
11722
+ * Check the connectivity with server for warmup purpose.
11723
+ *
11724
+ * @private
11725
+ */
11726
+ this._sayHi = () => {
11727
+ const client_request_id = randomId();
11728
+ const opts = {
11729
+ headers: AxiosHeaders.from({
11730
+ 'x-client-request-id': client_request_id,
11731
+ }),
11732
+ };
11733
+ this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11734
+ if (this.options.enableInsights) {
11735
+ postInsights('http_hi_failed', {
11736
+ api_key: this.key,
11737
+ err: e,
11738
+ client_request_id,
11739
+ });
11740
+ }
11741
+ });
11742
+ };
11743
+ this.getUserAgent = () => {
11744
+ return (this.userAgent ||
11745
+ `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.39"}`);
11746
+ };
11747
+ this.setUserAgent = (userAgent) => {
11748
+ this.userAgent = userAgent;
11749
+ };
11550
11750
  /**
11551
11751
  * _isUsingServerAuth - Returns true if we're using server side auth
11552
11752
  */
11553
11753
  this._isUsingServerAuth = () => !!this.secret;
11754
+ this._enrichAxiosOptions = (options = {
11755
+ params: {},
11756
+ headers: {},
11757
+ config: {},
11758
+ }) => {
11759
+ var _a;
11760
+ const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11761
+ const authorization = token ? { Authorization: token } : undefined;
11762
+ let signal = null;
11763
+ if (this.nextRequestAbortController !== null) {
11764
+ signal = this.nextRequestAbortController.signal;
11765
+ this.nextRequestAbortController = null;
11766
+ }
11767
+ if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11768
+ options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11769
+ }
11770
+ 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
11771
+ ? 'anonymous'
11772
+ : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11773
+ };
11774
+ this._getToken = () => {
11775
+ if (!this.tokenManager)
11776
+ return null;
11777
+ return this.tokenManager.getToken();
11778
+ };
11554
11779
  /**
11555
11780
  * encode ws url payload
11556
11781
  * @private
@@ -11563,6 +11788,38 @@ class StreamClient {
11563
11788
  client_request_id,
11564
11789
  });
11565
11790
  };
11791
+ /**
11792
+ * creates an abort controller that will be used by the next HTTP Request.
11793
+ */
11794
+ this.createAbortControllerForNextRequest = () => {
11795
+ return (this.nextRequestAbortController = new AbortController());
11796
+ };
11797
+ /**
11798
+ * createToken - Creates a token to authenticate this user. This function is used server side.
11799
+ * The resulting token should be passed to the client side when the users registers or logs in.
11800
+ *
11801
+ * @param {string} userID The UserWithId ID
11802
+ * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11803
+ * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11804
+ *
11805
+ * @return {string} Returns a token
11806
+ */
11807
+ this.createToken = (userID, exp, iat, call_cids) => {
11808
+ if (this.secret == null) {
11809
+ throw Error(`tokens can only be created server-side using the API Secret`);
11810
+ }
11811
+ const extra = {};
11812
+ if (exp) {
11813
+ extra.exp = exp;
11814
+ }
11815
+ if (iat) {
11816
+ extra.iat = iat;
11817
+ }
11818
+ if (call_cids) {
11819
+ extra.call_cids = call_cids;
11820
+ }
11821
+ return JWTUserToken(this.secret, userID, extra, {});
11822
+ };
11566
11823
  // set the key
11567
11824
  this.key = key;
11568
11825
  this.listeners = {};
@@ -11614,268 +11871,6 @@ class StreamClient {
11614
11871
  ? inputOptions.logger
11615
11872
  : () => null;
11616
11873
  }
11617
- devToken(userID) {
11618
- return DevToken(userID);
11619
- }
11620
- getAuthType() {
11621
- return this.anonymous ? 'anonymous' : 'jwt';
11622
- }
11623
- setBaseURL(baseURL) {
11624
- this.baseURL = baseURL;
11625
- this.wsBaseURL = this.baseURL
11626
- .replace('http', 'ws')
11627
- .replace(':3030', ':8800');
11628
- }
11629
- _setUser(user) {
11630
- /**
11631
- * This one is used by the frontend. This is a copy of the current user object stored on backend.
11632
- * It contains reserved properties and own user properties which are not present in `this._user`.
11633
- */
11634
- this.user = user;
11635
- this.userID = user.id;
11636
- // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
11637
- this._user = Object.assign({}, user);
11638
- }
11639
- /**
11640
- * on - Listen to events on all channels and users your watching
11641
- *
11642
- * client.on('message.new', event => {console.log("my new message", event, channel.state.messages)})
11643
- * or
11644
- * client.on(event => {console.log(event.type)})
11645
- *
11646
- * @param {EventHandler | string} callbackOrEventName The event type to listen for (optional)
11647
- * @param {EventHandler} [callbackOrNothing] The callback to call
11648
- *
11649
- * @return {Function} Returns a function which, when called, unsubscribes the event handler.
11650
- */
11651
- on(callbackOrEventName, callbackOrNothing) {
11652
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11653
- const callback = callbackOrNothing
11654
- ? callbackOrNothing
11655
- : callbackOrEventName;
11656
- if (!(key in this.listeners)) {
11657
- this.listeners[key] = [];
11658
- }
11659
- this.listeners[key].push(callback);
11660
- return () => {
11661
- this.off(key, callback);
11662
- };
11663
- }
11664
- /**
11665
- * off - Remove the event handler
11666
- *
11667
- */
11668
- off(callbackOrEventName, callbackOrNothing) {
11669
- const key = callbackOrNothing ? callbackOrEventName : 'all';
11670
- const callback = callbackOrNothing
11671
- ? callbackOrNothing
11672
- : callbackOrEventName;
11673
- if (!(key in this.listeners)) {
11674
- this.listeners[key] = [];
11675
- }
11676
- this.logger('debug', `Removing listener for ${key} event`);
11677
- this.listeners[key] = this.listeners[key].filter((value) => value !== callback);
11678
- }
11679
- _logApiRequest(type, url, data, config) {
11680
- this.logger('trace', `client: ${type} - Request - ${url}`, {
11681
- payload: data,
11682
- config,
11683
- });
11684
- }
11685
- _logApiResponse(type, url, response) {
11686
- this.logger('trace', `client:${type} - Response - url: ${url} > status ${response.status}`, {
11687
- response,
11688
- });
11689
- this.logger('trace', `client:${type} - Response payload`, {
11690
- response,
11691
- });
11692
- }
11693
- _logApiError(type, url, error) {
11694
- this.logger('error', `client:${type} - Error - url: ${url}`, {
11695
- url,
11696
- error,
11697
- });
11698
- }
11699
- get(url, params) {
11700
- return this.doAxiosRequest('get', url, null, {
11701
- params,
11702
- });
11703
- }
11704
- put(url, data) {
11705
- return this.doAxiosRequest('put', url, data);
11706
- }
11707
- post(url, data) {
11708
- return this.doAxiosRequest('post', url, data);
11709
- }
11710
- patch(url, data) {
11711
- return this.doAxiosRequest('patch', url, data);
11712
- }
11713
- delete(url, params) {
11714
- return this.doAxiosRequest('delete', url, null, {
11715
- params,
11716
- });
11717
- }
11718
- errorFromResponse(response) {
11719
- let err;
11720
- err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
11721
- if (response.data && response.data.code) {
11722
- err = new Error(`Stream error code ${response.data.code}: ${response.data.message}`);
11723
- err.code = response.data.code;
11724
- }
11725
- err.response = response;
11726
- err.status = response.status;
11727
- return err;
11728
- }
11729
- handleResponse(response) {
11730
- const data = response.data;
11731
- if (isErrorResponse(response)) {
11732
- throw this.errorFromResponse(response);
11733
- }
11734
- return data;
11735
- }
11736
- /**
11737
- * @private
11738
- */
11739
- connect() {
11740
- return __awaiter(this, void 0, void 0, function* () {
11741
- if (!this.userID || !this._user) {
11742
- throw Error('Call connectUser or connectAnonymousUser before starting the connection');
11743
- }
11744
- if (!this.wsBaseURL) {
11745
- throw Error('Websocket base url not set');
11746
- }
11747
- if (!this.clientID) {
11748
- throw Error('clientID is not set');
11749
- }
11750
- if (!this.wsConnection &&
11751
- (this.options.warmUp || this.options.enableInsights)) {
11752
- this._sayHi();
11753
- }
11754
- // The StableWSConnection handles all the reconnection logic.
11755
- if (this.options.wsConnection && this.node) {
11756
- // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose.
11757
- this.options.wsConnection.setClient(this);
11758
- this.wsConnection = this.options
11759
- .wsConnection;
11760
- }
11761
- else {
11762
- this.wsConnection = new StableWSConnection(this);
11763
- }
11764
- try {
11765
- // if fallback is used before, continue using it instead of waiting for WS to fail
11766
- if (this.wsFallback) {
11767
- return yield this.wsFallback.connect();
11768
- }
11769
- this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
11770
- // if WSFallback is enabled, ws connect should timeout faster so fallback can try
11771
- return yield this.wsConnection.connect(this.options.enableWSFallback
11772
- ? this.defaultWSTimeoutWithFallback
11773
- : this.defaultWSTimeout);
11774
- }
11775
- catch (err) {
11776
- // run fallback only if it's WS/Network error and not a normal API error
11777
- // make sure browser is online before even trying the longpoll
11778
- if (this.options.enableWSFallback &&
11779
- // @ts-ignore
11780
- isWSFailure(err) &&
11781
- isOnline(this.logger)) {
11782
- this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
11783
- this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
11784
- this.wsConnection._destroyCurrentWSConnection();
11785
- this.wsConnection.disconnect().then(); // close WS so no retry
11786
- this.wsFallback = new WSConnectionFallback(this);
11787
- return yield this.wsFallback.connect();
11788
- }
11789
- throw err;
11790
- }
11791
- });
11792
- }
11793
- /**
11794
- * Check the connectivity with server for warmup purpose.
11795
- *
11796
- * @private
11797
- */
11798
- _sayHi() {
11799
- const client_request_id = randomId();
11800
- const opts = {
11801
- headers: AxiosHeaders.from({
11802
- 'x-client-request-id': client_request_id,
11803
- }),
11804
- };
11805
- this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
11806
- if (this.options.enableInsights) {
11807
- postInsights('http_hi_failed', {
11808
- api_key: this.key,
11809
- err: e,
11810
- client_request_id,
11811
- });
11812
- }
11813
- });
11814
- }
11815
- getUserAgent() {
11816
- return (this.userAgent ||
11817
- `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${"0.0.37"}`);
11818
- }
11819
- setUserAgent(userAgent) {
11820
- this.userAgent = userAgent;
11821
- }
11822
- _enrichAxiosOptions(options = {
11823
- params: {},
11824
- headers: {},
11825
- config: {},
11826
- }) {
11827
- var _a;
11828
- const token = options.publicEndpoint && !this.user ? undefined : this._getToken();
11829
- const authorization = token ? { Authorization: token } : undefined;
11830
- let signal = null;
11831
- if (this.nextRequestAbortController !== null) {
11832
- signal = this.nextRequestAbortController.signal;
11833
- this.nextRequestAbortController = null;
11834
- }
11835
- if (!((_a = options.headers) === null || _a === void 0 ? void 0 : _a['x-client-request-id'])) {
11836
- options.headers = Object.assign(Object.assign({}, options.headers), { 'x-client-request-id': randomId() });
11837
- }
11838
- 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
11839
- ? 'anonymous'
11840
- : this.getAuthType(), 'X-Stream-Client': this.getUserAgent() }), options.headers) }, (signal ? { signal } : {})), options.config), this.options.axiosRequestConfig);
11841
- }
11842
- _getToken() {
11843
- if (!this.tokenManager)
11844
- return null;
11845
- return this.tokenManager.getToken();
11846
- }
11847
- /**
11848
- * creates an abort controller that will be used by the next HTTP Request.
11849
- */
11850
- createAbortControllerForNextRequest() {
11851
- return (this.nextRequestAbortController = new AbortController());
11852
- }
11853
- /**
11854
- * createToken - Creates a token to authenticate this user. This function is used server side.
11855
- * The resulting token should be passed to the client side when the users registers or logs in.
11856
- *
11857
- * @param {string} userID The UserWithId ID
11858
- * @param {number} [exp] The expiration time for the token expressed in the number of seconds since the epoch
11859
- * @param call_cids for anonymous tokens you have to provide the call cids the use can join
11860
- *
11861
- * @return {string} Returns a token
11862
- */
11863
- createToken(userID, exp, iat, call_cids) {
11864
- if (this.secret == null) {
11865
- throw Error(`tokens can only be created server-side using the API Secret`);
11866
- }
11867
- const extra = {};
11868
- if (exp) {
11869
- extra.exp = exp;
11870
- }
11871
- if (iat) {
11872
- extra.iat = iat;
11873
- }
11874
- if (call_cids) {
11875
- extra.call_cids = call_cids;
11876
- }
11877
- return JWTUserToken(this.secret, userID, extra, {});
11878
- }
11879
11874
  }
11880
11875
 
11881
11876
  /**