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