@stream-io/video-client 0.0.39 → 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.
@@ -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);
@@ -9081,13 +9081,6 @@ const getClientDetails = () => {
9081
9081
  * An object representation of a `Call`.
9082
9082
  */
9083
9083
  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
9084
  /**
9092
9085
  * Constructs a new `Call` instance.
9093
9086
  *
@@ -9133,7 +9126,6 @@ class Call {
9133
9126
  if (callingState === CallingState.LEFT) {
9134
9127
  throw new Error('Cannot leave call that has already been left.');
9135
9128
  }
9136
- this.rejoinPromise = undefined;
9137
9129
  if (this.ringing) {
9138
9130
  // I'm the one who started the call, so I should cancel it.
9139
9131
  const hasOtherParticipants = this.state.remoteParticipants.length > 0;
@@ -9337,7 +9329,7 @@ class Call {
9337
9329
  // we shouldn't be republishing the streams if we're migrating
9338
9330
  // as the underlying peer connection will take care of it as part
9339
9331
  // of the ice-restart process
9340
- if (localParticipant && !isReactNative() && !migrate) {
9332
+ if (localParticipant && !migrate) {
9341
9333
  const { audioStream, videoStream, screenShareStream: screenShare, } = localParticipant;
9342
9334
  // restore previous publishing state
9343
9335
  if (audioStream)
@@ -9349,7 +9341,6 @@ class Call {
9349
9341
  }
9350
9342
  this.logger('info', `[Rejoin]: State restored. Attempt: ${this.reconnectAttempts}`);
9351
9343
  });
9352
- this.rejoinPromise = rejoin;
9353
9344
  // reconnect if the connection was closed unexpectedly. example:
9354
9345
  // - SFU crash or restart
9355
9346
  // - network change
@@ -9382,9 +9373,6 @@ class Call {
9382
9373
  if (e.code === KnownCodes.WS_CLOSED_ABRUPTLY &&
9383
9374
  sfuClient.isMigratingAway)
9384
9375
  return;
9385
- // do nothing for react-native as it is handled by SDK
9386
- if (isReactNative())
9387
- return;
9388
9376
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
9389
9377
  rejoin().catch((err) => {
9390
9378
  this.logger('error', `[Rejoin]: Rejoin failed for ${this.reconnectAttempts} times. Giving up.`, err);
@@ -9398,28 +9386,34 @@ class Call {
9398
9386
  });
9399
9387
  });
9400
9388
  // 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
- }
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
+ });
9423
9417
  if (!this.subscriber) {
9424
9418
  this.subscriber = new Subscriber({
9425
9419
  sfuClient,
@@ -10270,6 +10264,9 @@ const isErrorEvent = (res) => res.error !== undefined;
10270
10264
  */
10271
10265
  class StableWSConnection {
10272
10266
  constructor(client) {
10267
+ this._log = (msg, extra = {}, level = 'info') => {
10268
+ this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10269
+ };
10273
10270
  this.setClient = (client) => {
10274
10271
  this.client = client;
10275
10272
  };
@@ -10298,7 +10295,8 @@ class StableWSConnection {
10298
10295
  if (event.type === 'offline') {
10299
10296
  // mark the connection as down
10300
10297
  this._log('onlineStatusChanged() - Status changing to offline');
10301
- this._setHealth(false);
10298
+ // we know that the app is offline so dispatch the unhealthy connection event immediately
10299
+ this._setHealth(false, true);
10302
10300
  }
10303
10301
  else if (event.type === 'online') {
10304
10302
  // retry right now...
@@ -10426,13 +10424,14 @@ class StableWSConnection {
10426
10424
  * Broadcasts an event in case the connection status changed.
10427
10425
  *
10428
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
10429
10428
  *
10430
10429
  */
10431
- this._setHealth = (healthy) => {
10430
+ this._setHealth = (healthy, dispatchImmediately = false) => {
10432
10431
  if (healthy === this.isHealthy)
10433
10432
  return;
10434
10433
  this.isHealthy = healthy;
10435
- if (this.isHealthy) {
10434
+ if (this.isHealthy || dispatchImmediately) {
10436
10435
  this.client.dispatchEvent({
10437
10436
  type: 'connection.changed',
10438
10437
  online: this.isHealthy,
@@ -10554,9 +10553,6 @@ class StableWSConnection {
10554
10553
  this.connectionCheckTimeout = this.pingInterval + 10 * 1000;
10555
10554
  addConnectionEventListeners(this.onlineStatusChanged);
10556
10555
  }
10557
- _log(msg, extra = {}, level = 'info') {
10558
- this.client.logger(level, 'connection:' + msg, Object.assign({}, extra));
10559
- }
10560
10556
  /**
10561
10557
  * connect - Connect to the WS URL
10562
10558
  * the default 15s timeout allows between 2~3 tries
@@ -11305,6 +11301,18 @@ class StreamClient {
11305
11301
  constructor(key, options) {
11306
11302
  var _a;
11307
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
+ };
11308
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); };
11309
11317
  this._hasConnectionID = () => Boolean(this._getConnectionID());
11310
11318
  /**
@@ -11369,6 +11377,16 @@ class StreamClient {
11369
11377
  }
11370
11378
  });
11371
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
+ };
11372
11390
  /**
11373
11391
  * Disconnects the websocket connection, without removing the user set on client.
11374
11392
  * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need
@@ -11457,6 +11475,66 @@ class StreamClient {
11457
11475
  // resolve the connection_id here.
11458
11476
  this.resolveConnectionId();
11459
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
+ };
11460
11538
  this.doAxiosRequest = (type, url, data, options = {}) => __awaiter(this, void 0, void 0, function* () {
11461
11539
  var _g;
11462
11540
  if (!options.publicEndpoint || this.user) {
@@ -11521,6 +11599,43 @@ class StreamClient {
11521
11599
  }
11522
11600
  }
11523
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
+ };
11524
11639
  this.dispatchEvent = (event) => {
11525
11640
  if (!event.received_at)
11526
11641
  event.received_at = new Date();
@@ -11548,10 +11663,119 @@ class StreamClient {
11548
11663
  listener(event);
11549
11664
  }
11550
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
+ };
11551
11750
  /**
11552
11751
  * _isUsingServerAuth - Returns true if we're using server side auth
11553
11752
  */
11554
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
+ };
11555
11779
  /**
11556
11780
  * encode ws url payload
11557
11781
  * @private
@@ -11564,6 +11788,38 @@ class StreamClient {
11564
11788
  client_request_id,
11565
11789
  });
11566
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
+ };
11567
11823
  // set the key
11568
11824
  this.key = key;
11569
11825
  this.listeners = {};
@@ -11615,268 +11871,6 @@ class StreamClient {
11615
11871
  ? inputOptions.logger
11616
11872
  : () => null;
11617
11873
  }
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
11874
  }
11881
11875
 
11882
11876
  /**