@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.
@@ -30,12 +30,6 @@ export declare class Call {
30
30
  * The state of this call.
31
31
  */
32
32
  readonly state: CallState;
33
- private rejoinPromise;
34
- /**
35
- * A promise that exposes the reconnection logic
36
- * The use-case is for the react-native platform where online/offline events are not available in the window
37
- */
38
- get rejoin(): (() => Promise<void>) | undefined;
39
33
  /**
40
34
  * Flag indicating whether this call is "watched" and receives
41
35
  * updates from the backend.
@@ -53,9 +53,9 @@ export declare class StreamClient {
53
53
  * @param {httpsAgent} [options.httpsAgent] - custom httpsAgent, in node it's default to https.agent()
54
54
  */
55
55
  constructor(key: string, options?: StreamClientOptions);
56
- devToken(userID: string): string;
57
- getAuthType(): "anonymous" | "jwt";
58
- setBaseURL(baseURL: string): void;
56
+ devToken: (userID: string) => string;
57
+ getAuthType: () => "anonymous" | "jwt";
58
+ setBaseURL: (baseURL: string) => void;
59
59
  _getConnectionID: () => string | undefined;
60
60
  _hasConnectionID: () => boolean;
61
61
  /**
@@ -72,7 +72,7 @@ export declare class StreamClient {
72
72
  */
73
73
  connectUser: (user: UserWithId, userTokenOrProvider: TokenOrProvider) => Promise<void | import("../../..").ConnectedEvent>;
74
74
  _setToken: (user: UserWithId, userTokenOrProvider: TokenOrProvider, isAnonymous: boolean) => Promise<void>;
75
- _setUser(user: UserWithId): void;
75
+ _setUser: (user: UserWithId) => void;
76
76
  /**
77
77
  * Disconnects the websocket connection, without removing the user set on client.
78
78
  * client.closeConnection will not trigger default auto-retry mechanism for reconnection. You need
@@ -115,19 +115,19 @@ export declare class StreamClient {
115
115
  *
116
116
  * @return {Function} Returns a function which, when called, unsubscribes the event handler.
117
117
  */
118
- on(callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler): () => void;
118
+ on: (callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler) => () => void;
119
119
  /**
120
120
  * off - Remove the event handler
121
121
  *
122
122
  */
123
- off(callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler): void;
124
- _logApiRequest(type: string, url: string, data: unknown, config: AxiosRequestConfig & {
125
- config?: AxiosRequestConfig & {
126
- maxBodyLength?: number;
127
- };
128
- }): void;
129
- _logApiResponse<T>(type: string, url: string, response: AxiosResponse<T>): void;
130
- _logApiError(type: string, url: string, error: unknown): void;
123
+ off: (callbackOrEventName: EventHandler | string, callbackOrNothing?: EventHandler) => void;
124
+ _logApiRequest: (type: string, url: string, data: unknown, config: AxiosRequestConfig<any> & {
125
+ config?: (AxiosRequestConfig<any> & {
126
+ maxBodyLength?: number | undefined;
127
+ }) | undefined;
128
+ }) => void;
129
+ _logApiResponse: <T>(type: string, url: string, response: AxiosResponse<T, any>) => void;
130
+ _logApiError: (type: string, url: string, error: unknown) => void;
131
131
  doAxiosRequest: <T, D = unknown>(type: string, url: string, data?: D | undefined, options?: AxiosRequestConfig & {
132
132
  config?: AxiosRequestConfig & {
133
133
  maxBodyLength?: number;
@@ -135,38 +135,38 @@ export declare class StreamClient {
135
135
  } & {
136
136
  publicEndpoint?: boolean;
137
137
  }) => Promise<T>;
138
- get<T>(url: string, params?: AxiosRequestConfig['params']): Promise<T>;
139
- put<T, D = unknown>(url: string, data?: D): Promise<T>;
140
- post<T, D = unknown>(url: string, data?: D): Promise<T>;
141
- patch<T, D = unknown>(url: string, data?: D): Promise<T>;
142
- delete<T>(url: string, params?: AxiosRequestConfig['params']): Promise<T>;
143
- errorFromResponse(response: AxiosResponse<APIErrorResponse>): ErrorFromResponse<APIErrorResponse>;
144
- handleResponse<T>(response: AxiosResponse<T>): T;
138
+ get: <T>(url: string, params?: AxiosRequestConfig['params']) => Promise<T>;
139
+ put: <T, D = unknown>(url: string, data?: D | undefined) => Promise<T>;
140
+ post: <T, D = unknown>(url: string, data?: D | undefined) => Promise<T>;
141
+ patch: <T, D = unknown>(url: string, data?: D | undefined) => Promise<T>;
142
+ delete: <T>(url: string, params?: AxiosRequestConfig['params']) => Promise<T>;
143
+ errorFromResponse: (response: AxiosResponse<APIErrorResponse>) => ErrorFromResponse<APIErrorResponse>;
144
+ handleResponse: <T>(response: AxiosResponse<T, any>) => T;
145
145
  dispatchEvent: (event: StreamVideoEvent) => void;
146
146
  handleEvent: (messageEvent: WebSocket.MessageEvent) => void;
147
147
  _callClientListeners: (event: StreamVideoEvent) => void;
148
148
  /**
149
149
  * @private
150
150
  */
151
- connect(): Promise<void | import("../../..").ConnectedEvent>;
151
+ connect: () => Promise<void | import("../../..").ConnectedEvent>;
152
152
  /**
153
153
  * Check the connectivity with server for warmup purpose.
154
154
  *
155
155
  * @private
156
156
  */
157
- _sayHi(): void;
158
- getUserAgent(): string;
159
- setUserAgent(userAgent: string): void;
157
+ _sayHi: () => void;
158
+ getUserAgent: () => string;
159
+ setUserAgent: (userAgent: string) => void;
160
160
  /**
161
161
  * _isUsingServerAuth - Returns true if we're using server side auth
162
162
  */
163
163
  _isUsingServerAuth: () => boolean;
164
- _enrichAxiosOptions(options?: AxiosRequestConfig & {
164
+ _enrichAxiosOptions: (options?: AxiosRequestConfig & {
165
165
  config?: AxiosRequestConfig;
166
166
  } & {
167
167
  publicEndpoint?: boolean;
168
- }): AxiosRequestConfig;
169
- _getToken(): string | null | undefined;
168
+ }) => AxiosRequestConfig;
169
+ _getToken: () => string | null | undefined;
170
170
  /**
171
171
  * encode ws url payload
172
172
  * @private
@@ -176,7 +176,7 @@ export declare class StreamClient {
176
176
  /**
177
177
  * creates an abort controller that will be used by the next HTTP Request.
178
178
  */
179
- createAbortControllerForNextRequest(): AbortController;
179
+ createAbortControllerForNextRequest: () => AbortController;
180
180
  /**
181
181
  * createToken - Creates a token to authenticate this user. This function is used server side.
182
182
  * The resulting token should be passed to the client side when the users registers or logs in.
@@ -187,5 +187,5 @@ export declare class StreamClient {
187
187
  *
188
188
  * @return {string} Returns a token
189
189
  */
190
- createToken(userID: string, exp?: number, iat?: number, call_cids?: string[]): string;
190
+ createToken: (userID: string, exp?: number, iat?: number, call_cids?: string[]) => string;
191
191
  }
@@ -47,7 +47,7 @@ export declare class StableWSConnection {
47
47
  wsID: number;
48
48
  client: StreamClient;
49
49
  constructor(client: StreamClient);
50
- _log(msg: string, extra?: UR, level?: LogLevel): void;
50
+ _log: (msg: string, extra?: UR, level?: LogLevel) => void;
51
51
  setClient: (client: StreamClient) => void;
52
52
  /**
53
53
  * connect - Connect to the WS URL
@@ -106,9 +106,10 @@ export declare class StableWSConnection {
106
106
  * Broadcasts an event in case the connection status changed.
107
107
  *
108
108
  * @param {boolean} healthy boolean indicating if the connection is healthy or not
109
+ * @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
109
110
  *
110
111
  */
111
- _setHealth: (healthy: boolean) => void;
112
+ _setHealth: (healthy: boolean, dispatchImmediately?: boolean) => void;
112
113
  /**
113
114
  * _errorFromWSEvent - Creates an error object for the WS event
114
115
  *
@@ -11,6 +11,7 @@ export declare const watchConnectionQualityChanged: (dispatcher: Dispatcher, sta
11
11
  * health check events that our SFU sends.
12
12
  */
13
13
  export declare const watchParticipantCountChanged: (dispatcher: Dispatcher, state: CallState) => () => void;
14
+ export declare const watchLiveEnded: (dispatcher: Dispatcher, call: Call) => () => void;
14
15
  /**
15
16
  * Watches and logs the errors reported by the currently connected SFU.
16
17
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
package/src/Call.ts CHANGED
@@ -103,7 +103,6 @@ import {
103
103
  StreamCallEvent,
104
104
  } from './coordinator/connection/types';
105
105
  import { getClientDetails } from './client-details';
106
- import { isReactNative } from './helpers/platforms';
107
106
  import { getLogger } from './logger';
108
107
 
109
108
  /**
@@ -135,16 +134,6 @@ export class Call {
135
134
  */
136
135
  readonly state = new CallState();
137
136
 
138
- private rejoinPromise: (() => Promise<void>) | undefined;
139
-
140
- /**
141
- * A promise that exposes the reconnection logic
142
- * The use-case is for the react-native platform where online/offline events are not available in the window
143
- */
144
- get rejoin(): (() => Promise<void>) | undefined {
145
- return this.rejoinPromise;
146
- }
147
-
148
137
  /**
149
138
  * Flag indicating whether this call is "watched" and receives
150
139
  * updates from the backend.
@@ -387,7 +376,6 @@ export class Call {
387
376
  if (callingState === CallingState.LEFT) {
388
377
  throw new Error('Cannot leave call that has already been left.');
389
378
  }
390
- this.rejoinPromise = undefined;
391
379
 
392
380
  if (this.ringing) {
393
381
  // I'm the one who started the call, so I should cancel it.
@@ -685,7 +673,7 @@ export class Call {
685
673
  // we shouldn't be republishing the streams if we're migrating
686
674
  // as the underlying peer connection will take care of it as part
687
675
  // of the ice-restart process
688
- if (localParticipant && !isReactNative() && !migrate) {
676
+ if (localParticipant && !migrate) {
689
677
  const {
690
678
  audioStream,
691
679
  videoStream,
@@ -703,8 +691,6 @@ export class Call {
703
691
  );
704
692
  };
705
693
 
706
- this.rejoinPromise = rejoin;
707
-
708
694
  // reconnect if the connection was closed unexpectedly. example:
709
695
  // - SFU crash or restart
710
696
  // - network change
@@ -744,8 +730,6 @@ export class Call {
744
730
  sfuClient.isMigratingAway
745
731
  )
746
732
  return;
747
- // do nothing for react-native as it is handled by SDK
748
- if (isReactNative()) return;
749
733
  if (this.reconnectAttempts < this.maxReconnectAttempts) {
750
734
  rejoin().catch((err) => {
751
735
  this.logger(
@@ -766,17 +750,17 @@ export class Call {
766
750
  });
767
751
 
768
752
  // handlers for connection online/offline events
769
- // Note: window.addEventListener is not available in React Native, hence the check
770
- if (typeof window !== 'undefined' && window.addEventListener) {
771
- const handleOnOffline = () => {
772
- window.removeEventListener('offline', handleOnOffline);
773
- this.logger('warn', '[Rejoin]: Going offline...');
774
- this.state.setCallingState(CallingState.OFFLINE);
775
- };
776
-
777
- const handleOnOnline = () => {
778
- window.removeEventListener('online', handleOnOnline);
779
- if (this.state.callingState === CallingState.OFFLINE) {
753
+ const unsubscribeOnlineEvent = this.streamClient.on(
754
+ 'connection.changed',
755
+ (e) => {
756
+ if (e.type !== 'connection.changed') return;
757
+ if (!e.online) return;
758
+ unsubscribeOnlineEvent();
759
+ const currentCallingState = this.state.callingState;
760
+ if (
761
+ currentCallingState === CallingState.OFFLINE ||
762
+ currentCallingState === CallingState.RECONNECTING_FAILED
763
+ ) {
780
764
  this.logger('info', '[Rejoin]: Going online...');
781
765
  rejoin().catch((err) => {
782
766
  this.logger(
@@ -787,17 +771,22 @@ export class Call {
787
771
  this.state.setCallingState(CallingState.RECONNECTING_FAILED);
788
772
  });
789
773
  }
790
- };
791
-
792
- window.addEventListener('offline', handleOnOffline);
793
- window.addEventListener('online', handleOnOnline);
774
+ },
775
+ );
776
+ const unsubscribeOfflineEvent = this.streamClient.on(
777
+ 'connection.changed',
778
+ (e) => {
779
+ if (e.type !== 'connection.changed') return;
780
+ if (e.online) return;
781
+ unsubscribeOfflineEvent();
782
+ this.state.setCallingState(CallingState.OFFLINE);
783
+ },
784
+ );
794
785
 
795
- // register cleanup hooks
796
- this.leaveCallHooks.push(
797
- () => window.removeEventListener('offline', handleOnOffline),
798
- () => window.removeEventListener('online', handleOnOnline),
799
- );
800
- }
786
+ this.leaveCallHooks.push(() => {
787
+ unsubscribeOnlineEvent();
788
+ unsubscribeOfflineEvent();
789
+ });
801
790
 
802
791
  if (!this.subscriber) {
803
792
  this.subscriber = new Subscriber({
@@ -106,7 +106,7 @@ export class StreamSfuClient {
106
106
  private readonly rpc: SignalServerClient;
107
107
  private keepAliveInterval?: NodeJS.Timeout;
108
108
  private connectionCheckTimeout?: NodeJS.Timeout;
109
- private pingIntervalInMs = 25 * 1000;
109
+ private pingIntervalInMs = 10 * 1000;
110
110
  private unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
111
111
  private lastMessageTimestamp?: Date;
112
112
  private readonly unsubscribeIceTrickle: () => void;
@@ -319,7 +319,7 @@ export class StreamSfuClient {
319
319
  new Date().getTime() - this.lastMessageTimestamp.getTime();
320
320
 
321
321
  if (timeSinceLastMessage > this.unhealthyTimeoutInMs) {
322
- this.logger('error', 'SFU connection unhealthy, closing');
322
+ this.logger('debug', 'SFU connection unhealthy, closing');
323
323
  this.close(
324
324
  4001,
325
325
  `SFU connection unhealthy. Didn't receive any healthcheck messages for ${this.unhealthyTimeoutInMs}ms`,
@@ -221,7 +221,10 @@ export class StreamVideoClient {
221
221
  if (event.type !== 'call.ring') return;
222
222
  const { call, members } = event;
223
223
  if (userToConnect.id === call.created_by.id) {
224
- this.logger('warn', 'Received `call.ring` sent by the current user');
224
+ this.logger(
225
+ 'debug',
226
+ 'Received `call.ring` sent by the current user so ignoring the event',
227
+ );
225
228
  return;
226
229
  }
227
230
 
@@ -162,20 +162,20 @@ export class StreamClient {
162
162
  : () => null;
163
163
  }
164
164
 
165
- devToken(userID: string) {
165
+ devToken = (userID: string) => {
166
166
  return DevToken(userID);
167
- }
167
+ };
168
168
 
169
- getAuthType() {
169
+ getAuthType = () => {
170
170
  return this.anonymous ? 'anonymous' : 'jwt';
171
- }
171
+ };
172
172
 
173
- setBaseURL(baseURL: string) {
173
+ setBaseURL = (baseURL: string) => {
174
174
  this.baseURL = baseURL;
175
175
  this.wsBaseURL = this.baseURL
176
176
  .replace('http', 'ws')
177
177
  .replace(':3030', ':8800');
178
- }
178
+ };
179
179
 
180
180
  _getConnectionID = () =>
181
181
  this.wsConnection?.connectionID || this.wsFallback?.connectionID;
@@ -282,7 +282,7 @@ export class StreamClient {
282
282
  isAnonymous,
283
283
  );
284
284
 
285
- _setUser(user: UserWithId) {
285
+ _setUser = (user: UserWithId) => {
286
286
  /**
287
287
  * This one is used by the frontend. This is a copy of the current user object stored on backend.
288
288
  * It contains reserved properties and own user properties which are not present in `this._user`.
@@ -291,7 +291,7 @@ export class StreamClient {
291
291
  this.userID = user.id;
292
292
  // this one is actually used for requests. This is a copy of current user provided to `connectUser` function.
293
293
  this._user = { ...user };
294
- }
294
+ };
295
295
 
296
296
  /**
297
297
  * Disconnects the websocket connection, without removing the user set on client.
@@ -423,10 +423,10 @@ export class StreamClient {
423
423
  *
424
424
  * @return {Function} Returns a function which, when called, unsubscribes the event handler.
425
425
  */
426
- on(
426
+ on = (
427
427
  callbackOrEventName: EventHandler | string,
428
428
  callbackOrNothing?: EventHandler,
429
- ) {
429
+ ) => {
430
430
  const key = callbackOrNothing ? (callbackOrEventName as string) : 'all';
431
431
  const callback = callbackOrNothing
432
432
  ? callbackOrNothing
@@ -439,16 +439,16 @@ export class StreamClient {
439
439
  return () => {
440
440
  this.off(key, callback);
441
441
  };
442
- }
442
+ };
443
443
 
444
444
  /**
445
445
  * off - Remove the event handler
446
446
  *
447
447
  */
448
- off(
448
+ off = (
449
449
  callbackOrEventName: EventHandler | string,
450
450
  callbackOrNothing?: EventHandler,
451
- ) {
451
+ ) => {
452
452
  const key = callbackOrNothing ? (callbackOrEventName as string) : 'all';
453
453
  const callback = callbackOrNothing
454
454
  ? callbackOrNothing
@@ -461,23 +461,27 @@ export class StreamClient {
461
461
  this.listeners[key] = this.listeners[key].filter(
462
462
  (value) => value !== callback,
463
463
  );
464
- }
464
+ };
465
465
 
466
- _logApiRequest(
466
+ _logApiRequest = (
467
467
  type: string,
468
468
  url: string,
469
469
  data: unknown,
470
470
  config: AxiosRequestConfig & {
471
471
  config?: AxiosRequestConfig & { maxBodyLength?: number };
472
472
  },
473
- ) {
473
+ ) => {
474
474
  this.logger('trace', `client: ${type} - Request - ${url}`, {
475
475
  payload: data,
476
476
  config,
477
477
  });
478
- }
478
+ };
479
479
 
480
- _logApiResponse<T>(type: string, url: string, response: AxiosResponse<T>) {
480
+ _logApiResponse = <T>(
481
+ type: string,
482
+ url: string,
483
+ response: AxiosResponse<T>,
484
+ ) => {
481
485
  this.logger(
482
486
  'trace',
483
487
  `client:${type} - Response - url: ${url} > status ${response.status}`,
@@ -488,14 +492,14 @@ export class StreamClient {
488
492
  this.logger('trace', `client:${type} - Response payload`, {
489
493
  response,
490
494
  });
491
- }
495
+ };
492
496
 
493
- _logApiError(type: string, url: string, error: unknown) {
497
+ _logApiError = (type: string, url: string, error: unknown) => {
494
498
  this.logger('error', `client:${type} - Error - url: ${url}`, {
495
499
  url,
496
500
  error,
497
501
  });
498
- }
502
+ };
499
503
 
500
504
  doAxiosRequest = async <T, D = unknown>(
501
505
  type: string,
@@ -568,33 +572,33 @@ export class StreamClient {
568
572
  }
569
573
  };
570
574
 
571
- get<T>(url: string, params?: AxiosRequestConfig['params']) {
575
+ get = <T>(url: string, params?: AxiosRequestConfig['params']) => {
572
576
  return this.doAxiosRequest<T, unknown>('get', url, null, {
573
577
  params,
574
578
  });
575
- }
579
+ };
576
580
 
577
- put<T, D = unknown>(url: string, data?: D) {
581
+ put = <T, D = unknown>(url: string, data?: D) => {
578
582
  return this.doAxiosRequest<T, D>('put', url, data);
579
- }
583
+ };
580
584
 
581
- post<T, D = unknown>(url: string, data?: D) {
585
+ post = <T, D = unknown>(url: string, data?: D) => {
582
586
  return this.doAxiosRequest<T, D>('post', url, data);
583
- }
587
+ };
584
588
 
585
- patch<T, D = unknown>(url: string, data?: D) {
589
+ patch = <T, D = unknown>(url: string, data?: D) => {
586
590
  return this.doAxiosRequest<T, D>('patch', url, data);
587
- }
591
+ };
588
592
 
589
- delete<T>(url: string, params?: AxiosRequestConfig['params']) {
593
+ delete = <T>(url: string, params?: AxiosRequestConfig['params']) => {
590
594
  return this.doAxiosRequest<T, unknown>('delete', url, null, {
591
595
  params,
592
596
  });
593
- }
597
+ };
594
598
 
595
- errorFromResponse(
599
+ errorFromResponse = (
596
600
  response: AxiosResponse<APIErrorResponse>,
597
- ): ErrorFromResponse<APIErrorResponse> {
601
+ ): ErrorFromResponse<APIErrorResponse> => {
598
602
  let err: ErrorFromResponse<APIErrorResponse>;
599
603
  err = new ErrorFromResponse(`Stream error HTTP code: ${response.status}`);
600
604
  if (response.data && response.data.code) {
@@ -606,15 +610,15 @@ export class StreamClient {
606
610
  err.response = response;
607
611
  err.status = response.status;
608
612
  return err;
609
- }
613
+ };
610
614
 
611
- handleResponse<T>(response: AxiosResponse<T>) {
615
+ handleResponse = <T>(response: AxiosResponse<T>) => {
612
616
  const data = response.data;
613
617
  if (isErrorResponse(response)) {
614
618
  throw this.errorFromResponse(response);
615
619
  }
616
620
  return data;
617
- }
621
+ };
618
622
 
619
623
  dispatchEvent = (event: StreamVideoEvent) => {
620
624
  if (!event.received_at) event.received_at = new Date();
@@ -650,7 +654,7 @@ export class StreamClient {
650
654
  /**
651
655
  * @private
652
656
  */
653
- async connect() {
657
+ connect = async () => {
654
658
  if (!this.userID || !this._user) {
655
659
  throw Error(
656
660
  'Call connectUser or connectAnonymousUser before starting the connection',
@@ -716,14 +720,14 @@ export class StreamClient {
716
720
 
717
721
  throw err;
718
722
  }
719
- }
723
+ };
720
724
 
721
725
  /**
722
726
  * Check the connectivity with server for warmup purpose.
723
727
  *
724
728
  * @private
725
729
  */
726
- _sayHi() {
730
+ _sayHi = () => {
727
731
  const client_request_id = randomId();
728
732
  const opts = {
729
733
  headers: AxiosHeaders.from({
@@ -739,27 +743,27 @@ export class StreamClient {
739
743
  });
740
744
  }
741
745
  });
742
- }
746
+ };
743
747
 
744
- getUserAgent() {
748
+ getUserAgent = () => {
745
749
  return (
746
750
  this.userAgent ||
747
751
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${
748
752
  process.env.PKG_VERSION
749
753
  }`
750
754
  );
751
- }
755
+ };
752
756
 
753
- setUserAgent(userAgent: string) {
757
+ setUserAgent = (userAgent: string) => {
754
758
  this.userAgent = userAgent;
755
- }
759
+ };
756
760
 
757
761
  /**
758
762
  * _isUsingServerAuth - Returns true if we're using server side auth
759
763
  */
760
764
  _isUsingServerAuth = () => !!this.secret;
761
765
 
762
- _enrichAxiosOptions(
766
+ _enrichAxiosOptions = (
763
767
  options: AxiosRequestConfig & { config?: AxiosRequestConfig } & {
764
768
  publicEndpoint?: boolean;
765
769
  } = {
@@ -767,7 +771,7 @@ export class StreamClient {
767
771
  headers: {},
768
772
  config: {},
769
773
  },
770
- ): AxiosRequestConfig {
774
+ ): AxiosRequestConfig => {
771
775
  const token =
772
776
  options.publicEndpoint && !this.user ? undefined : this._getToken();
773
777
  const authorization = token ? { Authorization: token } : undefined;
@@ -804,13 +808,13 @@ export class StreamClient {
804
808
  ...options.config,
805
809
  ...this.options.axiosRequestConfig,
806
810
  };
807
- }
811
+ };
808
812
 
809
- _getToken() {
813
+ _getToken = () => {
810
814
  if (!this.tokenManager) return null;
811
815
 
812
816
  return this.tokenManager.getToken();
813
- }
817
+ };
814
818
 
815
819
  /**
816
820
  * encode ws url payload
@@ -828,9 +832,9 @@ export class StreamClient {
828
832
  /**
829
833
  * creates an abort controller that will be used by the next HTTP Request.
830
834
  */
831
- createAbortControllerForNextRequest() {
835
+ createAbortControllerForNextRequest = () => {
832
836
  return (this.nextRequestAbortController = new AbortController());
833
- }
837
+ };
834
838
 
835
839
  /**
836
840
  * createToken - Creates a token to authenticate this user. This function is used server side.
@@ -842,12 +846,12 @@ export class StreamClient {
842
846
  *
843
847
  * @return {string} Returns a token
844
848
  */
845
- createToken(
849
+ createToken = (
846
850
  userID: string,
847
851
  exp?: number,
848
852
  iat?: number,
849
853
  call_cids?: string[],
850
- ) {
854
+ ) => {
851
855
  if (this.secret == null) {
852
856
  throw Error(
853
857
  `tokens can only be created server-side using the API Secret`,
@@ -868,5 +872,5 @@ export class StreamClient {
868
872
  }
869
873
 
870
874
  return JWTUserToken(this.secret, userID, extra, {});
871
- }
875
+ };
872
876
  }
@@ -105,11 +105,11 @@ export class StableWSConnection {
105
105
  addConnectionEventListeners(this.onlineStatusChanged);
106
106
  }
107
107
 
108
- _log(msg: string, extra: UR = {}, level: LogLevel = 'info') {
108
+ _log = (msg: string, extra: UR = {}, level: LogLevel = 'info') => {
109
109
  this.client.logger(level, 'connection:' + msg, {
110
110
  ...extra,
111
111
  });
112
- }
112
+ };
113
113
 
114
114
  setClient = (client: StreamClient) => {
115
115
  this.client = client;
@@ -475,7 +475,8 @@ export class StableWSConnection {
475
475
  if (event.type === 'offline') {
476
476
  // mark the connection as down
477
477
  this._log('onlineStatusChanged() - Status changing to offline');
478
- this._setHealth(false);
478
+ // we know that the app is offline so dispatch the unhealthy connection event immediately
479
+ this._setHealth(false, true);
479
480
  } else if (event.type === 'online') {
480
481
  // retry right now...
481
482
  // We check this.isHealthy, not sure if it's always
@@ -628,14 +629,15 @@ export class StableWSConnection {
628
629
  * Broadcasts an event in case the connection status changed.
629
630
  *
630
631
  * @param {boolean} healthy boolean indicating if the connection is healthy or not
632
+ * @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
631
633
  *
632
634
  */
633
- _setHealth = (healthy: boolean) => {
635
+ _setHealth = (healthy: boolean, dispatchImmediately = false) => {
634
636
  if (healthy === this.isHealthy) return;
635
637
 
636
638
  this.isHealthy = healthy;
637
639
 
638
- if (this.isHealthy) {
640
+ if (this.isHealthy || dispatchImmediately) {
639
641
  this.client.dispatchEvent({
640
642
  type: 'connection.changed',
641
643
  online: this.isHealthy,