@stream-io/video-client 1.27.0 → 1.27.2
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 +14 -0
- package/dist/index.browser.es.js +94 -85
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +93 -84
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +94 -85
- package/dist/index.es.js.map +1 -1
- package/dist/src/coordinator/connection/client.d.ts +1 -5
- package/dist/src/devices/devices.d.ts +5 -12
- package/dist/src/devices/index.d.ts +1 -0
- package/dist/src/devices/utils.d.ts +7 -0
- package/dist/src/helpers/lazy.d.ts +1 -1
- package/dist/src/stats/rtc/Tracer.d.ts +4 -1
- package/dist/src/stats/rtc/types.d.ts +1 -0
- package/dist/src/timers/index.d.ts +1 -1
- package/package.json +2 -2
- package/src/Call.ts +13 -4
- package/src/StreamSfuClient.ts +3 -2
- package/src/coordinator/connection/client.ts +27 -46
- package/src/coordinator/connection/connection.ts +0 -1
- package/src/devices/BrowserPermission.ts +1 -1
- package/src/devices/CameraManager.ts +1 -1
- package/src/devices/InputMediaDeviceManager.ts +5 -3
- package/src/devices/MicrophoneManager.ts +2 -1
- package/src/devices/SpeakerManager.ts +1 -1
- package/src/devices/devices.ts +29 -29
- package/src/devices/index.ts +1 -0
- package/src/devices/utils.ts +17 -0
- package/src/helpers/lazy.ts +3 -3
- package/src/rtc/__tests__/videoLayers.test.ts +4 -6
- package/src/rtc/videoLayers.ts +12 -6
- package/src/stats/rtc/Tracer.ts +19 -1
- package/src/stats/rtc/types.ts +1 -0
package/dist/index.cjs.js
CHANGED
|
@@ -5916,7 +5916,7 @@ const aggregate = (stats) => {
|
|
|
5916
5916
|
return report;
|
|
5917
5917
|
};
|
|
5918
5918
|
|
|
5919
|
-
const version = "1.27.
|
|
5919
|
+
const version = "1.27.2";
|
|
5920
5920
|
const [major, minor, patch] = version.split('.');
|
|
5921
5921
|
let sdkInfo = {
|
|
5922
5922
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -6500,6 +6500,15 @@ class Tracer {
|
|
|
6500
6500
|
return;
|
|
6501
6501
|
this.buffer.push([tag, this.id, data, Date.now()]);
|
|
6502
6502
|
};
|
|
6503
|
+
this.traceOnce = (key, tag, data) => {
|
|
6504
|
+
if (this.keys?.has(key))
|
|
6505
|
+
return;
|
|
6506
|
+
this.trace(tag, data);
|
|
6507
|
+
(this.keys ?? (this.keys = new Map())).set(key, true);
|
|
6508
|
+
};
|
|
6509
|
+
this.resetTrace = (key) => {
|
|
6510
|
+
this.keys?.delete(key);
|
|
6511
|
+
};
|
|
6503
6512
|
this.take = () => {
|
|
6504
6513
|
const snapshot = this.buffer;
|
|
6505
6514
|
this.buffer = [];
|
|
@@ -6512,6 +6521,7 @@ class Tracer {
|
|
|
6512
6521
|
};
|
|
6513
6522
|
this.dispose = () => {
|
|
6514
6523
|
this.buffer = [];
|
|
6524
|
+
this.keys?.clear();
|
|
6515
6525
|
};
|
|
6516
6526
|
this.id = id;
|
|
6517
6527
|
}
|
|
@@ -6975,9 +6985,8 @@ const computeVideoLayers = (videoTrack, publishOption) => {
|
|
|
6975
6985
|
if (isAudioTrackType(publishOption.trackType))
|
|
6976
6986
|
return;
|
|
6977
6987
|
const optimalVideoLayers = [];
|
|
6978
|
-
const
|
|
6979
|
-
const { width =
|
|
6980
|
-
const { bitrate, codec, fps, maxSpatialLayers = 3, maxTemporalLayers = 3, videoDimension = { width: 1280, height: 720 }, useSingleLayer, } = publishOption;
|
|
6988
|
+
const { bitrate, codec, fps = 30, maxSpatialLayers = 3, maxTemporalLayers = 3, videoDimension = { width: 1280, height: 720 }, useSingleLayer, } = publishOption;
|
|
6989
|
+
const { width = videoDimension.width, height = videoDimension.height } = videoTrack.getSettings();
|
|
6981
6990
|
const maxBitrate = getComputedMaxBitrate(videoDimension, width, height, bitrate);
|
|
6982
6991
|
let downscaleFactor = 1;
|
|
6983
6992
|
let bitrateFactor = 1;
|
|
@@ -7009,7 +7018,7 @@ const computeVideoLayers = (videoTrack, publishOption) => {
|
|
|
7009
7018
|
}
|
|
7010
7019
|
// for simplicity, we start with all layers enabled, then this function
|
|
7011
7020
|
// will clear/reassign the layers that are not needed
|
|
7012
|
-
return withSimulcastConstraints(
|
|
7021
|
+
return withSimulcastConstraints(width, height, optimalVideoLayers, useSingleLayer);
|
|
7013
7022
|
};
|
|
7014
7023
|
/**
|
|
7015
7024
|
* Computes the maximum bitrate for a given resolution.
|
|
@@ -7043,9 +7052,9 @@ const getComputedMaxBitrate = (targetResolution, currentWidth, currentHeight, bi
|
|
|
7043
7052
|
*
|
|
7044
7053
|
* https://chromium.googlesource.com/external/webrtc/+/refs/heads/main/media/engine/simulcast.cc#90
|
|
7045
7054
|
*/
|
|
7046
|
-
const withSimulcastConstraints = (
|
|
7055
|
+
const withSimulcastConstraints = (width, height, optimalVideoLayers, useSingleLayer) => {
|
|
7047
7056
|
let layers;
|
|
7048
|
-
const size = Math.max(
|
|
7057
|
+
const size = Math.max(width, height);
|
|
7049
7058
|
if (size <= 320) {
|
|
7050
7059
|
// provide only one layer 320x240 (f), the one with the highest quality
|
|
7051
7060
|
layers = optimalVideoLayers.filter((layer) => layer.rid === 'f');
|
|
@@ -7729,9 +7738,9 @@ const uninitialized = Symbol('uninitialized');
|
|
|
7729
7738
|
*/
|
|
7730
7739
|
function lazy(factory) {
|
|
7731
7740
|
let value = uninitialized;
|
|
7732
|
-
return () => {
|
|
7741
|
+
return (...args) => {
|
|
7733
7742
|
if (value === uninitialized) {
|
|
7734
|
-
value = factory();
|
|
7743
|
+
value = factory(...args);
|
|
7735
7744
|
}
|
|
7736
7745
|
return value;
|
|
7737
7746
|
};
|
|
@@ -8062,7 +8071,6 @@ class StreamSfuClient {
|
|
|
8062
8071
|
const current = this.joinResponseTask;
|
|
8063
8072
|
let timeoutId = undefined;
|
|
8064
8073
|
const unsubscribe = this.dispatcher.on('joinResponse', (joinResponse) => {
|
|
8065
|
-
this.logger('debug', 'Received joinResponse', joinResponse);
|
|
8066
8074
|
clearTimeout(timeoutId);
|
|
8067
8075
|
unsubscribe();
|
|
8068
8076
|
this.keepAlive();
|
|
@@ -8070,7 +8078,9 @@ class StreamSfuClient {
|
|
|
8070
8078
|
});
|
|
8071
8079
|
timeoutId = setTimeout(() => {
|
|
8072
8080
|
unsubscribe();
|
|
8073
|
-
|
|
8081
|
+
const message = `Waiting for "joinResponse" has timed out after ${this.joinResponseTimeout}ms`;
|
|
8082
|
+
this.tracer?.trace('joinRequestTimeout', message);
|
|
8083
|
+
current.reject(new Error(message));
|
|
8074
8084
|
}, this.joinResponseTimeout);
|
|
8075
8085
|
const joinRequest = SfuRequest.create({
|
|
8076
8086
|
requestPayload: {
|
|
@@ -9414,6 +9424,25 @@ const CallTypes = new CallTypesRegistry([
|
|
|
9414
9424
|
}),
|
|
9415
9425
|
]);
|
|
9416
9426
|
|
|
9427
|
+
/**
|
|
9428
|
+
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
9429
|
+
*
|
|
9430
|
+
* @param stream MediaStream
|
|
9431
|
+
* @returns void
|
|
9432
|
+
*/
|
|
9433
|
+
const disposeOfMediaStream = (stream) => {
|
|
9434
|
+
if (!stream.active)
|
|
9435
|
+
return;
|
|
9436
|
+
stream.getTracks().forEach((track) => {
|
|
9437
|
+
track.stop();
|
|
9438
|
+
});
|
|
9439
|
+
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
9440
|
+
if (typeof stream.release === 'function') {
|
|
9441
|
+
// @ts-expect-error - release() is present in react-native-webrtc
|
|
9442
|
+
stream.release();
|
|
9443
|
+
}
|
|
9444
|
+
};
|
|
9445
|
+
|
|
9417
9446
|
class BrowserPermission {
|
|
9418
9447
|
constructor(permission) {
|
|
9419
9448
|
this.permission = permission;
|
|
@@ -9545,8 +9574,9 @@ function canQueryPermissions() {
|
|
|
9545
9574
|
*
|
|
9546
9575
|
* @param permission a BrowserPermission instance.
|
|
9547
9576
|
* @param kind the kind of devices to enumerate.
|
|
9577
|
+
* @param tracer the tracer to use for tracing the device enumeration.
|
|
9548
9578
|
*/
|
|
9549
|
-
const getDevices = (permission, kind) => {
|
|
9579
|
+
const getDevices = (permission, kind, tracer) => {
|
|
9550
9580
|
return rxjs.from((async () => {
|
|
9551
9581
|
let devices = await navigator.mediaDevices.enumerateDevices();
|
|
9552
9582
|
// for privacy reasons, most browsers don't give you device labels
|
|
@@ -9555,6 +9585,7 @@ const getDevices = (permission, kind) => {
|
|
|
9555
9585
|
if (shouldPromptForBrowserPermission && (await permission.prompt())) {
|
|
9556
9586
|
devices = await navigator.mediaDevices.enumerateDevices();
|
|
9557
9587
|
}
|
|
9588
|
+
tracer?.traceOnce('device-enumeration', 'navigator.mediaDevices.enumerateDevices', devices);
|
|
9558
9589
|
return devices.filter((device) => device.kind === kind &&
|
|
9559
9590
|
device.label !== '' &&
|
|
9560
9591
|
device.deviceId !== 'default');
|
|
@@ -9605,12 +9636,12 @@ const getVideoBrowserPermission = lazy(() => new BrowserPermission({
|
|
|
9605
9636
|
constraints: videoDeviceConstraints,
|
|
9606
9637
|
queryName: 'camera',
|
|
9607
9638
|
}));
|
|
9608
|
-
const getDeviceChangeObserver = lazy(() => {
|
|
9639
|
+
const getDeviceChangeObserver = lazy((tracer) => {
|
|
9609
9640
|
// 'addEventListener' is not available in React Native, returning
|
|
9610
9641
|
// an observable that will never fire
|
|
9611
9642
|
if (!navigator.mediaDevices.addEventListener)
|
|
9612
9643
|
return rxjs.from([]);
|
|
9613
|
-
return rxjs.fromEvent(navigator.mediaDevices, 'devicechange').pipe(rxjs.map(() => undefined), rxjs.debounceTime(500));
|
|
9644
|
+
return rxjs.fromEvent(navigator.mediaDevices, 'devicechange').pipe(rxjs.tap(() => tracer?.resetTrace('device-enumeration')), rxjs.map(() => undefined), rxjs.debounceTime(500));
|
|
9614
9645
|
});
|
|
9615
9646
|
/**
|
|
9616
9647
|
* Prompts the user for a permission to use audio devices (if not already granted
|
|
@@ -9618,8 +9649,8 @@ const getDeviceChangeObserver = lazy(() => {
|
|
|
9618
9649
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
9619
9650
|
* the observable errors.
|
|
9620
9651
|
*/
|
|
9621
|
-
const getAudioDevices = lazy(() => {
|
|
9622
|
-
return rxjs.merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audioinput')), rxjs.shareReplay(1));
|
|
9652
|
+
const getAudioDevices = lazy((tracer) => {
|
|
9653
|
+
return rxjs.merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audioinput', tracer)), rxjs.shareReplay(1));
|
|
9623
9654
|
});
|
|
9624
9655
|
/**
|
|
9625
9656
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
@@ -9627,8 +9658,8 @@ const getAudioDevices = lazy(() => {
|
|
|
9627
9658
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
9628
9659
|
* the observable errors.
|
|
9629
9660
|
*/
|
|
9630
|
-
const getVideoDevices = lazy(() => {
|
|
9631
|
-
return rxjs.merge(getDeviceChangeObserver(), getVideoBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput')), rxjs.shareReplay(1));
|
|
9661
|
+
const getVideoDevices = lazy((tracer) => {
|
|
9662
|
+
return rxjs.merge(getDeviceChangeObserver(tracer), getVideoBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getVideoBrowserPermission(), 'videoinput', tracer)), rxjs.shareReplay(1));
|
|
9632
9663
|
});
|
|
9633
9664
|
/**
|
|
9634
9665
|
* Prompts the user for a permission to use video devices (if not already granted
|
|
@@ -9636,8 +9667,8 @@ const getVideoDevices = lazy(() => {
|
|
|
9636
9667
|
* if devices are added/removed the list is updated, and if the permission is revoked,
|
|
9637
9668
|
* the observable errors.
|
|
9638
9669
|
*/
|
|
9639
|
-
const getAudioOutputDevices = lazy(() => {
|
|
9640
|
-
return rxjs.merge(getDeviceChangeObserver(), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput')), rxjs.shareReplay(1));
|
|
9670
|
+
const getAudioOutputDevices = lazy((tracer) => {
|
|
9671
|
+
return rxjs.merge(getDeviceChangeObserver(tracer), getAudioBrowserPermission().asObservable()).pipe(rxjs.startWith(undefined), rxjs.concatMap(() => getDevices(getAudioBrowserPermission(), 'audiooutput', tracer)), rxjs.shareReplay(1));
|
|
9641
9672
|
});
|
|
9642
9673
|
let getUserMediaExecId = 0;
|
|
9643
9674
|
const getStream = async (constraints, tracer) => {
|
|
@@ -9809,24 +9840,6 @@ const deviceIds$ = typeof navigator !== 'undefined' &&
|
|
|
9809
9840
|
typeof navigator.mediaDevices !== 'undefined'
|
|
9810
9841
|
? getDeviceChangeObserver().pipe(rxjs.startWith(undefined), rxjs.concatMap(() => navigator.mediaDevices.enumerateDevices()), rxjs.shareReplay(1))
|
|
9811
9842
|
: undefined;
|
|
9812
|
-
/**
|
|
9813
|
-
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
9814
|
-
*
|
|
9815
|
-
* @param stream MediaStream
|
|
9816
|
-
* @returns void
|
|
9817
|
-
*/
|
|
9818
|
-
const disposeOfMediaStream = (stream) => {
|
|
9819
|
-
if (!stream.active)
|
|
9820
|
-
return;
|
|
9821
|
-
stream.getTracks().forEach((track) => {
|
|
9822
|
-
track.stop();
|
|
9823
|
-
});
|
|
9824
|
-
// @ts-expect-error release() is present in react-native-webrtc and must be called to dispose the stream
|
|
9825
|
-
if (typeof stream.release === 'function') {
|
|
9826
|
-
// @ts-expect-error - release() is present in react-native-webrtc
|
|
9827
|
-
stream.release();
|
|
9828
|
-
}
|
|
9829
|
-
};
|
|
9830
9843
|
/**
|
|
9831
9844
|
* Resolves `default` device id into the real device id. Some browsers (notably,
|
|
9832
9845
|
* Chromium-based) report device with id `default` among audio input and output
|
|
@@ -10009,6 +10022,7 @@ class InputMediaDeviceManager {
|
|
|
10009
10022
|
entry.stop?.();
|
|
10010
10023
|
this.filters = this.filters.filter((f) => f !== entry);
|
|
10011
10024
|
await this.applySettingsToStream();
|
|
10025
|
+
this.call.tracer.trace(`unregisterFilter.${TrackType[this.trackType]}`, null);
|
|
10012
10026
|
}),
|
|
10013
10027
|
};
|
|
10014
10028
|
}
|
|
@@ -10028,7 +10042,7 @@ class InputMediaDeviceManager {
|
|
|
10028
10042
|
*/
|
|
10029
10043
|
async select(deviceId) {
|
|
10030
10044
|
if (isReactNative()) {
|
|
10031
|
-
throw new Error('This method is not supported in React Native.
|
|
10045
|
+
throw new Error('This method is not supported in React Native.');
|
|
10032
10046
|
}
|
|
10033
10047
|
const prevDeviceId = this.state.selectedDevice;
|
|
10034
10048
|
if (deviceId === prevDeviceId) {
|
|
@@ -10595,7 +10609,7 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
10595
10609
|
}
|
|
10596
10610
|
}
|
|
10597
10611
|
getDevices() {
|
|
10598
|
-
return getVideoDevices();
|
|
10612
|
+
return getVideoDevices(this.call.tracer);
|
|
10599
10613
|
}
|
|
10600
10614
|
getStream(constraints) {
|
|
10601
10615
|
constraints.width = this.targetResolution.width;
|
|
@@ -11002,6 +11016,7 @@ class MicrophoneManager extends InputMediaDeviceManager {
|
|
|
11002
11016
|
.catch((err) => {
|
|
11003
11017
|
this.logger('warn', 'Failed to unregister noise cancellation', err);
|
|
11004
11018
|
});
|
|
11019
|
+
this.call.tracer.trace('noiseCancellation.disabled', true);
|
|
11005
11020
|
await this.call.notifyNoiseCancellationStopped();
|
|
11006
11021
|
}
|
|
11007
11022
|
/**
|
|
@@ -11046,7 +11061,7 @@ class MicrophoneManager extends InputMediaDeviceManager {
|
|
|
11046
11061
|
}
|
|
11047
11062
|
}
|
|
11048
11063
|
getDevices() {
|
|
11049
|
-
return getAudioDevices();
|
|
11064
|
+
return getAudioDevices(this.call.tracer);
|
|
11050
11065
|
}
|
|
11051
11066
|
getStream(constraints) {
|
|
11052
11067
|
return getAudioStream(constraints, this.call.tracer);
|
|
@@ -11311,7 +11326,7 @@ class SpeakerManager {
|
|
|
11311
11326
|
if (isReactNative()) {
|
|
11312
11327
|
throw new Error('This feature is not supported in React Native. Please visit https://getstream.io/video/docs/reactnative/core/camera-and-microphone/#speaker-management for more details');
|
|
11313
11328
|
}
|
|
11314
|
-
return getAudioOutputDevices();
|
|
11329
|
+
return getAudioOutputDevices(this.call.tracer);
|
|
11315
11330
|
}
|
|
11316
11331
|
/**
|
|
11317
11332
|
* Select a device.
|
|
@@ -11838,6 +11853,12 @@ class Call {
|
|
|
11838
11853
|
}
|
|
11839
11854
|
catch (err) {
|
|
11840
11855
|
this.logger('warn', `Failed to join call (${attempt})`, this.cid);
|
|
11856
|
+
if (err instanceof ErrorFromResponse && err.unrecoverable) {
|
|
11857
|
+
// if the error is unrecoverable, we should not retry as that signals
|
|
11858
|
+
// that connectivity is good, but the coordinator doesn't allow the user
|
|
11859
|
+
// to join the call due to some reason (e.g., ended call, expired token...)
|
|
11860
|
+
throw err;
|
|
11861
|
+
}
|
|
11841
11862
|
const sfuId = this.credentials?.server.edge_name || '';
|
|
11842
11863
|
const failures = (sfuJoinFailures.get(sfuId) || 0) + 1;
|
|
11843
11864
|
sfuJoinFailures.set(sfuId, failures);
|
|
@@ -12649,9 +12670,12 @@ class Call {
|
|
|
12649
12670
|
* @internal
|
|
12650
12671
|
*/
|
|
12651
12672
|
this.notifyTrackMuteState = async (muted, ...trackTypes) => {
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12673
|
+
const key = `muteState.${this.cid}.${trackTypes.join('-')}`;
|
|
12674
|
+
await withoutConcurrency(key, async () => {
|
|
12675
|
+
if (!this.sfuClient)
|
|
12676
|
+
return;
|
|
12677
|
+
await this.sfuClient.updateMuteStates(trackTypes.map((trackType) => ({ trackType, muted })));
|
|
12678
|
+
});
|
|
12655
12679
|
};
|
|
12656
12680
|
/**
|
|
12657
12681
|
* Will enhance the reported stats with additional participant-specific information (`callStatsReport$` state [store variable](./StreamVideoClient.md/#readonlystatestore)).
|
|
@@ -13561,7 +13585,6 @@ class StableWSConnection {
|
|
|
13561
13585
|
this.totalFailures += 1;
|
|
13562
13586
|
this._setHealth(false);
|
|
13563
13587
|
this.isConnecting = false;
|
|
13564
|
-
this.rejectConnectionOpen?.(new Error(`WebSocket error: ${event}`));
|
|
13565
13588
|
this._log(`onerror() - WS connection resulted into error`, { event });
|
|
13566
13589
|
this._reconnect();
|
|
13567
13590
|
};
|
|
@@ -14345,12 +14368,6 @@ class StreamClient {
|
|
|
14345
14368
|
response,
|
|
14346
14369
|
});
|
|
14347
14370
|
};
|
|
14348
|
-
this._logApiError = (type, url, error) => {
|
|
14349
|
-
this.logger('error', `client:${type} - Error - url: ${url}`, {
|
|
14350
|
-
url,
|
|
14351
|
-
error,
|
|
14352
|
-
});
|
|
14353
|
-
};
|
|
14354
14371
|
this.doAxiosRequest = async (type, url, data, options = {}) => {
|
|
14355
14372
|
if (!options.publicEndpoint) {
|
|
14356
14373
|
await Promise.all([
|
|
@@ -14397,27 +14414,36 @@ class StreamClient {
|
|
|
14397
14414
|
}
|
|
14398
14415
|
this._logApiResponse(type, url, response);
|
|
14399
14416
|
this.consecutiveFailures = 0;
|
|
14400
|
-
return
|
|
14417
|
+
return response.data;
|
|
14401
14418
|
}
|
|
14402
14419
|
catch (e /**TODO: generalize error types */) {
|
|
14403
14420
|
e.client_request_id = requestConfig.headers?.['x-client-request-id'];
|
|
14404
14421
|
this.consecutiveFailures += 1;
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14422
|
+
const { response } = e;
|
|
14423
|
+
if (!response || !isErrorResponse(response)) {
|
|
14424
|
+
this.logger('error', `client:${type} url: ${url}`, e);
|
|
14425
|
+
throw e;
|
|
14426
|
+
}
|
|
14427
|
+
const { data: responseData, status } = response;
|
|
14428
|
+
const isTokenExpired = responseData.code === KnownCodes.TOKEN_EXPIRED;
|
|
14429
|
+
if (isTokenExpired && !this.tokenManager.isStatic()) {
|
|
14430
|
+
this.logger('warn', `client:${type}: url: ${url}`, response);
|
|
14431
|
+
if (this.consecutiveFailures > 1) {
|
|
14432
|
+
await sleep(retryInterval(this.consecutiveFailures));
|
|
14415
14433
|
}
|
|
14416
|
-
|
|
14434
|
+
// refresh and retry the request
|
|
14435
|
+
await this.tokenManager.loadToken();
|
|
14436
|
+
return await this.doAxiosRequest(type, url, data, options);
|
|
14417
14437
|
}
|
|
14418
14438
|
else {
|
|
14419
|
-
this.
|
|
14420
|
-
throw
|
|
14439
|
+
this.logger('error', `client:${type} url: ${url}`, response);
|
|
14440
|
+
throw new ErrorFromResponse({
|
|
14441
|
+
message: `Stream error code ${responseData.code}: ${responseData.message}`,
|
|
14442
|
+
code: responseData.code ?? null,
|
|
14443
|
+
unrecoverable: responseData.unrecoverable ?? null,
|
|
14444
|
+
response: response,
|
|
14445
|
+
status: status,
|
|
14446
|
+
});
|
|
14421
14447
|
}
|
|
14422
14448
|
}
|
|
14423
14449
|
};
|
|
@@ -14440,23 +14466,6 @@ class StreamClient {
|
|
|
14440
14466
|
params,
|
|
14441
14467
|
});
|
|
14442
14468
|
};
|
|
14443
|
-
this.errorFromResponse = (response) => {
|
|
14444
|
-
const { data, status } = response;
|
|
14445
|
-
return new ErrorFromResponse({
|
|
14446
|
-
message: `Stream error code ${data.code}: ${data.message}`,
|
|
14447
|
-
code: data.code ?? null,
|
|
14448
|
-
unrecoverable: data.unrecoverable ?? null,
|
|
14449
|
-
response: response,
|
|
14450
|
-
status: status,
|
|
14451
|
-
});
|
|
14452
|
-
};
|
|
14453
|
-
this.handleResponse = (response) => {
|
|
14454
|
-
const data = response.data;
|
|
14455
|
-
if (isErrorResponse(response)) {
|
|
14456
|
-
throw this.errorFromResponse(response);
|
|
14457
|
-
}
|
|
14458
|
-
return data;
|
|
14459
|
-
};
|
|
14460
14469
|
this.dispatchEvent = (event) => {
|
|
14461
14470
|
this.logger('debug', `Dispatching event: ${event.type}`, event);
|
|
14462
14471
|
if (!this.listeners)
|
|
@@ -14489,7 +14498,7 @@ class StreamClient {
|
|
|
14489
14498
|
this.getUserAgent = () => {
|
|
14490
14499
|
if (!this.cachedUserAgent) {
|
|
14491
14500
|
const { clientAppIdentifier = {} } = this.options;
|
|
14492
|
-
const { sdkName = 'js', sdkVersion = "1.27.
|
|
14501
|
+
const { sdkName = 'js', sdkVersion = "1.27.2", ...extras } = clientAppIdentifier;
|
|
14493
14502
|
this.cachedUserAgent = [
|
|
14494
14503
|
`stream-video-${sdkName}-v${sdkVersion}`,
|
|
14495
14504
|
...Object.entries(extras).map(([key, value]) => `${key}=${value}`),
|