@stream-io/video-client 1.11.6 → 1.11.7
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/CHANGELOG.md +7 -0
- package/dist/index.browser.es.js +68 -562
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +53 -547
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +68 -562
- package/dist/index.es.js.map +1 -1
- package/dist/src/coordinator/connection/client.d.ts +0 -18
- package/dist/src/coordinator/connection/connection.d.ts +4 -12
- package/dist/src/coordinator/connection/signing.d.ts +1 -7
- package/dist/src/coordinator/connection/token_manager.d.ts +0 -2
- package/dist/src/coordinator/connection/types.d.ts +5 -6
- package/dist/src/coordinator/connection/utils.d.ts +6 -8
- package/package.json +6 -10
- package/src/__tests__/Call.test.ts +3 -2
- package/src/coordinator/connection/client.ts +12 -149
- package/src/coordinator/connection/connection.ts +40 -109
- package/src/coordinator/connection/signing.ts +31 -17
- package/src/coordinator/connection/token_manager.ts +3 -9
- package/src/coordinator/connection/types.ts +5 -9
- package/src/coordinator/connection/utils.ts +18 -50
- package/src/devices/__tests__/InputMediaDeviceManagerState.test.ts +13 -8
- package/src/devices/__tests__/mocks.ts +0 -4
- package/dist/src/coordinator/connection/base64.d.ts +0 -2
- package/dist/src/coordinator/connection/connection_fallback.d.ts +0 -39
- package/dist/src/coordinator/connection/errors.d.ts +0 -16
- package/dist/src/coordinator/connection/insights.d.ts +0 -57
- package/src/coordinator/connection/base64.ts +0 -80
- package/src/coordinator/connection/connection_fallback.ts +0 -242
- package/src/coordinator/connection/errors.ts +0 -80
- package/src/coordinator/connection/insights.ts +0 -88
package/dist/index.cjs.js
CHANGED
|
@@ -9,8 +9,6 @@ var uaParserJs = require('ua-parser-js');
|
|
|
9
9
|
var rxjs = require('rxjs');
|
|
10
10
|
var SDP = require('sdp-transform');
|
|
11
11
|
var https = require('https');
|
|
12
|
-
var WebSocket$1 = require('isomorphic-ws');
|
|
13
|
-
var base64Js = require('base64-js');
|
|
14
12
|
|
|
15
13
|
function _interopNamespaceDefault(e) {
|
|
16
14
|
var n = Object.create(null);
|
|
@@ -3195,42 +3193,6 @@ function getRandomBytes(length) {
|
|
|
3195
3193
|
getRandomValues(bytes);
|
|
3196
3194
|
return bytes;
|
|
3197
3195
|
}
|
|
3198
|
-
function convertErrorToJson(err) {
|
|
3199
|
-
const jsonObj = {};
|
|
3200
|
-
if (!err)
|
|
3201
|
-
return jsonObj;
|
|
3202
|
-
try {
|
|
3203
|
-
Object.getOwnPropertyNames(err).forEach((key) => {
|
|
3204
|
-
jsonObj[key] = Object.getOwnPropertyDescriptor(err, key);
|
|
3205
|
-
});
|
|
3206
|
-
}
|
|
3207
|
-
catch (_) {
|
|
3208
|
-
return {
|
|
3209
|
-
error: 'failed to serialize the error',
|
|
3210
|
-
};
|
|
3211
|
-
}
|
|
3212
|
-
return jsonObj;
|
|
3213
|
-
}
|
|
3214
|
-
/**
|
|
3215
|
-
* isOnline safely return the navigator.online value for browser env
|
|
3216
|
-
* if navigator is not in global object, it always return true
|
|
3217
|
-
*/
|
|
3218
|
-
function isOnline(logger) {
|
|
3219
|
-
const nav = typeof navigator !== 'undefined'
|
|
3220
|
-
? navigator
|
|
3221
|
-
: typeof window !== 'undefined' && window.navigator
|
|
3222
|
-
? window.navigator
|
|
3223
|
-
: undefined;
|
|
3224
|
-
if (!nav) {
|
|
3225
|
-
logger('warn', 'isOnline failed to access window.navigator and assume browser is online');
|
|
3226
|
-
return true;
|
|
3227
|
-
}
|
|
3228
|
-
// RN navigator has undefined for onLine
|
|
3229
|
-
if (typeof nav.onLine !== 'boolean') {
|
|
3230
|
-
return true;
|
|
3231
|
-
}
|
|
3232
|
-
return nav.onLine;
|
|
3233
|
-
}
|
|
3234
3196
|
/**
|
|
3235
3197
|
* listenForConnectionChanges - Adds an event listener fired on browser going online or offline
|
|
3236
3198
|
*/
|
|
@@ -3246,6 +3208,13 @@ function removeConnectionEventListeners(cb) {
|
|
|
3246
3208
|
window.removeEventListener('online', cb);
|
|
3247
3209
|
}
|
|
3248
3210
|
}
|
|
3211
|
+
function isErrorResponse(res) {
|
|
3212
|
+
return !res.status || res.status < 200 || 300 <= res.status;
|
|
3213
|
+
}
|
|
3214
|
+
// Type guards to check WebSocket error type
|
|
3215
|
+
function isCloseEvent(res) {
|
|
3216
|
+
return res.code !== undefined;
|
|
3217
|
+
}
|
|
3249
3218
|
|
|
3250
3219
|
/**
|
|
3251
3220
|
* Checks whether we are using React Native
|
|
@@ -3349,7 +3318,7 @@ const retryable = async (rpc, signal) => {
|
|
|
3349
3318
|
return result;
|
|
3350
3319
|
};
|
|
3351
3320
|
|
|
3352
|
-
const version = "1.11.
|
|
3321
|
+
const version = "1.11.7";
|
|
3353
3322
|
const [major, minor, patch] = version.split('.');
|
|
3354
3323
|
let sdkInfo = {
|
|
3355
3324
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -11521,68 +11490,6 @@ class Call {
|
|
|
11521
11490
|
}
|
|
11522
11491
|
}
|
|
11523
11492
|
|
|
11524
|
-
class InsightMetrics {
|
|
11525
|
-
constructor() {
|
|
11526
|
-
this.connectionStartTimestamp = null;
|
|
11527
|
-
this.wsTotalFailures = 0;
|
|
11528
|
-
this.wsConsecutiveFailures = 0;
|
|
11529
|
-
this.instanceClientId = randomId();
|
|
11530
|
-
}
|
|
11531
|
-
}
|
|
11532
|
-
/**
|
|
11533
|
-
* postInsights is not supposed to be used by end users directly within chat application, and thus is kept isolated
|
|
11534
|
-
* from all the client/connection code/logic.
|
|
11535
|
-
*
|
|
11536
|
-
* @param insightType
|
|
11537
|
-
* @param insights
|
|
11538
|
-
*/
|
|
11539
|
-
const postInsights = async (insightType, insights) => {
|
|
11540
|
-
const maxAttempts = 3;
|
|
11541
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
11542
|
-
try {
|
|
11543
|
-
await axios.post(`https://chat-insights.getstream.io/insights/${insightType}`, insights);
|
|
11544
|
-
}
|
|
11545
|
-
catch (e) {
|
|
11546
|
-
await sleep((i + 1) * 3000);
|
|
11547
|
-
continue;
|
|
11548
|
-
}
|
|
11549
|
-
break;
|
|
11550
|
-
}
|
|
11551
|
-
};
|
|
11552
|
-
function buildWsFatalInsight(connection, event) {
|
|
11553
|
-
return {
|
|
11554
|
-
...event,
|
|
11555
|
-
...buildWsBaseInsight(connection),
|
|
11556
|
-
};
|
|
11557
|
-
}
|
|
11558
|
-
function buildWsBaseInsight(connection) {
|
|
11559
|
-
const { client } = connection;
|
|
11560
|
-
return {
|
|
11561
|
-
ready_state: connection.ws?.readyState,
|
|
11562
|
-
url: connection._buildUrl(),
|
|
11563
|
-
api_key: client.key,
|
|
11564
|
-
start_ts: client.insightMetrics.connectionStartTimestamp,
|
|
11565
|
-
end_ts: new Date().getTime(),
|
|
11566
|
-
auth_type: client.getAuthType(),
|
|
11567
|
-
token: client.tokenManager.token,
|
|
11568
|
-
user_id: client.userID,
|
|
11569
|
-
user_details: client._user,
|
|
11570
|
-
// device: client.options.device,
|
|
11571
|
-
device: 'browser',
|
|
11572
|
-
client_id: connection.connectionID,
|
|
11573
|
-
ws_details: connection.ws,
|
|
11574
|
-
ws_consecutive_failures: client.insightMetrics.wsConsecutiveFailures,
|
|
11575
|
-
ws_total_failures: client.insightMetrics.wsTotalFailures,
|
|
11576
|
-
request_id: connection.requestID,
|
|
11577
|
-
online: typeof navigator !== 'undefined' ? navigator?.onLine : null,
|
|
11578
|
-
user_agent: typeof navigator !== 'undefined' ? navigator?.userAgent : null,
|
|
11579
|
-
instance_client_id: client.insightMetrics.instanceClientId,
|
|
11580
|
-
};
|
|
11581
|
-
}
|
|
11582
|
-
function buildWsSuccessAfterFailureInsight(connection) {
|
|
11583
|
-
return buildWsBaseInsight(connection);
|
|
11584
|
-
}
|
|
11585
|
-
|
|
11586
11493
|
/**
|
|
11587
11494
|
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
11588
11495
|
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
@@ -11610,9 +11517,6 @@ function makeSafePromise(promise) {
|
|
|
11610
11517
|
return unwrapPromise;
|
|
11611
11518
|
}
|
|
11612
11519
|
|
|
11613
|
-
// Type guards to check WebSocket error type
|
|
11614
|
-
const isCloseEvent = (res) => res.code !== undefined;
|
|
11615
|
-
const isErrorEvent = (res) => res.error !== undefined;
|
|
11616
11520
|
/**
|
|
11617
11521
|
* StableWSConnection - A WS connection that reconnects upon failure.
|
|
11618
11522
|
* - the browser will sometimes report that you're online or offline
|
|
@@ -11647,12 +11551,9 @@ class StableWSConnection {
|
|
|
11647
11551
|
*/
|
|
11648
11552
|
this._buildUrl = () => {
|
|
11649
11553
|
const params = new URLSearchParams();
|
|
11650
|
-
// const qs = encodeURIComponent(this.client._buildWSPayload(this.requestID));
|
|
11651
|
-
// params.set('json', qs);
|
|
11652
11554
|
params.set('api_key', this.client.key);
|
|
11653
11555
|
params.set('stream-auth-type', this.client.getAuthType());
|
|
11654
11556
|
params.set('X-Stream-Client', this.client.getUserAgent());
|
|
11655
|
-
// params.append('authorization', this.client._getToken()!);
|
|
11656
11557
|
return `${this.client.wsBaseURL}/connect?${params.toString()}`;
|
|
11657
11558
|
};
|
|
11658
11559
|
/**
|
|
@@ -11701,7 +11602,6 @@ class StableWSConnection {
|
|
|
11701
11602
|
custom: user.custom,
|
|
11702
11603
|
},
|
|
11703
11604
|
};
|
|
11704
|
-
this.authenticationSent = true;
|
|
11705
11605
|
this.ws?.send(JSON.stringify(authMessage));
|
|
11706
11606
|
this._log('onopen() - onopen callback', { wsID });
|
|
11707
11607
|
};
|
|
@@ -11718,7 +11618,6 @@ class StableWSConnection {
|
|
|
11718
11618
|
if (!this.isResolved && data && data.type === 'connection.error') {
|
|
11719
11619
|
this.isResolved = true;
|
|
11720
11620
|
if (data.error) {
|
|
11721
|
-
// @ts-expect-error - the types of _errorFromWSEvent are incorrect
|
|
11722
11621
|
this.rejectPromise?.(this._errorFromWSEvent(data, false));
|
|
11723
11622
|
return;
|
|
11724
11623
|
}
|
|
@@ -11760,9 +11659,13 @@ class StableWSConnection {
|
|
|
11760
11659
|
// this is a permanent error raised by stream..
|
|
11761
11660
|
// usually caused by invalid auth details
|
|
11762
11661
|
const error = new Error(`WS connection reject with error ${event.reason}`);
|
|
11662
|
+
// @ts-expect-error
|
|
11763
11663
|
error.reason = event.reason;
|
|
11664
|
+
// @ts-expect-error
|
|
11764
11665
|
error.code = event.code;
|
|
11666
|
+
// @ts-expect-error
|
|
11765
11667
|
error.wasClean = event.wasClean;
|
|
11668
|
+
// @ts-expect-error
|
|
11766
11669
|
error.target = event.target;
|
|
11767
11670
|
this.rejectPromise?.(error);
|
|
11768
11671
|
this._log(`onclose() - WS connection reject with error ${event.reason}`, {
|
|
@@ -11789,7 +11692,7 @@ class StableWSConnection {
|
|
|
11789
11692
|
this.totalFailures += 1;
|
|
11790
11693
|
this._setHealth(false);
|
|
11791
11694
|
this.isConnecting = false;
|
|
11792
|
-
this.rejectPromise?.(
|
|
11695
|
+
this.rejectPromise?.(new Error(`WebSocket error: ${event}`));
|
|
11793
11696
|
this._log(`onerror() - WS connection resulted into error`, { event });
|
|
11794
11697
|
this._reconnect();
|
|
11795
11698
|
};
|
|
@@ -11799,7 +11702,6 @@ class StableWSConnection {
|
|
|
11799
11702
|
*
|
|
11800
11703
|
* @param {boolean} healthy boolean indicating if the connection is healthy or not
|
|
11801
11704
|
* @param {boolean} dispatchImmediately boolean indicating to dispatch event immediately even if the connection is unhealthy
|
|
11802
|
-
*
|
|
11803
11705
|
*/
|
|
11804
11706
|
this._setHealth = (healthy, dispatchImmediately = false) => {
|
|
11805
11707
|
if (healthy === this.isHealthy)
|
|
@@ -11824,7 +11726,6 @@ class StableWSConnection {
|
|
|
11824
11726
|
};
|
|
11825
11727
|
/**
|
|
11826
11728
|
* _errorFromWSEvent - Creates an error object for the WS event
|
|
11827
|
-
*
|
|
11828
11729
|
*/
|
|
11829
11730
|
this._errorFromWSEvent = (event, isWSFailure = true) => {
|
|
11830
11731
|
let code;
|
|
@@ -11832,17 +11733,18 @@ class StableWSConnection {
|
|
|
11832
11733
|
let message;
|
|
11833
11734
|
if (isCloseEvent(event)) {
|
|
11834
11735
|
code = event.code;
|
|
11835
|
-
statusCode = 'unknown';
|
|
11836
11736
|
message = event.reason;
|
|
11737
|
+
statusCode = 0;
|
|
11837
11738
|
}
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
message =
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11739
|
+
else {
|
|
11740
|
+
const { error } = event;
|
|
11741
|
+
code = error.code;
|
|
11742
|
+
message = error.message;
|
|
11743
|
+
statusCode = error.StatusCode;
|
|
11744
|
+
}
|
|
11745
|
+
const msg = `WS failed with code: ${code} and reason: ${message}`;
|
|
11746
|
+
this._log(msg, { event }, 'warn');
|
|
11747
|
+
const error = new Error(msg);
|
|
11846
11748
|
error.code = code;
|
|
11847
11749
|
/**
|
|
11848
11750
|
* StatusCode does not exist on any event types but has been left
|
|
@@ -11867,10 +11769,8 @@ class StableWSConnection {
|
|
|
11867
11769
|
* Schedules a next health check ping for websocket.
|
|
11868
11770
|
*/
|
|
11869
11771
|
this.scheduleNextPing = () => {
|
|
11870
|
-
if (this.healthCheckTimeoutRef) {
|
|
11871
|
-
clearTimeout(this.healthCheckTimeoutRef);
|
|
11872
|
-
}
|
|
11873
11772
|
// 30 seconds is the recommended interval (messenger uses this)
|
|
11773
|
+
clearTimeout(this.healthCheckTimeoutRef);
|
|
11874
11774
|
this.healthCheckTimeoutRef = setTimeout(() => {
|
|
11875
11775
|
// send the healthcheck..., server replies with a health check event
|
|
11876
11776
|
const data = [{ type: 'health.check', client_id: this.client.clientID }];
|
|
@@ -11889,9 +11789,7 @@ class StableWSConnection {
|
|
|
11889
11789
|
* to be reconnected.
|
|
11890
11790
|
*/
|
|
11891
11791
|
this.scheduleConnectionCheck = () => {
|
|
11892
|
-
|
|
11893
|
-
clearTimeout(this.connectionCheckTimeoutRef);
|
|
11894
|
-
}
|
|
11792
|
+
clearTimeout(this.connectionCheckTimeoutRef);
|
|
11895
11793
|
this.connectionCheckTimeoutRef = setTimeout(() => {
|
|
11896
11794
|
const now = new Date();
|
|
11897
11795
|
if (this.lastEvent &&
|
|
@@ -11909,8 +11807,6 @@ class StableWSConnection {
|
|
|
11909
11807
|
this.totalFailures = 0;
|
|
11910
11808
|
/** We only make 1 attempt to reconnect at the same time.. */
|
|
11911
11809
|
this.isConnecting = false;
|
|
11912
|
-
/** True after the auth payload is sent to the server */
|
|
11913
|
-
this.authenticationSent = false;
|
|
11914
11810
|
/** To avoid reconnect if client is disconnected */
|
|
11915
11811
|
this.isDisconnected = false;
|
|
11916
11812
|
/** Boolean that indicates if the connection promise is resolved */
|
|
@@ -12018,18 +11914,10 @@ class StableWSConnection {
|
|
|
12018
11914
|
this.isConnecting = false;
|
|
12019
11915
|
this.isDisconnected = true;
|
|
12020
11916
|
// start by removing all the listeners
|
|
12021
|
-
|
|
12022
|
-
|
|
12023
|
-
}
|
|
12024
|
-
if (this.connectionCheckTimeoutRef) {
|
|
12025
|
-
clearInterval(this.connectionCheckTimeoutRef);
|
|
12026
|
-
}
|
|
11917
|
+
clearInterval(this.healthCheckTimeoutRef);
|
|
11918
|
+
clearInterval(this.connectionCheckTimeoutRef);
|
|
12027
11919
|
removeConnectionEventListeners(this.onlineStatusChanged);
|
|
12028
11920
|
this.isHealthy = false;
|
|
12029
|
-
// remove ws handlers...
|
|
12030
|
-
if (this.ws && this.ws.removeAllListeners) {
|
|
12031
|
-
this.ws.removeAllListeners();
|
|
12032
|
-
}
|
|
12033
11921
|
let isClosedPromise;
|
|
12034
11922
|
// and finally close...
|
|
12035
11923
|
// Assigning to local here because we will remove it from this before the
|
|
@@ -12062,12 +11950,10 @@ class StableWSConnection {
|
|
|
12062
11950
|
* @return {ConnectAPIResponse<ConnectedEvent>} Promise that completes once the first health check message is received
|
|
12063
11951
|
*/
|
|
12064
11952
|
async _connect() {
|
|
12065
|
-
if (this.isConnecting
|
|
12066
|
-
(this.isDisconnected && this.client.options.enableWSFallback))
|
|
11953
|
+
if (this.isConnecting)
|
|
12067
11954
|
return; // simply ignore _connect if it's currently trying to connect
|
|
12068
11955
|
this.isConnecting = true;
|
|
12069
11956
|
this.requestID = randomId();
|
|
12070
|
-
this.client.insightMetrics.connectionStartTimestamp = new Date().getTime();
|
|
12071
11957
|
let isTokenReady = false;
|
|
12072
11958
|
try {
|
|
12073
11959
|
this._log(`_connect() - waiting for token`);
|
|
@@ -12091,7 +11977,8 @@ class StableWSConnection {
|
|
|
12091
11977
|
wsURL,
|
|
12092
11978
|
requestID: this.requestID,
|
|
12093
11979
|
});
|
|
12094
|
-
this.
|
|
11980
|
+
const WS = this.client.options.WebSocketImpl ?? WebSocket;
|
|
11981
|
+
this.ws = new WS(wsURL);
|
|
12095
11982
|
this.ws.onopen = this.onopen.bind(this, this.wsID);
|
|
12096
11983
|
this.ws.onclose = this.onclose.bind(this, this.wsID);
|
|
12097
11984
|
this.ws.onerror = this.onerror.bind(this, this.wsID);
|
|
@@ -12101,11 +11988,6 @@ class StableWSConnection {
|
|
|
12101
11988
|
if (response) {
|
|
12102
11989
|
this.connectionID = response.connection_id;
|
|
12103
11990
|
this.client.resolveConnectionId?.(this.connectionID);
|
|
12104
|
-
if (this.client.insightMetrics.wsConsecutiveFailures > 0 &&
|
|
12105
|
-
this.client.options.enableInsights) {
|
|
12106
|
-
postInsights('ws_success_after_failure', buildWsSuccessAfterFailureInsight(this));
|
|
12107
|
-
this.client.insightMetrics.wsConsecutiveFailures = 0;
|
|
12108
|
-
}
|
|
12109
11991
|
return response;
|
|
12110
11992
|
}
|
|
12111
11993
|
}
|
|
@@ -12114,12 +11996,6 @@ class StableWSConnection {
|
|
|
12114
11996
|
this.isConnecting = false;
|
|
12115
11997
|
// @ts-ignore
|
|
12116
11998
|
this._log(`_connect() - Error - `, err);
|
|
12117
|
-
if (this.client.options.enableInsights) {
|
|
12118
|
-
this.client.insightMetrics.wsConsecutiveFailures++;
|
|
12119
|
-
this.client.insightMetrics.wsTotalFailures++;
|
|
12120
|
-
const insights = buildWsFatalInsight(this, convertErrorToJson(err));
|
|
12121
|
-
postInsights?.('ws_fatal', insights);
|
|
12122
|
-
}
|
|
12123
11999
|
this.client.rejectConnectionId?.(err);
|
|
12124
12000
|
throw err;
|
|
12125
12001
|
}
|
|
@@ -12153,7 +12029,7 @@ class StableWSConnection {
|
|
|
12153
12029
|
this._log('_reconnect() - Abort (2) since already connecting or healthy');
|
|
12154
12030
|
return;
|
|
12155
12031
|
}
|
|
12156
|
-
if (this.isDisconnected
|
|
12032
|
+
if (this.isDisconnected) {
|
|
12157
12033
|
this._log('_reconnect() - Abort (3) since disconnect() is called');
|
|
12158
12034
|
return;
|
|
12159
12035
|
}
|
|
@@ -12195,7 +12071,6 @@ class StableWSConnection {
|
|
|
12195
12071
|
// ws connection from now on.
|
|
12196
12072
|
this.wsID += 1;
|
|
12197
12073
|
try {
|
|
12198
|
-
this?.ws?.removeAllListeners();
|
|
12199
12074
|
this?.ws?.close();
|
|
12200
12075
|
}
|
|
12201
12076
|
catch (e) {
|
|
@@ -12207,36 +12082,16 @@ class StableWSConnection {
|
|
|
12207
12082
|
}
|
|
12208
12083
|
}
|
|
12209
12084
|
|
|
12210
|
-
function
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
return !!callback && isString(arrayOrString);
|
|
12215
|
-
}
|
|
12216
|
-
function map(arrayOrString, callback) {
|
|
12217
|
-
const res = [];
|
|
12218
|
-
if (isString(arrayOrString) && isMapStringCallback(arrayOrString, callback)) {
|
|
12219
|
-
for (let k = 0, len = arrayOrString.length; k < len; k++) {
|
|
12220
|
-
if (arrayOrString.charAt(k)) {
|
|
12221
|
-
const kValue = arrayOrString.charAt(k);
|
|
12222
|
-
const mappedValue = callback(kValue, k, arrayOrString);
|
|
12223
|
-
res[k] = mappedValue;
|
|
12224
|
-
}
|
|
12225
|
-
}
|
|
12226
|
-
}
|
|
12227
|
-
else if (!isString(arrayOrString) &&
|
|
12228
|
-
!isMapStringCallback(arrayOrString, callback)) {
|
|
12229
|
-
for (let k = 0, len = arrayOrString.length; k < len; k++) {
|
|
12230
|
-
if (k in arrayOrString) {
|
|
12231
|
-
const kValue = arrayOrString[k];
|
|
12232
|
-
const mappedValue = callback(kValue, k, arrayOrString);
|
|
12233
|
-
res[k] = mappedValue;
|
|
12234
|
-
}
|
|
12235
|
-
}
|
|
12085
|
+
function getUserFromToken(token) {
|
|
12086
|
+
const fragments = token.split('.');
|
|
12087
|
+
if (fragments.length !== 3) {
|
|
12088
|
+
return '';
|
|
12236
12089
|
}
|
|
12237
|
-
|
|
12090
|
+
const b64Payload = fragments[1];
|
|
12091
|
+
const payload = decodeBase64(b64Payload);
|
|
12092
|
+
const data = JSON.parse(payload);
|
|
12093
|
+
return data.user_id;
|
|
12238
12094
|
}
|
|
12239
|
-
const encodeBase64 = (data) => base64Js.fromByteArray(new Uint8Array(map(data, (char) => char.charCodeAt(0))));
|
|
12240
12095
|
// base-64 decoder throws exception if encoded string is not padded by '=' to make string length
|
|
12241
12096
|
// in multiples of 4. So gonna use our own method for this purpose to keep backwards compatibility
|
|
12242
12097
|
// https://github.com/beatgammit/base64-js/blob/master/index.js#L26
|
|
@@ -12258,29 +12113,6 @@ const decodeBase64 = (s) => {
|
|
|
12258
12113
|
return r;
|
|
12259
12114
|
};
|
|
12260
12115
|
|
|
12261
|
-
/**
|
|
12262
|
-
*
|
|
12263
|
-
* @param {string} userId the id of the user
|
|
12264
|
-
* @return {string}
|
|
12265
|
-
*/
|
|
12266
|
-
function DevToken(userId) {
|
|
12267
|
-
return [
|
|
12268
|
-
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', //{"alg": "HS256", "typ": "JWT"}
|
|
12269
|
-
encodeBase64(JSON.stringify({ user_id: userId })),
|
|
12270
|
-
'devtoken', // hardcoded signature
|
|
12271
|
-
].join('.');
|
|
12272
|
-
}
|
|
12273
|
-
function UserFromToken(token) {
|
|
12274
|
-
const fragments = token.split('.');
|
|
12275
|
-
if (fragments.length !== 3) {
|
|
12276
|
-
return '';
|
|
12277
|
-
}
|
|
12278
|
-
const b64Payload = fragments[1];
|
|
12279
|
-
const payload = decodeBase64(b64Payload);
|
|
12280
|
-
const data = JSON.parse(payload);
|
|
12281
|
-
return data.user_id;
|
|
12282
|
-
}
|
|
12283
|
-
|
|
12284
12116
|
/**
|
|
12285
12117
|
* TokenManager
|
|
12286
12118
|
*
|
|
@@ -12289,8 +12121,6 @@ function UserFromToken(token) {
|
|
|
12289
12121
|
class TokenManager {
|
|
12290
12122
|
/**
|
|
12291
12123
|
* Constructor
|
|
12292
|
-
*
|
|
12293
|
-
* @param {Secret} secret
|
|
12294
12124
|
*/
|
|
12295
12125
|
constructor(secret) {
|
|
12296
12126
|
/**
|
|
@@ -12343,7 +12173,7 @@ class TokenManager {
|
|
|
12343
12173
|
// Allow empty token for anonymous users
|
|
12344
12174
|
if (isAnonymous && tokenOrProvider === '')
|
|
12345
12175
|
return;
|
|
12346
|
-
const tokenUserId =
|
|
12176
|
+
const tokenUserId = getUserFromToken(tokenOrProvider);
|
|
12347
12177
|
if (tokenOrProvider != null &&
|
|
12348
12178
|
(tokenUserId == null ||
|
|
12349
12179
|
tokenUserId === '' ||
|
|
@@ -12358,7 +12188,6 @@ class TokenManager {
|
|
|
12358
12188
|
// Fetches a token from tokenProvider function and sets in tokenManager.
|
|
12359
12189
|
// In case of static token, it will simply resolve to static token.
|
|
12360
12190
|
this.loadToken = () => {
|
|
12361
|
-
// eslint-disable-next-line no-async-promise-executor
|
|
12362
12191
|
this.loadTokenPromise = new Promise(async (resolve, reject) => {
|
|
12363
12192
|
if (this.type === 'static') {
|
|
12364
12193
|
return resolve(this.token);
|
|
@@ -12387,236 +12216,11 @@ class TokenManager {
|
|
|
12387
12216
|
};
|
|
12388
12217
|
this.isStatic = () => this.type === 'static';
|
|
12389
12218
|
this.loadTokenPromise = null;
|
|
12390
|
-
|
|
12391
|
-
this.secret = secret;
|
|
12392
|
-
}
|
|
12219
|
+
this.secret = secret;
|
|
12393
12220
|
this.type = 'static';
|
|
12394
12221
|
}
|
|
12395
12222
|
}
|
|
12396
12223
|
|
|
12397
|
-
const APIErrorCodes = {
|
|
12398
|
-
'-1': { name: 'InternalSystemError', retryable: true },
|
|
12399
|
-
'2': { name: 'AccessKeyError', retryable: false },
|
|
12400
|
-
'3': { name: 'AuthenticationFailedError', retryable: true },
|
|
12401
|
-
'4': { name: 'InputError', retryable: false },
|
|
12402
|
-
'6': { name: 'DuplicateUsernameError', retryable: false },
|
|
12403
|
-
'9': { name: 'RateLimitError', retryable: true },
|
|
12404
|
-
'16': { name: 'DoesNotExistError', retryable: false },
|
|
12405
|
-
'17': { name: 'NotAllowedError', retryable: false },
|
|
12406
|
-
'18': { name: 'EventNotSupportedError', retryable: false },
|
|
12407
|
-
'19': { name: 'ChannelFeatureNotSupportedError', retryable: false },
|
|
12408
|
-
'20': { name: 'MessageTooLongError', retryable: false },
|
|
12409
|
-
'21': { name: 'MultipleNestingLevelError', retryable: false },
|
|
12410
|
-
'22': { name: 'PayloadTooBigError', retryable: false },
|
|
12411
|
-
'23': { name: 'RequestTimeoutError', retryable: true },
|
|
12412
|
-
'24': { name: 'MaxHeaderSizeExceededError', retryable: false },
|
|
12413
|
-
'40': { name: 'AuthErrorTokenExpired', retryable: false },
|
|
12414
|
-
'41': { name: 'AuthErrorTokenNotValidYet', retryable: false },
|
|
12415
|
-
'42': { name: 'AuthErrorTokenUsedBeforeIssuedAt', retryable: false },
|
|
12416
|
-
'43': { name: 'AuthErrorTokenSignatureInvalid', retryable: false },
|
|
12417
|
-
'44': { name: 'CustomCommandEndpointMissingError', retryable: false },
|
|
12418
|
-
'45': { name: 'CustomCommandEndpointCallError', retryable: true },
|
|
12419
|
-
'46': { name: 'ConnectionIDNotFoundError', retryable: false },
|
|
12420
|
-
'60': { name: 'CoolDownError', retryable: true },
|
|
12421
|
-
'69': { name: 'ErrWrongRegion', retryable: false },
|
|
12422
|
-
'70': { name: 'ErrQueryChannelPermissions', retryable: false },
|
|
12423
|
-
'71': { name: 'ErrTooManyConnections', retryable: true },
|
|
12424
|
-
'99': { name: 'AppSuspendedError', retryable: false },
|
|
12425
|
-
};
|
|
12426
|
-
function isAPIError(error) {
|
|
12427
|
-
return error.code !== undefined;
|
|
12428
|
-
}
|
|
12429
|
-
function isErrorRetryable(error) {
|
|
12430
|
-
if (!error.code)
|
|
12431
|
-
return false;
|
|
12432
|
-
const err = APIErrorCodes[`${error.code}`];
|
|
12433
|
-
if (!err)
|
|
12434
|
-
return false;
|
|
12435
|
-
return err.retryable;
|
|
12436
|
-
}
|
|
12437
|
-
function isConnectionIDError(error) {
|
|
12438
|
-
return error.code === 46; // ConnectionIDNotFoundError
|
|
12439
|
-
}
|
|
12440
|
-
function isWSFailure(err) {
|
|
12441
|
-
if (typeof err.isWSFailure === 'boolean') {
|
|
12442
|
-
return err.isWSFailure;
|
|
12443
|
-
}
|
|
12444
|
-
try {
|
|
12445
|
-
return JSON.parse(err.message).isWSFailure;
|
|
12446
|
-
}
|
|
12447
|
-
catch (_) {
|
|
12448
|
-
return false;
|
|
12449
|
-
}
|
|
12450
|
-
}
|
|
12451
|
-
function isErrorResponse(res) {
|
|
12452
|
-
return !res.status || res.status < 200 || 300 <= res.status;
|
|
12453
|
-
}
|
|
12454
|
-
|
|
12455
|
-
var ConnectionState;
|
|
12456
|
-
(function (ConnectionState) {
|
|
12457
|
-
ConnectionState["Closed"] = "CLOSED";
|
|
12458
|
-
ConnectionState["Connected"] = "CONNECTED";
|
|
12459
|
-
ConnectionState["Connecting"] = "CONNECTING";
|
|
12460
|
-
ConnectionState["Disconnected"] = "DISCONNECTED";
|
|
12461
|
-
ConnectionState["Init"] = "INIT";
|
|
12462
|
-
})(ConnectionState || (ConnectionState = {}));
|
|
12463
|
-
class WSConnectionFallback {
|
|
12464
|
-
constructor(client) {
|
|
12465
|
-
/** @private */
|
|
12466
|
-
this._onlineStatusChanged = (event) => {
|
|
12467
|
-
this._log(`_onlineStatusChanged() - ${event.type}`);
|
|
12468
|
-
if (event.type === 'offline') {
|
|
12469
|
-
this._setState(ConnectionState.Closed);
|
|
12470
|
-
this.cancelToken?.cancel('disconnect() is called');
|
|
12471
|
-
this.cancelToken = undefined;
|
|
12472
|
-
return;
|
|
12473
|
-
}
|
|
12474
|
-
if (event.type === 'online' && this.state === ConnectionState.Closed) {
|
|
12475
|
-
this.connect(true);
|
|
12476
|
-
}
|
|
12477
|
-
};
|
|
12478
|
-
/** @private */
|
|
12479
|
-
this._req = async (params, config, retry) => {
|
|
12480
|
-
if (!this.cancelToken && !params.close) {
|
|
12481
|
-
this.cancelToken = axios.CancelToken.source();
|
|
12482
|
-
}
|
|
12483
|
-
try {
|
|
12484
|
-
const res = await this.client.doAxiosRequest('get', this.client.baseURL.replace(':3030', ':8900') + '/longpoll', // replace port if present for testing with local API
|
|
12485
|
-
undefined, {
|
|
12486
|
-
config: { ...config, cancelToken: this.cancelToken?.token },
|
|
12487
|
-
params,
|
|
12488
|
-
publicEndpoint: true,
|
|
12489
|
-
});
|
|
12490
|
-
this.consecutiveFailures = 0; // always reset in case of no error
|
|
12491
|
-
return res;
|
|
12492
|
-
}
|
|
12493
|
-
catch (err) {
|
|
12494
|
-
this.consecutiveFailures += 1;
|
|
12495
|
-
// @ts-ignore
|
|
12496
|
-
if (retry && isErrorRetryable(err)) {
|
|
12497
|
-
this._log(`_req() - Retryable error, retrying request`);
|
|
12498
|
-
await sleep(retryInterval(this.consecutiveFailures));
|
|
12499
|
-
return this._req(params, config, retry);
|
|
12500
|
-
}
|
|
12501
|
-
throw err;
|
|
12502
|
-
}
|
|
12503
|
-
};
|
|
12504
|
-
/** @private */
|
|
12505
|
-
this._poll = async () => {
|
|
12506
|
-
while (this.state === ConnectionState.Connected) {
|
|
12507
|
-
try {
|
|
12508
|
-
const data = await this._req({}, {
|
|
12509
|
-
timeout: 30000,
|
|
12510
|
-
}, true); // 30s => API responds in 20s if there is no event
|
|
12511
|
-
if (data.events?.length) {
|
|
12512
|
-
for (let i = 0; i < data.events.length; i++) {
|
|
12513
|
-
this.client.dispatchEvent(data.events[i]);
|
|
12514
|
-
}
|
|
12515
|
-
}
|
|
12516
|
-
}
|
|
12517
|
-
catch (err) {
|
|
12518
|
-
if (axios.isCancel(err)) {
|
|
12519
|
-
this._log(`_poll() - axios canceled request`);
|
|
12520
|
-
return;
|
|
12521
|
-
}
|
|
12522
|
-
/** client.doAxiosRequest will take care of TOKEN_EXPIRED error */
|
|
12523
|
-
// @ts-ignore
|
|
12524
|
-
if (isConnectionIDError(err)) {
|
|
12525
|
-
this._log(`_poll() - ConnectionID error, connecting without ID...`);
|
|
12526
|
-
this._setState(ConnectionState.Disconnected);
|
|
12527
|
-
this.connect(true);
|
|
12528
|
-
return;
|
|
12529
|
-
}
|
|
12530
|
-
// @ts-ignore
|
|
12531
|
-
if (isAPIError(err) && !isErrorRetryable(err)) {
|
|
12532
|
-
this._setState(ConnectionState.Closed);
|
|
12533
|
-
return;
|
|
12534
|
-
}
|
|
12535
|
-
await sleep(retryInterval(this.consecutiveFailures));
|
|
12536
|
-
}
|
|
12537
|
-
}
|
|
12538
|
-
};
|
|
12539
|
-
/**
|
|
12540
|
-
* connect try to open a longpoll request
|
|
12541
|
-
* @param reconnect should be false for first call and true for subsequent calls to keep the connection alive and call recoverState
|
|
12542
|
-
*/
|
|
12543
|
-
this.connect = async (reconnect = false) => {
|
|
12544
|
-
if (this.state === ConnectionState.Connecting) {
|
|
12545
|
-
this._log('connect() - connecting already in progress', { reconnect }, 'warn');
|
|
12546
|
-
return;
|
|
12547
|
-
}
|
|
12548
|
-
if (this.state === ConnectionState.Connected) {
|
|
12549
|
-
this._log('connect() - already connected and polling', { reconnect }, 'warn');
|
|
12550
|
-
return;
|
|
12551
|
-
}
|
|
12552
|
-
this._setState(ConnectionState.Connecting);
|
|
12553
|
-
this.connectionID = undefined; // connect should be sent with empty connection_id so API creates one
|
|
12554
|
-
try {
|
|
12555
|
-
const { event } = await this._req({ json: this.client._buildWSPayload() }, {
|
|
12556
|
-
timeout: 8000, // 8s
|
|
12557
|
-
}, reconnect);
|
|
12558
|
-
this._setState(ConnectionState.Connected);
|
|
12559
|
-
this.connectionID = event.connection_id;
|
|
12560
|
-
this.client.resolveConnectionId?.();
|
|
12561
|
-
// @ts-expect-error
|
|
12562
|
-
this.client.dispatchEvent(event);
|
|
12563
|
-
this._poll();
|
|
12564
|
-
return event;
|
|
12565
|
-
}
|
|
12566
|
-
catch (err) {
|
|
12567
|
-
this._setState(ConnectionState.Closed);
|
|
12568
|
-
this.client.rejectConnectionId?.();
|
|
12569
|
-
throw err;
|
|
12570
|
-
}
|
|
12571
|
-
};
|
|
12572
|
-
/**
|
|
12573
|
-
* isHealthy checks if there is a connectionID and connection is in Connected state
|
|
12574
|
-
*/
|
|
12575
|
-
this.isHealthy = () => {
|
|
12576
|
-
return !!this.connectionID && this.state === ConnectionState.Connected;
|
|
12577
|
-
};
|
|
12578
|
-
this.disconnect = async (timeout = 2000) => {
|
|
12579
|
-
removeConnectionEventListeners(this._onlineStatusChanged);
|
|
12580
|
-
this._setState(ConnectionState.Disconnected);
|
|
12581
|
-
this.cancelToken?.cancel('disconnect() is called');
|
|
12582
|
-
this.cancelToken = undefined;
|
|
12583
|
-
const connection_id = this.connectionID;
|
|
12584
|
-
this.connectionID = undefined;
|
|
12585
|
-
try {
|
|
12586
|
-
await this._req({ close: true, connection_id }, {
|
|
12587
|
-
timeout,
|
|
12588
|
-
}, false);
|
|
12589
|
-
this._log(`disconnect() - Closed connectionID`);
|
|
12590
|
-
}
|
|
12591
|
-
catch (err) {
|
|
12592
|
-
this._log(`disconnect() - Failed`, { err }, 'error');
|
|
12593
|
-
}
|
|
12594
|
-
};
|
|
12595
|
-
this.client = client;
|
|
12596
|
-
this.state = ConnectionState.Init;
|
|
12597
|
-
this.consecutiveFailures = 0;
|
|
12598
|
-
addConnectionEventListeners(this._onlineStatusChanged);
|
|
12599
|
-
}
|
|
12600
|
-
_log(msg, extra = {}, level = 'info') {
|
|
12601
|
-
this.client.logger(level, 'WSConnectionFallback:' + msg, {
|
|
12602
|
-
...extra,
|
|
12603
|
-
});
|
|
12604
|
-
}
|
|
12605
|
-
_setState(state) {
|
|
12606
|
-
this._log(`_setState() - ${state}`);
|
|
12607
|
-
// transition from connecting => connected
|
|
12608
|
-
if (this.state === ConnectionState.Connecting &&
|
|
12609
|
-
state === ConnectionState.Connected) {
|
|
12610
|
-
this.client.dispatchEvent({ type: 'connection.changed', online: true });
|
|
12611
|
-
}
|
|
12612
|
-
if (state === ConnectionState.Closed ||
|
|
12613
|
-
state === ConnectionState.Disconnected) {
|
|
12614
|
-
this.client.dispatchEvent({ type: 'connection.changed', online: false });
|
|
12615
|
-
}
|
|
12616
|
-
this.state = state;
|
|
12617
|
-
}
|
|
12618
|
-
}
|
|
12619
|
-
|
|
12620
12224
|
const getLocationHint = async (hintUrl = `https://hint.stream-io-video.com/`, timeout = 2000, maxAttempts = 3) => {
|
|
12621
12225
|
const logger = getLogger(['location-hint']);
|
|
12622
12226
|
let attempt = 0;
|
|
@@ -12659,9 +12263,6 @@ class StreamClient {
|
|
|
12659
12263
|
*/
|
|
12660
12264
|
constructor(key, options) {
|
|
12661
12265
|
this.listeners = {};
|
|
12662
|
-
this.devToken = (userID) => {
|
|
12663
|
-
return DevToken(userID);
|
|
12664
|
-
};
|
|
12665
12266
|
this.getAuthType = () => {
|
|
12666
12267
|
return this.anonymous ? 'anonymous' : 'jwt';
|
|
12667
12268
|
};
|
|
@@ -12679,7 +12280,7 @@ class StreamClient {
|
|
|
12679
12280
|
}
|
|
12680
12281
|
return hint;
|
|
12681
12282
|
};
|
|
12682
|
-
this._getConnectionID = () => this.wsConnection?.connectionID
|
|
12283
|
+
this._getConnectionID = () => this.wsConnection?.connectionID;
|
|
12683
12284
|
this._hasConnectionID = () => Boolean(this._getConnectionID());
|
|
12684
12285
|
/**
|
|
12685
12286
|
* connectUser - Set the current user and open a WebSocket connection
|
|
@@ -12755,11 +12356,7 @@ class StreamClient {
|
|
|
12755
12356
|
* https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
|
12756
12357
|
*/
|
|
12757
12358
|
this.closeConnection = async (timeout) => {
|
|
12758
|
-
await
|
|
12759
|
-
this.wsConnection?.disconnect(timeout),
|
|
12760
|
-
this.wsFallback?.disconnect(timeout),
|
|
12761
|
-
]);
|
|
12762
|
-
return Promise.resolve();
|
|
12359
|
+
await this.wsConnection?.disconnect(timeout);
|
|
12763
12360
|
};
|
|
12764
12361
|
/**
|
|
12765
12362
|
* Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection
|
|
@@ -12773,12 +12370,11 @@ class StreamClient {
|
|
|
12773
12370
|
this.logger('info', 'client:openConnection() - connection already in progress');
|
|
12774
12371
|
return await wsPromise;
|
|
12775
12372
|
}
|
|
12776
|
-
if (
|
|
12777
|
-
this._hasConnectionID()) {
|
|
12373
|
+
if (this.wsConnection?.isHealthy && this._hasConnectionID()) {
|
|
12778
12374
|
this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
|
|
12779
12375
|
return;
|
|
12780
12376
|
}
|
|
12781
|
-
this._setupConnectionIdPromise();
|
|
12377
|
+
await this._setupConnectionIdPromise();
|
|
12782
12378
|
this.clientID = `${this.userID}--${randomId()}`;
|
|
12783
12379
|
const newWsPromise = this.connect();
|
|
12784
12380
|
this.wsPromiseSafe = makeSafePromise(newWsPromise);
|
|
@@ -12805,11 +12401,7 @@ class StreamClient {
|
|
|
12805
12401
|
this.resolveConnectionId = undefined;
|
|
12806
12402
|
};
|
|
12807
12403
|
this.connectGuestUser = async (user) => {
|
|
12808
|
-
this.guestUserCreatePromise = this.doAxiosRequest('post', '/guest', {
|
|
12809
|
-
user: {
|
|
12810
|
-
...user,
|
|
12811
|
-
},
|
|
12812
|
-
}, { publicEndpoint: true });
|
|
12404
|
+
this.guestUserCreatePromise = this.doAxiosRequest('post', '/guest', { user }, { publicEndpoint: true });
|
|
12813
12405
|
const response = await this.guestUserCreatePromise;
|
|
12814
12406
|
this.guestUserCreatePromise.finally(() => (this.guestUserCreatePromise = undefined));
|
|
12815
12407
|
return this.connectUser(response.user, response.access_token);
|
|
@@ -12819,7 +12411,7 @@ class StreamClient {
|
|
|
12819
12411
|
*/
|
|
12820
12412
|
this.connectAnonymousUser = async (user, tokenOrProvider) => {
|
|
12821
12413
|
addConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
12822
|
-
this._setupConnectionIdPromise();
|
|
12414
|
+
await this._setupConnectionIdPromise();
|
|
12823
12415
|
this.anonymous = true;
|
|
12824
12416
|
await this._setToken(user, tokenOrProvider, this.anonymous);
|
|
12825
12417
|
this._setUser(user);
|
|
@@ -13013,78 +12605,17 @@ class StreamClient {
|
|
|
13013
12605
|
if (!this.userID || !this._user) {
|
|
13014
12606
|
throw Error('Call connectUser or connectAnonymousUser before starting the connection');
|
|
13015
12607
|
}
|
|
13016
|
-
if (!this.wsBaseURL)
|
|
12608
|
+
if (!this.wsBaseURL)
|
|
13017
12609
|
throw Error('Websocket base url not set');
|
|
13018
|
-
|
|
13019
|
-
if (!this.clientID) {
|
|
12610
|
+
if (!this.clientID)
|
|
13020
12611
|
throw Error('clientID is not set');
|
|
13021
|
-
}
|
|
13022
|
-
if (!this.wsConnection &&
|
|
13023
|
-
(this.options.warmUp || this.options.enableInsights)) {
|
|
13024
|
-
this._sayHi();
|
|
13025
|
-
}
|
|
13026
12612
|
// The StableWSConnection handles all the reconnection logic.
|
|
13027
|
-
|
|
13028
|
-
|
|
13029
|
-
|
|
13030
|
-
this.wsConnection = this.options
|
|
13031
|
-
.wsConnection;
|
|
13032
|
-
}
|
|
13033
|
-
else {
|
|
13034
|
-
this.wsConnection = new StableWSConnection(this);
|
|
13035
|
-
}
|
|
13036
|
-
try {
|
|
13037
|
-
// if fallback is used before, continue using it instead of waiting for WS to fail
|
|
13038
|
-
if (this.wsFallback) {
|
|
13039
|
-
return await this.wsFallback.connect();
|
|
13040
|
-
}
|
|
13041
|
-
this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
|
|
13042
|
-
// if WSFallback is enabled, ws connect should timeout faster so fallback can try
|
|
13043
|
-
return await this.wsConnection.connect(this.options.enableWSFallback
|
|
13044
|
-
? this.defaultWSTimeoutWithFallback
|
|
13045
|
-
: this.defaultWSTimeout);
|
|
13046
|
-
}
|
|
13047
|
-
catch (err) {
|
|
13048
|
-
// run fallback only if it's WS/Network error and not a normal API error
|
|
13049
|
-
// make sure browser is online before even trying the longpoll
|
|
13050
|
-
if (this.options.enableWSFallback &&
|
|
13051
|
-
// @ts-ignore
|
|
13052
|
-
isWSFailure(err) &&
|
|
13053
|
-
isOnline(this.logger)) {
|
|
13054
|
-
this.logger('warn', 'client:connect() - WS failed, fallback to longpoll');
|
|
13055
|
-
this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' });
|
|
13056
|
-
this.wsConnection._destroyCurrentWSConnection();
|
|
13057
|
-
this.wsConnection.disconnect().then(); // close WS so no retry
|
|
13058
|
-
this.wsFallback = new WSConnectionFallback(this);
|
|
13059
|
-
return await this.wsFallback.connect();
|
|
13060
|
-
}
|
|
13061
|
-
throw err;
|
|
13062
|
-
}
|
|
13063
|
-
};
|
|
13064
|
-
/**
|
|
13065
|
-
* Check the connectivity with server for warmup purpose.
|
|
13066
|
-
*
|
|
13067
|
-
* @private
|
|
13068
|
-
*/
|
|
13069
|
-
this._sayHi = () => {
|
|
13070
|
-
const client_request_id = randomId();
|
|
13071
|
-
const opts = {
|
|
13072
|
-
headers: axios.AxiosHeaders.from({
|
|
13073
|
-
'x-client-request-id': client_request_id,
|
|
13074
|
-
}),
|
|
13075
|
-
};
|
|
13076
|
-
this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
|
|
13077
|
-
if (this.options.enableInsights) {
|
|
13078
|
-
postInsights('http_hi_failed', {
|
|
13079
|
-
api_key: this.key,
|
|
13080
|
-
err: e,
|
|
13081
|
-
client_request_id,
|
|
13082
|
-
});
|
|
13083
|
-
}
|
|
13084
|
-
});
|
|
12613
|
+
this.wsConnection = new StableWSConnection(this);
|
|
12614
|
+
this.logger('info', 'StreamClient.connect: this.wsConnection.connect()');
|
|
12615
|
+
return await this.wsConnection.connect(this.defaultWSTimeout);
|
|
13085
12616
|
};
|
|
13086
12617
|
this.getUserAgent = () => {
|
|
13087
|
-
const version = "1.11.
|
|
12618
|
+
const version = "1.11.7";
|
|
13088
12619
|
return (this.userAgent ||
|
|
13089
12620
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
13090
12621
|
};
|
|
@@ -13132,18 +12663,6 @@ class StreamClient {
|
|
|
13132
12663
|
return null;
|
|
13133
12664
|
return this.tokenManager.getToken();
|
|
13134
12665
|
};
|
|
13135
|
-
/**
|
|
13136
|
-
* encode ws url payload
|
|
13137
|
-
* @private
|
|
13138
|
-
* @returns json string
|
|
13139
|
-
*/
|
|
13140
|
-
this._buildWSPayload = (client_request_id) => {
|
|
13141
|
-
return JSON.stringify({
|
|
13142
|
-
user_id: this.userID,
|
|
13143
|
-
user_details: this._user,
|
|
13144
|
-
client_request_id,
|
|
13145
|
-
});
|
|
13146
|
-
};
|
|
13147
12666
|
this.updateNetworkConnectionStatus = (event) => {
|
|
13148
12667
|
if (event.type === 'offline') {
|
|
13149
12668
|
this.logger('debug', 'device went offline');
|
|
@@ -13172,7 +12691,6 @@ class StreamClient {
|
|
|
13172
12691
|
this.options = {
|
|
13173
12692
|
timeout: 5000,
|
|
13174
12693
|
withCredentials: false, // making sure cookies are not sent
|
|
13175
|
-
warmUp: false,
|
|
13176
12694
|
...inputOptions,
|
|
13177
12695
|
};
|
|
13178
12696
|
if (this.node && !this.options.httpsAgent) {
|
|
@@ -13182,16 +12700,6 @@ class StreamClient {
|
|
|
13182
12700
|
});
|
|
13183
12701
|
}
|
|
13184
12702
|
this.setBaseURL(this.options.baseURL || 'https://video.stream-io-api.com/video');
|
|
13185
|
-
if (typeof process !== 'undefined' &&
|
|
13186
|
-
'env' in process &&
|
|
13187
|
-
process.env.STREAM_LOCAL_TEST_RUN) {
|
|
13188
|
-
this.setBaseURL('http://localhost:3030/video');
|
|
13189
|
-
}
|
|
13190
|
-
if (typeof process !== 'undefined' &&
|
|
13191
|
-
'env' in process &&
|
|
13192
|
-
process.env.STREAM_LOCAL_TEST_HOST) {
|
|
13193
|
-
this.setBaseURL(`http://${process.env.STREAM_LOCAL_TEST_HOST}/video`);
|
|
13194
|
-
}
|
|
13195
12703
|
this.axiosInstance = axios.create({
|
|
13196
12704
|
...this.options,
|
|
13197
12705
|
baseURL: this.baseURL,
|
|
@@ -13208,8 +12716,6 @@ class StreamClient {
|
|
|
13208
12716
|
// generated from secret.
|
|
13209
12717
|
this.tokenManager = new TokenManager(this.secret);
|
|
13210
12718
|
this.consecutiveFailures = 0;
|
|
13211
|
-
this.insightMetrics = new InsightMetrics();
|
|
13212
|
-
this.defaultWSTimeoutWithFallback = 6000;
|
|
13213
12719
|
this.defaultWSTimeout = 15000;
|
|
13214
12720
|
this.logger = isFunction(inputOptions.logger)
|
|
13215
12721
|
? inputOptions.logger
|