@stream-io/video-client 1.11.4 → 1.11.5
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 +61 -44
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +61 -44
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +61 -44
- 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/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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [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)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* 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)
|
|
11
|
+
|
|
5
12
|
## [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
13
|
|
|
7
14
|
|
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.5";
|
|
3339
3332
|
const [major, minor, patch] = version.split('.');
|
|
3340
3333
|
let sdkInfo = {
|
|
3341
3334
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -11569,6 +11562,33 @@ function buildWsSuccessAfterFailureInsight(connection) {
|
|
|
11569
11562
|
return buildWsBaseInsight(connection);
|
|
11570
11563
|
}
|
|
11571
11564
|
|
|
11565
|
+
/**
|
|
11566
|
+
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
11567
|
+
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
11568
|
+
* rejection is handled everywhere promise result is expected).
|
|
11569
|
+
*
|
|
11570
|
+
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
11571
|
+
* That way, the saved promise never rejects. A callback is provided as return
|
|
11572
|
+
* value to build a *new* promise, that resolves and rejects along with
|
|
11573
|
+
* the original promise.
|
|
11574
|
+
* @param promise Promise to wrap, which possibly rejects
|
|
11575
|
+
* @returns Callback to build a new promise, which resolves and rejects along
|
|
11576
|
+
* with the original promise
|
|
11577
|
+
*/
|
|
11578
|
+
function makeSafePromise(promise) {
|
|
11579
|
+
let isPending = true;
|
|
11580
|
+
const safePromise = promise
|
|
11581
|
+
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
11582
|
+
.finally(() => (isPending = false));
|
|
11583
|
+
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
11584
|
+
if (fulfillment.status === 'rejected')
|
|
11585
|
+
throw fulfillment.error;
|
|
11586
|
+
return fulfillment.result;
|
|
11587
|
+
});
|
|
11588
|
+
unwrapPromise.checkPending = () => isPending;
|
|
11589
|
+
return unwrapPromise;
|
|
11590
|
+
}
|
|
11591
|
+
|
|
11572
11592
|
// Type guards to check WebSocket error type
|
|
11573
11593
|
const isCloseEvent = (res) => res.code !== undefined;
|
|
11574
11594
|
const isErrorEvent = (res) => res.error !== undefined;
|
|
@@ -11817,10 +11837,10 @@ class StableWSConnection {
|
|
|
11817
11837
|
this._setupConnectionPromise = () => {
|
|
11818
11838
|
this.isResolved = false;
|
|
11819
11839
|
/** a promise that is resolved once ws.open is called */
|
|
11820
|
-
this.
|
|
11840
|
+
this.connectionOpenSafe = makeSafePromise(new Promise((resolve, reject) => {
|
|
11821
11841
|
this.resolvePromise = resolve;
|
|
11822
11842
|
this.rejectPromise = reject;
|
|
11823
|
-
});
|
|
11843
|
+
}));
|
|
11824
11844
|
};
|
|
11825
11845
|
/**
|
|
11826
11846
|
* Schedules a next health check ping for websocket.
|
|
@@ -12041,13 +12061,7 @@ class StableWSConnection {
|
|
|
12041
12061
|
this._log(`_connect() - tokenProvider failed before, so going to retry`);
|
|
12042
12062
|
await this.client.tokenManager.loadToken();
|
|
12043
12063
|
}
|
|
12044
|
-
|
|
12045
|
-
if (this.client.connectionIdPromise) {
|
|
12046
|
-
if (await isPromisePending(this.client.connectionIdPromise)) {
|
|
12047
|
-
mustSetupConnectionIdPromise = false;
|
|
12048
|
-
}
|
|
12049
|
-
}
|
|
12050
|
-
if (mustSetupConnectionIdPromise) {
|
|
12064
|
+
if (!this.client.isConnectionIsPromisePending) {
|
|
12051
12065
|
this.client._setupConnectionIdPromise();
|
|
12052
12066
|
}
|
|
12053
12067
|
this._setupConnectionPromise();
|
|
@@ -12167,6 +12181,9 @@ class StableWSConnection {
|
|
|
12167
12181
|
// we don't care
|
|
12168
12182
|
}
|
|
12169
12183
|
}
|
|
12184
|
+
get connectionOpen() {
|
|
12185
|
+
return this.connectionOpenSafe?.();
|
|
12186
|
+
}
|
|
12170
12187
|
}
|
|
12171
12188
|
|
|
12172
12189
|
function isString(arrayOrString) {
|
|
@@ -12730,19 +12747,21 @@ class StreamClient {
|
|
|
12730
12747
|
if (!this.userID) {
|
|
12731
12748
|
throw Error('UserWithId is not set on client, use client.connectUser or client.connectAnonymousUser instead');
|
|
12732
12749
|
}
|
|
12733
|
-
|
|
12750
|
+
const wsPromise = this.wsPromiseSafe?.();
|
|
12751
|
+
if (this.wsConnection?.isConnecting && wsPromise) {
|
|
12734
12752
|
this.logger('info', 'client:openConnection() - connection already in progress');
|
|
12735
|
-
return
|
|
12753
|
+
return await wsPromise;
|
|
12736
12754
|
}
|
|
12737
12755
|
if ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) &&
|
|
12738
12756
|
this._hasConnectionID()) {
|
|
12739
12757
|
this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists');
|
|
12740
|
-
return
|
|
12758
|
+
return;
|
|
12741
12759
|
}
|
|
12742
12760
|
this._setupConnectionIdPromise();
|
|
12743
12761
|
this.clientID = `${this.userID}--${randomId()}`;
|
|
12744
|
-
|
|
12745
|
-
|
|
12762
|
+
const newWsPromise = this.connect();
|
|
12763
|
+
this.wsPromiseSafe = makeSafePromise(newWsPromise);
|
|
12764
|
+
return await newWsPromise;
|
|
12746
12765
|
};
|
|
12747
12766
|
/**
|
|
12748
12767
|
* Disconnects the websocket and removes the user from client.
|
|
@@ -12760,7 +12779,7 @@ class StreamClient {
|
|
|
12760
12779
|
await this.closeConnection(timeout);
|
|
12761
12780
|
removeConnectionEventListeners(this.updateNetworkConnectionStatus);
|
|
12762
12781
|
this.tokenManager.reset();
|
|
12763
|
-
this.
|
|
12782
|
+
this.connectionIdPromiseSafe = undefined;
|
|
12764
12783
|
this.rejectConnectionId = undefined;
|
|
12765
12784
|
this.resolveConnectionId = undefined;
|
|
12766
12785
|
};
|
|
@@ -12821,12 +12840,12 @@ class StreamClient {
|
|
|
12821
12840
|
/**
|
|
12822
12841
|
* sets up the this.connectionIdPromise
|
|
12823
12842
|
*/
|
|
12824
|
-
this._setupConnectionIdPromise =
|
|
12843
|
+
this._setupConnectionIdPromise = () => {
|
|
12825
12844
|
/** a promise that is resolved once connection id is set */
|
|
12826
|
-
this.
|
|
12845
|
+
this.connectionIdPromiseSafe = makeSafePromise(new Promise((resolve, reject) => {
|
|
12827
12846
|
this.resolveConnectionId = resolve;
|
|
12828
12847
|
this.rejectConnectionId = reject;
|
|
12829
|
-
});
|
|
12848
|
+
}));
|
|
12830
12849
|
};
|
|
12831
12850
|
this._logApiRequest = (type, url, data, config) => {
|
|
12832
12851
|
this.logger('trace', `client: ${type} - Request - ${url}`, {
|
|
@@ -13044,7 +13063,7 @@ class StreamClient {
|
|
|
13044
13063
|
});
|
|
13045
13064
|
};
|
|
13046
13065
|
this.getUserAgent = () => {
|
|
13047
|
-
const version = "1.11.
|
|
13066
|
+
const version = "1.11.5";
|
|
13048
13067
|
return (this.userAgent ||
|
|
13049
13068
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
13050
13069
|
};
|
|
@@ -13158,7 +13177,7 @@ class StreamClient {
|
|
|
13158
13177
|
});
|
|
13159
13178
|
// WS connection is initialized when setUser is called
|
|
13160
13179
|
this.wsConnection = null;
|
|
13161
|
-
this.
|
|
13180
|
+
this.wsPromiseSafe = null;
|
|
13162
13181
|
this.setUserPromise = null;
|
|
13163
13182
|
// mapping between channel groups and configs
|
|
13164
13183
|
this.anonymous = false;
|
|
@@ -13175,6 +13194,15 @@ class StreamClient {
|
|
|
13175
13194
|
? inputOptions.logger
|
|
13176
13195
|
: () => null;
|
|
13177
13196
|
}
|
|
13197
|
+
get connectionIdPromise() {
|
|
13198
|
+
return this.connectionIdPromiseSafe?.();
|
|
13199
|
+
}
|
|
13200
|
+
get isConnectionIsPromisePending() {
|
|
13201
|
+
return this.connectionIdPromiseSafe?.checkPending() ?? false;
|
|
13202
|
+
}
|
|
13203
|
+
get wsPromise() {
|
|
13204
|
+
return this.wsPromiseSafe?.();
|
|
13205
|
+
}
|
|
13178
13206
|
}
|
|
13179
13207
|
|
|
13180
13208
|
/**
|
|
@@ -13184,6 +13212,7 @@ class StreamVideoClient {
|
|
|
13184
13212
|
constructor(apiKeyOrArgs, opts) {
|
|
13185
13213
|
this.logLevel = 'warn';
|
|
13186
13214
|
this.eventHandlersToUnregister = [];
|
|
13215
|
+
this.connectionConcurrencyTag = Symbol('connectionConcurrencyTag');
|
|
13187
13216
|
/**
|
|
13188
13217
|
* Connects the given user to the client.
|
|
13189
13218
|
* Only one user can connect at a time, if you want to change users, call `disconnectUser` before connecting a new user.
|
|
@@ -13205,11 +13234,7 @@ class StreamVideoClient {
|
|
|
13205
13234
|
return this.streamClient.connectGuestUser(user);
|
|
13206
13235
|
};
|
|
13207
13236
|
}
|
|
13208
|
-
|
|
13209
|
-
? this.disconnectionPromise.then(() => connectUser())
|
|
13210
|
-
: connectUser();
|
|
13211
|
-
this.connectionPromise?.finally(() => (this.connectionPromise = undefined));
|
|
13212
|
-
const connectUserResponse = await this.connectionPromise;
|
|
13237
|
+
const connectUserResponse = await withoutConcurrency(this.connectionConcurrencyTag, () => connectUser());
|
|
13213
13238
|
// connectUserResponse will be void if connectUser called twice for the same user
|
|
13214
13239
|
if (connectUserResponse?.me) {
|
|
13215
13240
|
this.writeableStateStore.setConnectedUser(connectUserResponse.me);
|
|
@@ -13286,17 +13311,13 @@ class StreamVideoClient {
|
|
|
13286
13311
|
* https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
|
13287
13312
|
*/
|
|
13288
13313
|
this.disconnectUser = async (timeout) => {
|
|
13289
|
-
if (!this.streamClient.user
|
|
13314
|
+
if (!this.streamClient.user) {
|
|
13290
13315
|
return;
|
|
13291
13316
|
}
|
|
13292
13317
|
const userId = this.streamClient.user?.id;
|
|
13293
13318
|
const apiKey = this.streamClient.key;
|
|
13294
13319
|
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;
|
|
13320
|
+
await withoutConcurrency(this.connectionConcurrencyTag, () => disconnectUser());
|
|
13300
13321
|
if (userId) {
|
|
13301
13322
|
StreamVideoClient._instanceMap.delete(apiKey + userId);
|
|
13302
13323
|
}
|
|
@@ -13471,11 +13492,7 @@ class StreamVideoClient {
|
|
|
13471
13492
|
*/
|
|
13472
13493
|
this.connectAnonymousUser = async (user, tokenOrProvider) => {
|
|
13473
13494
|
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;
|
|
13495
|
+
return await withoutConcurrency(this.connectionConcurrencyTag, () => connectAnonymousUser());
|
|
13479
13496
|
};
|
|
13480
13497
|
let logger = logToConsole;
|
|
13481
13498
|
let logLevel = 'warn';
|