@stream-io/video-client 1.11.11 → 1.11.13
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 +232 -73
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +232 -73
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +232 -73
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +7 -0
- package/dist/src/StreamSfuClient.d.ts +1 -3
- package/dist/src/coordinator/connection/connection.d.ts +1 -1
- package/dist/src/coordinator/connection/types.d.ts +5 -0
- package/dist/src/helpers/promise.d.ts +14 -0
- package/dist/src/timers/index.d.ts +22 -0
- package/dist/src/timers/types.d.ts +12 -0
- package/dist/src/timers/worker.build.d.ts +3 -0
- package/dist/src/timers/worker.d.ts +1 -0
- package/package.json +4 -3
- package/src/Call.ts +38 -3
- package/src/StreamSfuClient.ts +33 -32
- package/src/StreamVideoClient.ts +4 -0
- package/src/coordinator/connection/connection.ts +14 -5
- package/src/coordinator/connection/types.ts +6 -0
- package/src/helpers/promise.ts +44 -0
- package/src/timers/index.ts +137 -0
- package/src/timers/types.ts +15 -0
- package/src/timers/worker.build.ts +26 -0
- package/src/timers/worker.ts +40 -0
- package/dist/src/helpers/withResolvers.d.ts +0 -14
- package/src/helpers/withResolvers.ts +0 -43
package/dist/index.es.js
CHANGED
|
@@ -3298,7 +3298,7 @@ const retryable = async (rpc, signal) => {
|
|
|
3298
3298
|
return result;
|
|
3299
3299
|
};
|
|
3300
3300
|
|
|
3301
|
-
const version = "1.11.
|
|
3301
|
+
const version = "1.11.13";
|
|
3302
3302
|
const [major, minor, patch] = version.split('.');
|
|
3303
3303
|
let sdkInfo = {
|
|
3304
3304
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -6375,6 +6375,32 @@ const createWebSocketSignalChannel = (opts) => {
|
|
|
6375
6375
|
return ws;
|
|
6376
6376
|
};
|
|
6377
6377
|
|
|
6378
|
+
/**
|
|
6379
|
+
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
6380
|
+
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
6381
|
+
* rejection is handled everywhere promise result is expected).
|
|
6382
|
+
*
|
|
6383
|
+
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
6384
|
+
* That way, the saved promise never rejects. A callback is provided as return
|
|
6385
|
+
* value to build a *new* promise, that resolves and rejects along with
|
|
6386
|
+
* the original promise.
|
|
6387
|
+
* @param promise Promise to wrap, which possibly rejects
|
|
6388
|
+
* @returns Callback to build a new promise, which resolves and rejects along
|
|
6389
|
+
* with the original promise
|
|
6390
|
+
*/
|
|
6391
|
+
function makeSafePromise(promise) {
|
|
6392
|
+
let isPending = true;
|
|
6393
|
+
const safePromise = promise
|
|
6394
|
+
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
6395
|
+
.finally(() => (isPending = false));
|
|
6396
|
+
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
6397
|
+
if (fulfillment.status === 'rejected')
|
|
6398
|
+
throw fulfillment.error;
|
|
6399
|
+
return fulfillment.result;
|
|
6400
|
+
});
|
|
6401
|
+
unwrapPromise.checkPending = () => isPending;
|
|
6402
|
+
return unwrapPromise;
|
|
6403
|
+
}
|
|
6378
6404
|
/**
|
|
6379
6405
|
* Creates a new promise with resolvers.
|
|
6380
6406
|
*
|
|
@@ -6407,6 +6433,151 @@ const promiseWithResolvers = () => {
|
|
|
6407
6433
|
};
|
|
6408
6434
|
};
|
|
6409
6435
|
|
|
6436
|
+
const uninitialized = Symbol('uninitialized');
|
|
6437
|
+
/**
|
|
6438
|
+
* Lazily creates a value using a provided factory
|
|
6439
|
+
*/
|
|
6440
|
+
function lazy(factory) {
|
|
6441
|
+
let value = uninitialized;
|
|
6442
|
+
return () => {
|
|
6443
|
+
if (value === uninitialized) {
|
|
6444
|
+
value = factory();
|
|
6445
|
+
}
|
|
6446
|
+
return value;
|
|
6447
|
+
};
|
|
6448
|
+
}
|
|
6449
|
+
|
|
6450
|
+
const timerWorker = {
|
|
6451
|
+
src: `var timerIdMapping = new Map();
|
|
6452
|
+
self.addEventListener('message', function (event) {
|
|
6453
|
+
var request = event.data;
|
|
6454
|
+
switch (request.type) {
|
|
6455
|
+
case 'setTimeout':
|
|
6456
|
+
case 'setInterval':
|
|
6457
|
+
timerIdMapping.set(request.id, (request.type === 'setTimeout' ? setTimeout : setInterval)(function () {
|
|
6458
|
+
tick(request.id);
|
|
6459
|
+
if (request.type === 'setTimeout') {
|
|
6460
|
+
timerIdMapping.delete(request.id);
|
|
6461
|
+
}
|
|
6462
|
+
}, request.timeout));
|
|
6463
|
+
break;
|
|
6464
|
+
case 'clearTimeout':
|
|
6465
|
+
case 'clearInterval':
|
|
6466
|
+
(request.type === 'clearTimeout' ? clearTimeout : clearInterval)(timerIdMapping.get(request.id));
|
|
6467
|
+
timerIdMapping.delete(request.id);
|
|
6468
|
+
break;
|
|
6469
|
+
}
|
|
6470
|
+
});
|
|
6471
|
+
function tick(id) {
|
|
6472
|
+
var message = { type: 'tick', id: id };
|
|
6473
|
+
self.postMessage(message);
|
|
6474
|
+
}`,
|
|
6475
|
+
};
|
|
6476
|
+
|
|
6477
|
+
class TimerWorker {
|
|
6478
|
+
constructor() {
|
|
6479
|
+
this.currentTimerId = 1;
|
|
6480
|
+
this.callbacks = new Map();
|
|
6481
|
+
this.fallback = false;
|
|
6482
|
+
}
|
|
6483
|
+
setup({ useTimerWorker = true } = {}) {
|
|
6484
|
+
if (!useTimerWorker) {
|
|
6485
|
+
this.fallback = true;
|
|
6486
|
+
return;
|
|
6487
|
+
}
|
|
6488
|
+
try {
|
|
6489
|
+
const source = timerWorker.src;
|
|
6490
|
+
const blob = new Blob([source], {
|
|
6491
|
+
type: 'application/javascript; charset=utf-8',
|
|
6492
|
+
});
|
|
6493
|
+
const script = URL.createObjectURL(blob);
|
|
6494
|
+
this.worker = new Worker(script, { name: 'str-timer-worker' });
|
|
6495
|
+
this.worker.addEventListener('message', (event) => {
|
|
6496
|
+
const { type, id } = event.data;
|
|
6497
|
+
if (type === 'tick') {
|
|
6498
|
+
this.callbacks.get(id)?.();
|
|
6499
|
+
}
|
|
6500
|
+
});
|
|
6501
|
+
}
|
|
6502
|
+
catch (err) {
|
|
6503
|
+
getLogger(['timer-worker'])('error', err);
|
|
6504
|
+
this.fallback = true;
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6507
|
+
destroy() {
|
|
6508
|
+
this.callbacks.clear();
|
|
6509
|
+
this.worker?.terminate();
|
|
6510
|
+
this.worker = undefined;
|
|
6511
|
+
this.fallback = false;
|
|
6512
|
+
}
|
|
6513
|
+
get ready() {
|
|
6514
|
+
return this.fallback || Boolean(this.worker);
|
|
6515
|
+
}
|
|
6516
|
+
setInterval(callback, timeout) {
|
|
6517
|
+
return this.setTimer('setInterval', callback, timeout);
|
|
6518
|
+
}
|
|
6519
|
+
clearInterval(id) {
|
|
6520
|
+
this.clearTimer('clearInterval', id);
|
|
6521
|
+
}
|
|
6522
|
+
setTimeout(callback, timeout) {
|
|
6523
|
+
return this.setTimer('setTimeout', callback, timeout);
|
|
6524
|
+
}
|
|
6525
|
+
clearTimeout(id) {
|
|
6526
|
+
this.clearTimer('clearTimeout', id);
|
|
6527
|
+
}
|
|
6528
|
+
setTimer(type, callback, timeout) {
|
|
6529
|
+
if (!this.ready) {
|
|
6530
|
+
this.setup();
|
|
6531
|
+
}
|
|
6532
|
+
if (this.fallback) {
|
|
6533
|
+
return (type === 'setTimeout' ? setTimeout : setInterval)(callback, timeout);
|
|
6534
|
+
}
|
|
6535
|
+
const id = this.getTimerId();
|
|
6536
|
+
this.callbacks.set(id, () => {
|
|
6537
|
+
callback();
|
|
6538
|
+
// Timeouts are one-off operations, so no need to keep callback reference
|
|
6539
|
+
// after timer has fired
|
|
6540
|
+
if (type === 'setTimeout') {
|
|
6541
|
+
this.callbacks.delete(id);
|
|
6542
|
+
}
|
|
6543
|
+
});
|
|
6544
|
+
this.sendMessage({ type, id, timeout });
|
|
6545
|
+
return id;
|
|
6546
|
+
}
|
|
6547
|
+
clearTimer(type, id) {
|
|
6548
|
+
if (!id) {
|
|
6549
|
+
return;
|
|
6550
|
+
}
|
|
6551
|
+
if (!this.ready) {
|
|
6552
|
+
this.setup();
|
|
6553
|
+
}
|
|
6554
|
+
if (this.fallback) {
|
|
6555
|
+
(type === 'clearTimeout' ? clearTimeout : clearInterval)(id);
|
|
6556
|
+
return;
|
|
6557
|
+
}
|
|
6558
|
+
this.callbacks.delete(id);
|
|
6559
|
+
this.sendMessage({ type, id });
|
|
6560
|
+
}
|
|
6561
|
+
getTimerId() {
|
|
6562
|
+
return this.currentTimerId++;
|
|
6563
|
+
}
|
|
6564
|
+
sendMessage(message) {
|
|
6565
|
+
if (!this.worker) {
|
|
6566
|
+
throw new Error("Cannot use timer worker before it's set up");
|
|
6567
|
+
}
|
|
6568
|
+
this.worker.postMessage(message);
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
let timerWorkerEnabled = false;
|
|
6572
|
+
const enableTimerWorker = () => {
|
|
6573
|
+
timerWorkerEnabled = true;
|
|
6574
|
+
};
|
|
6575
|
+
const getTimers = lazy(() => {
|
|
6576
|
+
const instance = new TimerWorker();
|
|
6577
|
+
instance.setup({ useTimerWorker: timerWorkerEnabled });
|
|
6578
|
+
return instance;
|
|
6579
|
+
});
|
|
6580
|
+
|
|
6410
6581
|
/**
|
|
6411
6582
|
* The client used for exchanging information with the SFU.
|
|
6412
6583
|
*/
|
|
@@ -6427,7 +6598,6 @@ class StreamSfuClient {
|
|
|
6427
6598
|
this.isLeaving = false;
|
|
6428
6599
|
this.pingIntervalInMs = 10 * 1000;
|
|
6429
6600
|
this.unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
|
|
6430
|
-
this.restoreWebSocketConcurrencyTag = Symbol('recoverWebSocket');
|
|
6431
6601
|
/**
|
|
6432
6602
|
* Promise that resolves when the JoinResponse is received.
|
|
6433
6603
|
* Rejects after a certain threshold if the response is not received.
|
|
@@ -6448,31 +6618,25 @@ class StreamSfuClient {
|
|
|
6448
6618
|
},
|
|
6449
6619
|
});
|
|
6450
6620
|
this.signalWs.addEventListener('close', this.handleWebSocketClose);
|
|
6451
|
-
this.
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6621
|
+
this.signalReady = makeSafePromise(Promise.race([
|
|
6622
|
+
new Promise((resolve) => {
|
|
6623
|
+
const onOpen = () => {
|
|
6624
|
+
this.signalWs.removeEventListener('open', onOpen);
|
|
6625
|
+
resolve(this.signalWs);
|
|
6626
|
+
};
|
|
6627
|
+
this.signalWs.addEventListener('open', onOpen);
|
|
6628
|
+
}),
|
|
6629
|
+
new Promise((resolve, reject) => {
|
|
6630
|
+
setTimeout(() => reject(new Error('SFU WS connection timed out')), this.joinResponseTimeout);
|
|
6631
|
+
}),
|
|
6632
|
+
]));
|
|
6459
6633
|
};
|
|
6460
6634
|
this.cleanUpWebSocket = () => {
|
|
6461
|
-
this.signalWs.removeEventListener('error', this.restoreWebSocket);
|
|
6462
6635
|
this.signalWs.removeEventListener('close', this.handleWebSocketClose);
|
|
6463
6636
|
};
|
|
6464
|
-
this.restoreWebSocket = () => {
|
|
6465
|
-
withoutConcurrency(this.restoreWebSocketConcurrencyTag, async () => {
|
|
6466
|
-
await this.networkAvailableTask?.promise;
|
|
6467
|
-
this.logger('debug', 'Restoring SFU WS connection');
|
|
6468
|
-
this.cleanUpWebSocket();
|
|
6469
|
-
await sleep(500);
|
|
6470
|
-
this.createWebSocket();
|
|
6471
|
-
}).catch((err) => this.logger('debug', `Can't restore WS connection`, err));
|
|
6472
|
-
};
|
|
6473
6637
|
this.handleWebSocketClose = () => {
|
|
6474
6638
|
this.signalWs.removeEventListener('close', this.handleWebSocketClose);
|
|
6475
|
-
clearInterval(this.keepAliveInterval);
|
|
6639
|
+
getTimers().clearInterval(this.keepAliveInterval);
|
|
6476
6640
|
clearTimeout(this.connectionCheckTimeout);
|
|
6477
6641
|
this.onSignalClose?.();
|
|
6478
6642
|
};
|
|
@@ -6563,7 +6727,7 @@ class StreamSfuClient {
|
|
|
6563
6727
|
};
|
|
6564
6728
|
this.join = async (data) => {
|
|
6565
6729
|
// wait for the signal web socket to be ready before sending "joinRequest"
|
|
6566
|
-
await this.signalReady;
|
|
6730
|
+
await this.signalReady();
|
|
6567
6731
|
if (this.joinResponseTask.isResolved || this.joinResponseTask.isRejected) {
|
|
6568
6732
|
// we need to lock the RPC requests until we receive a JoinResponse.
|
|
6569
6733
|
// that's why we have this primitive lock mechanism.
|
|
@@ -6618,7 +6782,7 @@ class StreamSfuClient {
|
|
|
6618
6782
|
}));
|
|
6619
6783
|
};
|
|
6620
6784
|
this.send = async (message) => {
|
|
6621
|
-
await this.signalReady; // wait for the signal ws to be open
|
|
6785
|
+
await this.signalReady(); // wait for the signal ws to be open
|
|
6622
6786
|
const msgJson = SfuRequest.toJson(message);
|
|
6623
6787
|
if (this.signalWs.readyState !== WebSocket.OPEN) {
|
|
6624
6788
|
this.logger('debug', 'Signal WS is not open. Skipping message', msgJson);
|
|
@@ -6628,8 +6792,9 @@ class StreamSfuClient {
|
|
|
6628
6792
|
this.signalWs.send(SfuRequest.toBinary(message));
|
|
6629
6793
|
};
|
|
6630
6794
|
this.keepAlive = () => {
|
|
6631
|
-
|
|
6632
|
-
this.keepAliveInterval
|
|
6795
|
+
const timers = getTimers();
|
|
6796
|
+
timers.clearInterval(this.keepAliveInterval);
|
|
6797
|
+
this.keepAliveInterval = timers.setInterval(() => {
|
|
6633
6798
|
this.ping().catch((e) => {
|
|
6634
6799
|
this.logger('error', 'Error sending healthCheckRequest to SFU', e);
|
|
6635
6800
|
});
|
|
@@ -8210,20 +8375,6 @@ function canQueryPermissions() {
|
|
|
8210
8375
|
!!navigator.permissions?.query);
|
|
8211
8376
|
}
|
|
8212
8377
|
|
|
8213
|
-
const uninitialized = Symbol('uninitialized');
|
|
8214
|
-
/**
|
|
8215
|
-
* Lazily creates a value using a provided factory
|
|
8216
|
-
*/
|
|
8217
|
-
function lazy(factory) {
|
|
8218
|
-
let value = uninitialized;
|
|
8219
|
-
return () => {
|
|
8220
|
-
if (value === uninitialized) {
|
|
8221
|
-
value = factory();
|
|
8222
|
-
}
|
|
8223
|
-
return value;
|
|
8224
|
-
};
|
|
8225
|
-
}
|
|
8226
|
-
|
|
8227
8378
|
/**
|
|
8228
8379
|
* Returns an Observable that emits the list of available devices
|
|
8229
8380
|
* that meet the given constraints.
|
|
@@ -9835,6 +9986,7 @@ class Call {
|
|
|
9835
9986
|
this.reconnectAttempts = 0;
|
|
9836
9987
|
this.reconnectStrategy = WebsocketReconnectStrategy.UNSPECIFIED;
|
|
9837
9988
|
this.fastReconnectDeadlineSeconds = 0;
|
|
9989
|
+
this.disconnectionTimeoutSeconds = 0;
|
|
9838
9990
|
this.lastOfflineTimestamp = 0;
|
|
9839
9991
|
// maintain the order of publishing tracks to restore them after a reconnection
|
|
9840
9992
|
// it shouldn't contain duplicates
|
|
@@ -10351,6 +10503,10 @@ class Call {
|
|
|
10351
10503
|
*/
|
|
10352
10504
|
this.handleSfuSignalClose = (sfuClient) => {
|
|
10353
10505
|
this.logger('debug', '[Reconnect] SFU signal connection closed');
|
|
10506
|
+
// SFU WS closed before we finished current join, no need to schedule reconnect
|
|
10507
|
+
// because join operation will fail
|
|
10508
|
+
if (this.state.callingState === CallingState.JOINING)
|
|
10509
|
+
return;
|
|
10354
10510
|
// normal close, no need to reconnect
|
|
10355
10511
|
if (sfuClient.isLeaving)
|
|
10356
10512
|
return;
|
|
@@ -10366,10 +10522,21 @@ class Call {
|
|
|
10366
10522
|
* @param strategy the reconnection strategy to use.
|
|
10367
10523
|
*/
|
|
10368
10524
|
this.reconnect = async (strategy) => {
|
|
10525
|
+
if (this.state.callingState === CallingState.RECONNECTING ||
|
|
10526
|
+
this.state.callingState === CallingState.RECONNECTING_FAILED)
|
|
10527
|
+
return;
|
|
10369
10528
|
return withoutConcurrency(this.reconnectConcurrencyTag, async () => {
|
|
10370
10529
|
this.logger('info', `[Reconnect] Reconnecting with strategy ${WebsocketReconnectStrategy[strategy]}`);
|
|
10530
|
+
let reconnectStartTime = Date.now();
|
|
10371
10531
|
this.reconnectStrategy = strategy;
|
|
10372
10532
|
do {
|
|
10533
|
+
if (this.disconnectionTimeoutSeconds > 0 &&
|
|
10534
|
+
(Date.now() - reconnectStartTime) / 1000 >
|
|
10535
|
+
this.disconnectionTimeoutSeconds) {
|
|
10536
|
+
this.logger('warn', '[Reconnect] Stopping reconnection attempts after reaching disconnection timeout');
|
|
10537
|
+
this.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
10538
|
+
return;
|
|
10539
|
+
}
|
|
10373
10540
|
// we don't increment reconnect attempts for the FAST strategy.
|
|
10374
10541
|
if (this.reconnectStrategy !== WebsocketReconnectStrategy.FAST) {
|
|
10375
10542
|
this.reconnectAttempts++;
|
|
@@ -10469,7 +10636,7 @@ class Call {
|
|
|
10469
10636
|
const currentPublisher = this.publisher;
|
|
10470
10637
|
currentSubscriber?.detachEventHandlers();
|
|
10471
10638
|
currentPublisher?.detachEventHandlers();
|
|
10472
|
-
const migrationTask = currentSfuClient.enterMigration();
|
|
10639
|
+
const migrationTask = makeSafePromise(currentSfuClient.enterMigration());
|
|
10473
10640
|
try {
|
|
10474
10641
|
const currentSfu = currentSfuClient.edgeName;
|
|
10475
10642
|
await this.join({ ...this.joinCallData, migrating_from: currentSfu });
|
|
@@ -10485,7 +10652,7 @@ class Call {
|
|
|
10485
10652
|
// Wait for the migration to complete, then close the previous SFU client
|
|
10486
10653
|
// and the peer connection instances. In case of failure, the migration
|
|
10487
10654
|
// task would throw an error and REJOIN would be attempted.
|
|
10488
|
-
await migrationTask;
|
|
10655
|
+
await migrationTask();
|
|
10489
10656
|
// in MIGRATE, we can consider the call as joined only after
|
|
10490
10657
|
// `participantMigrationComplete` event is received, signaled by
|
|
10491
10658
|
// the `migrationTask`
|
|
@@ -11341,6 +11508,14 @@ class Call {
|
|
|
11341
11508
|
this.dynascaleManager.setVideoTrackSubscriptionOverrides(enabled ? undefined : { enabled: false });
|
|
11342
11509
|
this.dynascaleManager.applyTrackSubscriptions();
|
|
11343
11510
|
};
|
|
11511
|
+
/**
|
|
11512
|
+
* Sets the maximum amount of time a user can remain waiting for a reconnect
|
|
11513
|
+
* after a network disruption
|
|
11514
|
+
* @param timeoutSeconds Timeout in seconds, or 0 to keep reconnecting indefinetely
|
|
11515
|
+
*/
|
|
11516
|
+
this.setDisconnectionTimeout = (timeoutSeconds) => {
|
|
11517
|
+
this.disconnectionTimeoutSeconds = timeoutSeconds;
|
|
11518
|
+
};
|
|
11344
11519
|
this.type = type;
|
|
11345
11520
|
this.id = id;
|
|
11346
11521
|
this.cid = `${type}:${id}`;
|
|
@@ -11494,33 +11669,6 @@ class Call {
|
|
|
11494
11669
|
}
|
|
11495
11670
|
}
|
|
11496
11671
|
|
|
11497
|
-
/**
|
|
11498
|
-
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
11499
|
-
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
11500
|
-
* rejection is handled everywhere promise result is expected).
|
|
11501
|
-
*
|
|
11502
|
-
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
11503
|
-
* That way, the saved promise never rejects. A callback is provided as return
|
|
11504
|
-
* value to build a *new* promise, that resolves and rejects along with
|
|
11505
|
-
* the original promise.
|
|
11506
|
-
* @param promise Promise to wrap, which possibly rejects
|
|
11507
|
-
* @returns Callback to build a new promise, which resolves and rejects along
|
|
11508
|
-
* with the original promise
|
|
11509
|
-
*/
|
|
11510
|
-
function makeSafePromise(promise) {
|
|
11511
|
-
let isPending = true;
|
|
11512
|
-
const safePromise = promise
|
|
11513
|
-
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
11514
|
-
.finally(() => (isPending = false));
|
|
11515
|
-
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
11516
|
-
if (fulfillment.status === 'rejected')
|
|
11517
|
-
throw fulfillment.error;
|
|
11518
|
-
return fulfillment.result;
|
|
11519
|
-
});
|
|
11520
|
-
unwrapPromise.checkPending = () => isPending;
|
|
11521
|
-
return unwrapPromise;
|
|
11522
|
-
}
|
|
11523
|
-
|
|
11524
11672
|
/**
|
|
11525
11673
|
* StableWSConnection - A WS connection that reconnects upon failure.
|
|
11526
11674
|
* - the browser will sometimes report that you're online or offline
|
|
@@ -11773,9 +11921,12 @@ class StableWSConnection {
|
|
|
11773
11921
|
* Schedules a next health check ping for websocket.
|
|
11774
11922
|
*/
|
|
11775
11923
|
this.scheduleNextPing = () => {
|
|
11924
|
+
const timers = getTimers();
|
|
11925
|
+
if (this.healthCheckTimeoutRef) {
|
|
11926
|
+
timers.clearTimeout(this.healthCheckTimeoutRef);
|
|
11927
|
+
}
|
|
11776
11928
|
// 30 seconds is the recommended interval (messenger uses this)
|
|
11777
|
-
|
|
11778
|
-
this.healthCheckTimeoutRef = setTimeout(() => {
|
|
11929
|
+
this.healthCheckTimeoutRef = timers.setTimeout(() => {
|
|
11779
11930
|
// send the healthcheck..., server replies with a health check event
|
|
11780
11931
|
const data = [{ type: 'health.check', client_id: this.client.clientID }];
|
|
11781
11932
|
// try to send on the connection
|
|
@@ -11918,8 +12069,12 @@ class StableWSConnection {
|
|
|
11918
12069
|
this.isConnecting = false;
|
|
11919
12070
|
this.isDisconnected = true;
|
|
11920
12071
|
// start by removing all the listeners
|
|
11921
|
-
|
|
11922
|
-
|
|
12072
|
+
if (this.healthCheckTimeoutRef) {
|
|
12073
|
+
getTimers().clearInterval(this.healthCheckTimeoutRef);
|
|
12074
|
+
}
|
|
12075
|
+
if (this.connectionCheckTimeoutRef) {
|
|
12076
|
+
clearInterval(this.connectionCheckTimeoutRef);
|
|
12077
|
+
}
|
|
11923
12078
|
removeConnectionEventListeners(this.onlineStatusChanged);
|
|
11924
12079
|
this.isHealthy = false;
|
|
11925
12080
|
let isClosedPromise;
|
|
@@ -12619,7 +12774,7 @@ class StreamClient {
|
|
|
12619
12774
|
return await this.wsConnection.connect(this.defaultWSTimeout);
|
|
12620
12775
|
};
|
|
12621
12776
|
this.getUserAgent = () => {
|
|
12622
|
-
const version = "1.11.
|
|
12777
|
+
const version = "1.11.13";
|
|
12623
12778
|
return (this.userAgent ||
|
|
12624
12779
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
12625
12780
|
};
|
|
@@ -13030,10 +13185,14 @@ class StreamVideoClient {
|
|
|
13030
13185
|
if (typeof apiKeyOrArgs === 'string') {
|
|
13031
13186
|
logLevel = opts?.logLevel || logLevel;
|
|
13032
13187
|
logger = opts?.logger || logger;
|
|
13188
|
+
if (opts?.expertimental_enableTimerWorker)
|
|
13189
|
+
enableTimerWorker();
|
|
13033
13190
|
}
|
|
13034
13191
|
else {
|
|
13035
13192
|
logLevel = apiKeyOrArgs.options?.logLevel || logLevel;
|
|
13036
13193
|
logger = apiKeyOrArgs.options?.logger || logger;
|
|
13194
|
+
if (apiKeyOrArgs.options?.expertimental_enableTimerWorker)
|
|
13195
|
+
enableTimerWorker();
|
|
13037
13196
|
}
|
|
13038
13197
|
setLogger(logger, logLevel);
|
|
13039
13198
|
this.logger = getLogger(['client']);
|