@stream-io/video-client 1.11.4 → 1.11.6
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 +70 -51
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +70 -51
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +70 -51
- package/dist/index.es.js.map +1 -1
- package/dist/src/StreamVideoClient.d.ts +2 -3
- package/dist/src/coordinator/connection/client.d.ts +11 -8
- package/dist/src/coordinator/connection/connection.d.ts +5 -4
- package/dist/src/helpers/promise.d.ts +18 -0
- package/dist/src/rtc/codecs.d.ts +2 -1
- package/package.json +1 -1
- package/src/StreamVideoClient.ts +14 -19
- package/src/__tests__/Call.test.ts +2 -2
- package/src/coordinator/connection/client.ts +33 -14
- package/src/coordinator/connection/connection.ts +14 -19
- package/src/helpers/promise.ts +47 -0
- package/src/rtc/Publisher.ts +8 -3
- package/src/rtc/codecs.ts +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [1.11.6](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.5...@stream-io/video-client-1.11.6) (2024-11-22)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* force single codec preference in the SDP ([#1588](https://github.com/GetStream/stream-video-js/issues/1588)) ([4afff09](https://github.com/GetStream/stream-video-js/commit/4afff09a778f8567176d22bcc22d36001dca7cd3)), closes [#1581](https://github.com/GetStream/stream-video-js/issues/1581)
|
|
11
|
+
|
|
12
|
+
## [1.11.5](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.4...@stream-io/video-client-1.11.5) (2024-11-22)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* unhandled promise rejections during reconnect ([#1585](https://github.com/GetStream/stream-video-js/issues/1585)) ([920c4ea](https://github.com/GetStream/stream-video-js/commit/920c4ea3b3f622430b35ac1bade74a6206ee17e5)), closes [/github.com/GetStream/stream-video-js/pull/1585/files#diff-420f6ddab47c1be72fd9ce8c99e1fa2b9f5f0495b7c367546ee0ff634beaed81](https://github.com/GetStream//github.com/GetStream/stream-video-js/pull/1585/files/issues/diff-420f6ddab47c1be72fd9ce8c99e1fa2b9f5f0495b7c367546ee0ff634beaed81)
|
|
18
|
+
|
|
5
19
|
## [1.11.4](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.3...@stream-io/video-client-1.11.4) (2024-11-21)
|
|
6
20
|
|
|
7
21
|
|
package/dist/index.browser.es.js
CHANGED
|
@@ -3190,13 +3190,6 @@ function convertErrorToJson(err) {
|
|
|
3190
3190
|
}
|
|
3191
3191
|
return jsonObj;
|
|
3192
3192
|
}
|
|
3193
|
-
/**
|
|
3194
|
-
* Informs if a promise is yet to be resolved or rejected
|
|
3195
|
-
*/
|
|
3196
|
-
async function isPromisePending(promise) {
|
|
3197
|
-
const emptyObj = {};
|
|
3198
|
-
return Promise.race([promise, emptyObj]).then((value) => (value === emptyObj ? true : false), () => false);
|
|
3199
|
-
}
|
|
3200
3193
|
/**
|
|
3201
3194
|
* isOnline safely return the navigator.online value for browser env
|
|
3202
3195
|
* if navigator is not in global object, it always return true
|
|
@@ -3335,7 +3328,7 @@ const retryable = async (rpc, signal) => {
|
|
|
3335
3328
|
return result;
|
|
3336
3329
|
};
|
|
3337
3330
|
|
|
3338
|
-
const version = "1.11.
|
|
3331
|
+
const version = "1.11.6";
|
|
3339
3332
|
const [major, minor, patch] = version.split('.');
|
|
3340
3333
|
let sdkInfo = {
|
|
3341
3334
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -3439,11 +3432,13 @@ var browsers = /*#__PURE__*/Object.freeze({
|
|
|
3439
3432
|
* @param kind the kind of codec to get.
|
|
3440
3433
|
* @param preferredCodec the codec to prioritize (vp8, h264, vp9, av1...).
|
|
3441
3434
|
* @param codecToRemove the codec to exclude from the list.
|
|
3435
|
+
* @param codecPreferencesSource the source of the codec preferences.
|
|
3442
3436
|
*/
|
|
3443
|
-
const getPreferredCodecs = (kind, preferredCodec, codecToRemove) => {
|
|
3444
|
-
|
|
3437
|
+
const getPreferredCodecs = (kind, preferredCodec, codecToRemove, codecPreferencesSource = 'receiver') => {
|
|
3438
|
+
const source = codecPreferencesSource === 'receiver' ? RTCRtpReceiver : RTCRtpSender;
|
|
3439
|
+
if (!('getCapabilities' in source))
|
|
3445
3440
|
return;
|
|
3446
|
-
const capabilities =
|
|
3441
|
+
const capabilities = source.getCapabilities(kind);
|
|
3447
3442
|
if (!capabilities)
|
|
3448
3443
|
return;
|
|
3449
3444
|
const preferred = [];
|
|
@@ -5881,9 +5876,9 @@ class Publisher {
|
|
|
5881
5876
|
this.getStats = (selector) => {
|
|
5882
5877
|
return this.pc.getStats(selector);
|
|
5883
5878
|
};
|
|
5884
|
-
this.getCodecPreferences = (trackType, preferredCodec) => {
|
|
5879
|
+
this.getCodecPreferences = (trackType, preferredCodec, codecPreferencesSource) => {
|
|
5885
5880
|
if (trackType === TrackType.VIDEO) {
|
|
5886
|
-
return getPreferredCodecs('video', preferredCodec || 'vp8');
|
|
5881
|
+
return getPreferredCodecs('video', preferredCodec || 'vp8', codecPreferencesSource);
|
|
5887
5882
|
}
|
|
5888
5883
|
if (trackType === TrackType.AUDIO) {
|
|
5889
5884
|
const defaultAudioCodec = this.isRedEnabled ? 'red' : 'opus';
|
|
@@ -6115,8 +6110,8 @@ class Publisher {
|
|
|
6115
6110
|
const opts = this.publishOptsForTrack.get(trackType);
|
|
6116
6111
|
if (!opts || !opts.forceSingleCodec)
|
|
6117
6112
|
return sdp;
|
|
6118
|
-
const codec = opts.forceCodec || opts.preferredCodec;
|
|
6119
|
-
const orderedCodecs = this.getCodecPreferences(trackType, codec);
|
|
6113
|
+
const codec = opts.forceCodec || getOptimalVideoCodec(opts.preferredCodec);
|
|
6114
|
+
const orderedCodecs = this.getCodecPreferences(trackType, codec, 'sender');
|
|
6120
6115
|
if (!orderedCodecs || orderedCodecs.length === 0)
|
|
6121
6116
|
return sdp;
|
|
6122
6117
|
const transceiver = this.transceiverCache.get(trackType);
|
|
@@ -11569,6 +11564,33 @@ function buildWsSuccessAfterFailureInsight(connection) {
|
|
|
11569
11564
|
return buildWsBaseInsight(connection);
|
|
11570
11565
|
}
|
|
11571
11566
|
|
|
11567
|
+
/**
|
|
11568
|
+
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
11569
|
+
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
11570
|
+
* rejection is handled everywhere promise result is expected).
|
|
11571
|
+
*
|
|
11572
|
+
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
11573
|
+
* That way, the saved promise never rejects. A callback is provided as return
|
|
11574
|
+
* value to build a *new* promise, that resolves and rejects along with
|
|
11575
|
+
* the original promise.
|
|
11576
|
+
* @param promise Promise to wrap, which possibly rejects
|
|
11577
|
+
* @returns Callback to build a new promise, which resolves and rejects along
|
|
11578
|
+
* with the original promise
|
|
11579
|
+
*/
|
|
11580
|
+
function makeSafePromise(promise) {
|
|
11581
|
+
let isPending = true;
|
|
11582
|
+
const safePromise = promise
|
|
11583
|
+
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
11584
|
+
.finally(() => (isPending = false));
|
|
11585
|
+
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
11586
|
+
if (fulfillment.status === 'rejected')
|
|
11587
|
+
throw fulfillment.error;
|
|
11588
|
+
return fulfillment.result;
|
|
11589
|
+
});
|
|
11590
|
+
unwrapPromise.checkPending = () => isPending;
|
|
11591
|
+
return unwrapPromise;
|
|
11592
|
+
}
|
|
11593
|
+
|
|
11572
11594
|
// Type guards to check WebSocket error type
|
|
11573
11595
|
const isCloseEvent = (res) => res.code !== undefined;
|
|
11574
11596
|
const isErrorEvent = (res) => res.error !== undefined;
|
|
@@ -11817,10 +11839,10 @@ class StableWSConnection {
|
|
|
11817
11839
|
this._setupConnectionPromise = () => {
|
|
11818
11840
|
this.isResolved = false;
|
|
11819
11841
|
/** a promise that is resolved once ws.open is called */
|
|
11820
|
-
this.
|
|
11842
|
+
this.connectionOpenSafe = makeSafePromise(new Promise((resolve, reject) => {
|
|
11821
11843
|
this.resolvePromise = resolve;
|
|
11822
11844
|
this.rejectPromise = reject;
|
|
11823
|
-
});
|
|
11845
|
+
}));
|
|
11824
11846
|
};
|
|
11825
11847
|
/**
|
|
11826
11848
|
* Schedules a next health check ping for websocket.
|
|
@@ -12041,13 +12063,7 @@ class StableWSConnection {
|
|
|
12041
12063
|
this._log(`_connect() - tokenProvider failed before, so going to retry`);
|
|
12042
12064
|
await this.client.tokenManager.loadToken();
|
|
12043
12065
|
}
|
|
12044
|
-
|
|
12045
|
-
if (this.client.connectionIdPromise) {
|
|
12046
|
-
if (await isPromisePending(this.client.connectionIdPromise)) {
|
|
12047
|
-
mustSetupConnectionIdPromise = false;
|
|
12048
|
-
}
|
|
12049
|
-
}
|
|
12050
|
-
if (mustSetupConnectionIdPromise) {
|
|
12066
|
+
if (!this.client.isConnectionIsPromisePending) {
|
|
12051
12067
|
this.client._setupConnectionIdPromise();
|
|
12052
12068
|
}
|
|
12053
12069
|
this._setupConnectionPromise();
|
|
@@ -12167,6 +12183,9 @@ class StableWSConnection {
|
|
|
12167
12183
|
// we don't care
|
|
12168
12184
|
}
|
|
12169
12185
|
}
|
|
12186
|
+
get connectionOpen() {
|
|
12187
|
+
return this.connectionOpenSafe?.();
|
|
12188
|
+
}
|
|
12170
12189
|
}
|
|
12171
12190
|
|
|
12172
12191
|
function isString(arrayOrString) {
|
|
@@ -12730,19 +12749,21 @@ class StreamClient {
|
|
|
12730
12749
|
if (!this.userID) {
|
|
12731
12750
|
throw Error('UserWithId is not set on client, use client.connectUser or client.connectAnonymousUser instead');
|
|
12732
12751
|
}
|
|
12733
|
-
|
|
12752
|
+
const wsPromise = this.wsPromiseSafe?.();
|
|
12753
|
+
if (this.wsConnection?.isConnecting && wsPromise) {
|
|
12734
12754
|
this.logger('info', 'client:openConnection() - connection already in progress');
|
|
12735
|
-
return
|
|
12755
|
+
return await wsPromise;
|
|
12736
12756
|
}
|
|
12737
12757
|
if ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) &&
|
|
12738
12758
|
this._hasConnectionID()) {
|
|
12739
12759
|
this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
|
|
12740
|
-
return
|
|
12760
|
+
return;
|
|
12741
12761
|
}
|
|
12742
12762
|
this._setupConnectionIdPromise();
|
|
12743
12763
|
this.clientID = `${this.userID}--${randomId()}`;
|
|
12744
|
-
|
|
12745
|
-
|
|
12764
|
+
const newWsPromise = this.connect();
|
|
12765
|
+
this.wsPromiseSafe = makeSafePromise(newWsPromise);
|
|
12766
|
+
return await newWsPromise;
|
|
12746
12767
|
};
|
|
12747
12768
|
/**
|
|
12748
12769
|
* Disconnects the websocket and removes the user from client.
|
|
@@ -12760,7 +12781,7 @@ class StreamClient {
|
|
|
12760
12781
|
await this.closeConnection(timeout);
|
|
12761
12782
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
12762
12783
|
this.tokenManager.reset();
|
|
12763
|
-
this.
|
|
12784
|
+
this.connectionIdPromiseSafe = undefined;
|
|
12764
12785
|
this.rejectConnectionId = undefined;
|
|
12765
12786
|
this.resolveConnectionId = undefined;
|
|
12766
12787
|
};
|
|
@@ -12821,12 +12842,12 @@ class StreamClient {
|
|
|
12821
12842
|
/**
|
|
12822
12843
|
* sets up the this.connectionIdPromise
|
|
12823
12844
|
*/
|
|
12824
|
-
this._setupConnectionIdPromise =
|
|
12845
|
+
this._setupConnectionIdPromise = () => {
|
|
12825
12846
|
/** a promise that is resolved once connection id is set */
|
|
12826
|
-
this.
|
|
12847
|
+
this.connectionIdPromiseSafe = makeSafePromise(new Promise((resolve, reject) => {
|
|
12827
12848
|
this.resolveConnectionId = resolve;
|
|
12828
12849
|
this.rejectConnectionId = reject;
|
|
12829
|
-
});
|
|
12850
|
+
}));
|
|
12830
12851
|
};
|
|
12831
12852
|
this._logApiRequest = (type, url, data, config) => {
|
|
12832
12853
|
this.logger('trace', `client: ${type} - Request - ${url}`, {
|
|
@@ -13044,7 +13065,7 @@ class StreamClient {
|
|
|
13044
13065
|
});
|
|
13045
13066
|
};
|
|
13046
13067
|
this.getUserAgent = () => {
|
|
13047
|
-
const version = "1.11.
|
|
13068
|
+
const version = "1.11.6";
|
|
13048
13069
|
return (this.userAgent ||
|
|
13049
13070
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
13050
13071
|
};
|
|
@@ -13158,7 +13179,7 @@ class StreamClient {
|
|
|
13158
13179
|
});
|
|
13159
13180
|
// WS connection is initialized when setUser is called
|
|
13160
13181
|
this.wsConnection = null;
|
|
13161
|
-
this.
|
|
13182
|
+
this.wsPromiseSafe = null;
|
|
13162
13183
|
this.setUserPromise = null;
|
|
13163
13184
|
// mapping between channel groups and configs
|
|
13164
13185
|
this.anonymous = false;
|
|
@@ -13175,6 +13196,15 @@ class StreamClient {
|
|
|
13175
13196
|
? inputOptions.logger
|
|
13176
13197
|
: () => null;
|
|
13177
13198
|
}
|
|
13199
|
+
get connectionIdPromise() {
|
|
13200
|
+
return this.connectionIdPromiseSafe?.();
|
|
13201
|
+
}
|
|
13202
|
+
get isConnectionIsPromisePending() {
|
|
13203
|
+
return this.connectionIdPromiseSafe?.checkPending() ?? false;
|
|
13204
|
+
}
|
|
13205
|
+
get wsPromise() {
|
|
13206
|
+
return this.wsPromiseSafe?.();
|
|
13207
|
+
}
|
|
13178
13208
|
}
|
|
13179
13209
|
|
|
13180
13210
|
/**
|
|
@@ -13184,6 +13214,7 @@ class StreamVideoClient {
|
|
|
13184
13214
|
constructor(apiKeyOrArgs, opts) {
|
|
13185
13215
|
this.logLevel = 'warn';
|
|
13186
13216
|
this.eventHandlersToUnregister = [];
|
|
13217
|
+
this.connectionConcurrencyTag = Symbol('connectionConcurrencyTag');
|
|
13187
13218
|
/**
|
|
13188
13219
|
* Connects the given user to the client.
|
|
13189
13220
|
* Only one user can connect at a time, if you want to change users, call `disconnectUser` before connecting a new user.
|
|
@@ -13205,11 +13236,7 @@ class StreamVideoClient {
|
|
|
13205
13236
|
return this.streamClient.connectGuestUser(user);
|
|
13206
13237
|
};
|
|
13207
13238
|
}
|
|
13208
|
-
|
|
13209
|
-
? this.disconnectionPromise.then(() => connectUser())
|
|
13210
|
-
: connectUser();
|
|
13211
|
-
this.connectionPromise?.finally(() => (this.connectionPromise = undefined));
|
|
13212
|
-
const connectUserResponse = await this.connectionPromise;
|
|
13239
|
+
const connectUserResponse = await withoutConcurrency(this.connectionConcurrencyTag, () => connectUser());
|
|
13213
13240
|
// connectUserResponse will be void if connectUser called twice for the same user
|
|
13214
13241
|
if (connectUserResponse?.me) {
|
|
13215
13242
|
this.writeableStateStore.setConnectedUser(connectUserResponse.me);
|
|
@@ -13286,17 +13313,13 @@ class StreamVideoClient {
|
|
|
13286
13313
|
* https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
|
13287
13314
|
*/
|
|
13288
13315
|
this.disconnectUser = async (timeout) => {
|
|
13289
|
-
if (!this.streamClient.user
|
|
13316
|
+
if (!this.streamClient.user) {
|
|
13290
13317
|
return;
|
|
13291
13318
|
}
|
|
13292
13319
|
const userId = this.streamClient.user?.id;
|
|
13293
13320
|
const apiKey = this.streamClient.key;
|
|
13294
13321
|
const disconnectUser = () => this.streamClient.disconnectUser(timeout);
|
|
13295
|
-
this.
|
|
13296
|
-
? this.connectionPromise.then(() => disconnectUser())
|
|
13297
|
-
: disconnectUser();
|
|
13298
|
-
this.disconnectionPromise.finally(() => (this.disconnectionPromise = undefined));
|
|
13299
|
-
await this.disconnectionPromise;
|
|
13322
|
+
await withoutConcurrency(this.connectionConcurrencyTag, () => disconnectUser());
|
|
13300
13323
|
if (userId) {
|
|
13301
13324
|
StreamVideoClient._instanceMap.delete(apiKey + userId);
|
|
13302
13325
|
}
|
|
@@ -13471,11 +13494,7 @@ class StreamVideoClient {
|
|
|
13471
13494
|
*/
|
|
13472
13495
|
this.connectAnonymousUser = async (user, tokenOrProvider) => {
|
|
13473
13496
|
const connectAnonymousUser = () => this.streamClient.connectAnonymousUser(user, tokenOrProvider);
|
|
13474
|
-
this.
|
|
13475
|
-
? this.disconnectionPromise.then(() => connectAnonymousUser())
|
|
13476
|
-
: connectAnonymousUser();
|
|
13477
|
-
this.connectionPromise.finally(() => (this.connectionPromise = undefined));
|
|
13478
|
-
return this.connectionPromise;
|
|
13497
|
+
return await withoutConcurrency(this.connectionConcurrencyTag, () => connectAnonymousUser());
|
|
13479
13498
|
};
|
|
13480
13499
|
let logger = logToConsole;
|
|
13481
13500
|
let logLevel = 'warn';
|