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