@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.cjs.js
CHANGED
|
@@ -3318,7 +3318,7 @@ const retryable = async (rpc, signal) => {
|
|
|
3318
3318
|
return result;
|
|
3319
3319
|
};
|
|
3320
3320
|
|
|
3321
|
-
const version = "1.11.
|
|
3321
|
+
const version = "1.11.13";
|
|
3322
3322
|
const [major, minor, patch] = version.split('.');
|
|
3323
3323
|
let sdkInfo = {
|
|
3324
3324
|
type: SdkType.PLAIN_JAVASCRIPT,
|
|
@@ -6395,6 +6395,32 @@ const createWebSocketSignalChannel = (opts) => {
|
|
|
6395
6395
|
return ws;
|
|
6396
6396
|
};
|
|
6397
6397
|
|
|
6398
|
+
/**
|
|
6399
|
+
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
6400
|
+
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
6401
|
+
* rejection is handled everywhere promise result is expected).
|
|
6402
|
+
*
|
|
6403
|
+
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
6404
|
+
* That way, the saved promise never rejects. A callback is provided as return
|
|
6405
|
+
* value to build a *new* promise, that resolves and rejects along with
|
|
6406
|
+
* the original promise.
|
|
6407
|
+
* @param promise Promise to wrap, which possibly rejects
|
|
6408
|
+
* @returns Callback to build a new promise, which resolves and rejects along
|
|
6409
|
+
* with the original promise
|
|
6410
|
+
*/
|
|
6411
|
+
function makeSafePromise(promise) {
|
|
6412
|
+
let isPending = true;
|
|
6413
|
+
const safePromise = promise
|
|
6414
|
+
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
6415
|
+
.finally(() => (isPending = false));
|
|
6416
|
+
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
6417
|
+
if (fulfillment.status === 'rejected')
|
|
6418
|
+
throw fulfillment.error;
|
|
6419
|
+
return fulfillment.result;
|
|
6420
|
+
});
|
|
6421
|
+
unwrapPromise.checkPending = () => isPending;
|
|
6422
|
+
return unwrapPromise;
|
|
6423
|
+
}
|
|
6398
6424
|
/**
|
|
6399
6425
|
* Creates a new promise with resolvers.
|
|
6400
6426
|
*
|
|
@@ -6427,6 +6453,151 @@ const promiseWithResolvers = () => {
|
|
|
6427
6453
|
};
|
|
6428
6454
|
};
|
|
6429
6455
|
|
|
6456
|
+
const uninitialized = Symbol('uninitialized');
|
|
6457
|
+
/**
|
|
6458
|
+
* Lazily creates a value using a provided factory
|
|
6459
|
+
*/
|
|
6460
|
+
function lazy(factory) {
|
|
6461
|
+
let value = uninitialized;
|
|
6462
|
+
return () => {
|
|
6463
|
+
if (value === uninitialized) {
|
|
6464
|
+
value = factory();
|
|
6465
|
+
}
|
|
6466
|
+
return value;
|
|
6467
|
+
};
|
|
6468
|
+
}
|
|
6469
|
+
|
|
6470
|
+
const timerWorker = {
|
|
6471
|
+
src: `var timerIdMapping = new Map();
|
|
6472
|
+
self.addEventListener('message', function (event) {
|
|
6473
|
+
var request = event.data;
|
|
6474
|
+
switch (request.type) {
|
|
6475
|
+
case 'setTimeout':
|
|
6476
|
+
case 'setInterval':
|
|
6477
|
+
timerIdMapping.set(request.id, (request.type === 'setTimeout' ? setTimeout : setInterval)(function () {
|
|
6478
|
+
tick(request.id);
|
|
6479
|
+
if (request.type === 'setTimeout') {
|
|
6480
|
+
timerIdMapping.delete(request.id);
|
|
6481
|
+
}
|
|
6482
|
+
}, request.timeout));
|
|
6483
|
+
break;
|
|
6484
|
+
case 'clearTimeout':
|
|
6485
|
+
case 'clearInterval':
|
|
6486
|
+
(request.type === 'clearTimeout' ? clearTimeout : clearInterval)(timerIdMapping.get(request.id));
|
|
6487
|
+
timerIdMapping.delete(request.id);
|
|
6488
|
+
break;
|
|
6489
|
+
}
|
|
6490
|
+
});
|
|
6491
|
+
function tick(id) {
|
|
6492
|
+
var message = { type: 'tick', id: id };
|
|
6493
|
+
self.postMessage(message);
|
|
6494
|
+
}`,
|
|
6495
|
+
};
|
|
6496
|
+
|
|
6497
|
+
class TimerWorker {
|
|
6498
|
+
constructor() {
|
|
6499
|
+
this.currentTimerId = 1;
|
|
6500
|
+
this.callbacks = new Map();
|
|
6501
|
+
this.fallback = false;
|
|
6502
|
+
}
|
|
6503
|
+
setup({ useTimerWorker = true } = {}) {
|
|
6504
|
+
if (!useTimerWorker) {
|
|
6505
|
+
this.fallback = true;
|
|
6506
|
+
return;
|
|
6507
|
+
}
|
|
6508
|
+
try {
|
|
6509
|
+
const source = timerWorker.src;
|
|
6510
|
+
const blob = new Blob([source], {
|
|
6511
|
+
type: 'application/javascript; charset=utf-8',
|
|
6512
|
+
});
|
|
6513
|
+
const script = URL.createObjectURL(blob);
|
|
6514
|
+
this.worker = new Worker(script, { name: 'str-timer-worker' });
|
|
6515
|
+
this.worker.addEventListener('message', (event) => {
|
|
6516
|
+
const { type, id } = event.data;
|
|
6517
|
+
if (type === 'tick') {
|
|
6518
|
+
this.callbacks.get(id)?.();
|
|
6519
|
+
}
|
|
6520
|
+
});
|
|
6521
|
+
}
|
|
6522
|
+
catch (err) {
|
|
6523
|
+
getLogger(['timer-worker'])('error', err);
|
|
6524
|
+
this.fallback = true;
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
destroy() {
|
|
6528
|
+
this.callbacks.clear();
|
|
6529
|
+
this.worker?.terminate();
|
|
6530
|
+
this.worker = undefined;
|
|
6531
|
+
this.fallback = false;
|
|
6532
|
+
}
|
|
6533
|
+
get ready() {
|
|
6534
|
+
return this.fallback || Boolean(this.worker);
|
|
6535
|
+
}
|
|
6536
|
+
setInterval(callback, timeout) {
|
|
6537
|
+
return this.setTimer('setInterval', callback, timeout);
|
|
6538
|
+
}
|
|
6539
|
+
clearInterval(id) {
|
|
6540
|
+
this.clearTimer('clearInterval', id);
|
|
6541
|
+
}
|
|
6542
|
+
setTimeout(callback, timeout) {
|
|
6543
|
+
return this.setTimer('setTimeout', callback, timeout);
|
|
6544
|
+
}
|
|
6545
|
+
clearTimeout(id) {
|
|
6546
|
+
this.clearTimer('clearTimeout', id);
|
|
6547
|
+
}
|
|
6548
|
+
setTimer(type, callback, timeout) {
|
|
6549
|
+
if (!this.ready) {
|
|
6550
|
+
this.setup();
|
|
6551
|
+
}
|
|
6552
|
+
if (this.fallback) {
|
|
6553
|
+
return (type === 'setTimeout' ? setTimeout : setInterval)(callback, timeout);
|
|
6554
|
+
}
|
|
6555
|
+
const id = this.getTimerId();
|
|
6556
|
+
this.callbacks.set(id, () => {
|
|
6557
|
+
callback();
|
|
6558
|
+
// Timeouts are one-off operations, so no need to keep callback reference
|
|
6559
|
+
// after timer has fired
|
|
6560
|
+
if (type === 'setTimeout') {
|
|
6561
|
+
this.callbacks.delete(id);
|
|
6562
|
+
}
|
|
6563
|
+
});
|
|
6564
|
+
this.sendMessage({ type, id, timeout });
|
|
6565
|
+
return id;
|
|
6566
|
+
}
|
|
6567
|
+
clearTimer(type, id) {
|
|
6568
|
+
if (!id) {
|
|
6569
|
+
return;
|
|
6570
|
+
}
|
|
6571
|
+
if (!this.ready) {
|
|
6572
|
+
this.setup();
|
|
6573
|
+
}
|
|
6574
|
+
if (this.fallback) {
|
|
6575
|
+
(type === 'clearTimeout' ? clearTimeout : clearInterval)(id);
|
|
6576
|
+
return;
|
|
6577
|
+
}
|
|
6578
|
+
this.callbacks.delete(id);
|
|
6579
|
+
this.sendMessage({ type, id });
|
|
6580
|
+
}
|
|
6581
|
+
getTimerId() {
|
|
6582
|
+
return this.currentTimerId++;
|
|
6583
|
+
}
|
|
6584
|
+
sendMessage(message) {
|
|
6585
|
+
if (!this.worker) {
|
|
6586
|
+
throw new Error("Cannot use timer worker before it's set up");
|
|
6587
|
+
}
|
|
6588
|
+
this.worker.postMessage(message);
|
|
6589
|
+
}
|
|
6590
|
+
}
|
|
6591
|
+
let timerWorkerEnabled = false;
|
|
6592
|
+
const enableTimerWorker = () => {
|
|
6593
|
+
timerWorkerEnabled = true;
|
|
6594
|
+
};
|
|
6595
|
+
const getTimers = lazy(() => {
|
|
6596
|
+
const instance = new TimerWorker();
|
|
6597
|
+
instance.setup({ useTimerWorker: timerWorkerEnabled });
|
|
6598
|
+
return instance;
|
|
6599
|
+
});
|
|
6600
|
+
|
|
6430
6601
|
/**
|
|
6431
6602
|
* The client used for exchanging information with the SFU.
|
|
6432
6603
|
*/
|
|
@@ -6447,7 +6618,6 @@ class StreamSfuClient {
|
|
|
6447
6618
|
this.isLeaving = false;
|
|
6448
6619
|
this.pingIntervalInMs = 10 * 1000;
|
|
6449
6620
|
this.unhealthyTimeoutInMs = this.pingIntervalInMs + 5 * 1000;
|
|
6450
|
-
this.restoreWebSocketConcurrencyTag = Symbol('recoverWebSocket');
|
|
6451
6621
|
/**
|
|
6452
6622
|
* Promise that resolves when the JoinResponse is received.
|
|
6453
6623
|
* Rejects after a certain threshold if the response is not received.
|
|
@@ -6468,31 +6638,25 @@ class StreamSfuClient {
|
|
|
6468
6638
|
},
|
|
6469
6639
|
});
|
|
6470
6640
|
this.signalWs.addEventListener('close', this.handleWebSocketClose);
|
|
6471
|
-
this.
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6641
|
+
this.signalReady = makeSafePromise(Promise.race([
|
|
6642
|
+
new Promise((resolve) => {
|
|
6643
|
+
const onOpen = () => {
|
|
6644
|
+
this.signalWs.removeEventListener('open', onOpen);
|
|
6645
|
+
resolve(this.signalWs);
|
|
6646
|
+
};
|
|
6647
|
+
this.signalWs.addEventListener('open', onOpen);
|
|
6648
|
+
}),
|
|
6649
|
+
new Promise((resolve, reject) => {
|
|
6650
|
+
setTimeout(() => reject(new Error('SFU WS connection timed out')), this.joinResponseTimeout);
|
|
6651
|
+
}),
|
|
6652
|
+
]));
|
|
6479
6653
|
};
|
|
6480
6654
|
this.cleanUpWebSocket = () => {
|
|
6481
|
-
this.signalWs.removeEventListener('error', this.restoreWebSocket);
|
|
6482
6655
|
this.signalWs.removeEventListener('close', this.handleWebSocketClose);
|
|
6483
6656
|
};
|
|
6484
|
-
this.restoreWebSocket = () => {
|
|
6485
|
-
withoutConcurrency(this.restoreWebSocketConcurrencyTag, async () => {
|
|
6486
|
-
await this.networkAvailableTask?.promise;
|
|
6487
|
-
this.logger('debug', 'Restoring SFU WS connection');
|
|
6488
|
-
this.cleanUpWebSocket();
|
|
6489
|
-
await sleep(500);
|
|
6490
|
-
this.createWebSocket();
|
|
6491
|
-
}).catch((err) => this.logger('debug', `Can't restore WS connection`, err));
|
|
6492
|
-
};
|
|
6493
6657
|
this.handleWebSocketClose = () => {
|
|
6494
6658
|
this.signalWs.removeEventListener('close', this.handleWebSocketClose);
|
|
6495
|
-
clearInterval(this.keepAliveInterval);
|
|
6659
|
+
getTimers().clearInterval(this.keepAliveInterval);
|
|
6496
6660
|
clearTimeout(this.connectionCheckTimeout);
|
|
6497
6661
|
this.onSignalClose?.();
|
|
6498
6662
|
};
|
|
@@ -6583,7 +6747,7 @@ class StreamSfuClient {
|
|
|
6583
6747
|
};
|
|
6584
6748
|
this.join = async (data) => {
|
|
6585
6749
|
// wait for the signal web socket to be ready before sending "joinRequest"
|
|
6586
|
-
await this.signalReady;
|
|
6750
|
+
await this.signalReady();
|
|
6587
6751
|
if (this.joinResponseTask.isResolved || this.joinResponseTask.isRejected) {
|
|
6588
6752
|
// we need to lock the RPC requests until we receive a JoinResponse.
|
|
6589
6753
|
// that's why we have this primitive lock mechanism.
|
|
@@ -6638,7 +6802,7 @@ class StreamSfuClient {
|
|
|
6638
6802
|
}));
|
|
6639
6803
|
};
|
|
6640
6804
|
this.send = async (message) => {
|
|
6641
|
-
await this.signalReady; // wait for the signal ws to be open
|
|
6805
|
+
await this.signalReady(); // wait for the signal ws to be open
|
|
6642
6806
|
const msgJson = SfuRequest.toJson(message);
|
|
6643
6807
|
if (this.signalWs.readyState !== WebSocket.OPEN) {
|
|
6644
6808
|
this.logger('debug', 'Signal WS is not open. Skipping message', msgJson);
|
|
@@ -6648,8 +6812,9 @@ class StreamSfuClient {
|
|
|
6648
6812
|
this.signalWs.send(SfuRequest.toBinary(message));
|
|
6649
6813
|
};
|
|
6650
6814
|
this.keepAlive = () => {
|
|
6651
|
-
|
|
6652
|
-
this.keepAliveInterval
|
|
6815
|
+
const timers = getTimers();
|
|
6816
|
+
timers.clearInterval(this.keepAliveInterval);
|
|
6817
|
+
this.keepAliveInterval = timers.setInterval(() => {
|
|
6653
6818
|
this.ping().catch((e) => {
|
|
6654
6819
|
this.logger('error', 'Error sending healthCheckRequest to SFU', e);
|
|
6655
6820
|
});
|
|
@@ -8230,20 +8395,6 @@ function canQueryPermissions() {
|
|
|
8230
8395
|
!!navigator.permissions?.query);
|
|
8231
8396
|
}
|
|
8232
8397
|
|
|
8233
|
-
const uninitialized = Symbol('uninitialized');
|
|
8234
|
-
/**
|
|
8235
|
-
* Lazily creates a value using a provided factory
|
|
8236
|
-
*/
|
|
8237
|
-
function lazy(factory) {
|
|
8238
|
-
let value = uninitialized;
|
|
8239
|
-
return () => {
|
|
8240
|
-
if (value === uninitialized) {
|
|
8241
|
-
value = factory();
|
|
8242
|
-
}
|
|
8243
|
-
return value;
|
|
8244
|
-
};
|
|
8245
|
-
}
|
|
8246
|
-
|
|
8247
8398
|
/**
|
|
8248
8399
|
* Returns an Observable that emits the list of available devices
|
|
8249
8400
|
* that meet the given constraints.
|
|
@@ -9855,6 +10006,7 @@ class Call {
|
|
|
9855
10006
|
this.reconnectAttempts = 0;
|
|
9856
10007
|
this.reconnectStrategy = WebsocketReconnectStrategy.UNSPECIFIED;
|
|
9857
10008
|
this.fastReconnectDeadlineSeconds = 0;
|
|
10009
|
+
this.disconnectionTimeoutSeconds = 0;
|
|
9858
10010
|
this.lastOfflineTimestamp = 0;
|
|
9859
10011
|
// maintain the order of publishing tracks to restore them after a reconnection
|
|
9860
10012
|
// it shouldn't contain duplicates
|
|
@@ -10371,6 +10523,10 @@ class Call {
|
|
|
10371
10523
|
*/
|
|
10372
10524
|
this.handleSfuSignalClose = (sfuClient) => {
|
|
10373
10525
|
this.logger('debug', '[Reconnect] SFU signal connection closed');
|
|
10526
|
+
// SFU WS closed before we finished current join, no need to schedule reconnect
|
|
10527
|
+
// because join operation will fail
|
|
10528
|
+
if (this.state.callingState === exports.CallingState.JOINING)
|
|
10529
|
+
return;
|
|
10374
10530
|
// normal close, no need to reconnect
|
|
10375
10531
|
if (sfuClient.isLeaving)
|
|
10376
10532
|
return;
|
|
@@ -10386,10 +10542,21 @@ class Call {
|
|
|
10386
10542
|
* @param strategy the reconnection strategy to use.
|
|
10387
10543
|
*/
|
|
10388
10544
|
this.reconnect = async (strategy) => {
|
|
10545
|
+
if (this.state.callingState === exports.CallingState.RECONNECTING ||
|
|
10546
|
+
this.state.callingState === exports.CallingState.RECONNECTING_FAILED)
|
|
10547
|
+
return;
|
|
10389
10548
|
return withoutConcurrency(this.reconnectConcurrencyTag, async () => {
|
|
10390
10549
|
this.logger('info', `[Reconnect] Reconnecting with strategy ${WebsocketReconnectStrategy[strategy]}`);
|
|
10550
|
+
let reconnectStartTime = Date.now();
|
|
10391
10551
|
this.reconnectStrategy = strategy;
|
|
10392
10552
|
do {
|
|
10553
|
+
if (this.disconnectionTimeoutSeconds > 0 &&
|
|
10554
|
+
(Date.now() - reconnectStartTime) / 1000 >
|
|
10555
|
+
this.disconnectionTimeoutSeconds) {
|
|
10556
|
+
this.logger('warn', '[Reconnect] Stopping reconnection attempts after reaching disconnection timeout');
|
|
10557
|
+
this.state.setCallingState(exports.CallingState.RECONNECTING_FAILED);
|
|
10558
|
+
return;
|
|
10559
|
+
}
|
|
10393
10560
|
// we don't increment reconnect attempts for the FAST strategy.
|
|
10394
10561
|
if (this.reconnectStrategy !== WebsocketReconnectStrategy.FAST) {
|
|
10395
10562
|
this.reconnectAttempts++;
|
|
@@ -10489,7 +10656,7 @@ class Call {
|
|
|
10489
10656
|
const currentPublisher = this.publisher;
|
|
10490
10657
|
currentSubscriber?.detachEventHandlers();
|
|
10491
10658
|
currentPublisher?.detachEventHandlers();
|
|
10492
|
-
const migrationTask = currentSfuClient.enterMigration();
|
|
10659
|
+
const migrationTask = makeSafePromise(currentSfuClient.enterMigration());
|
|
10493
10660
|
try {
|
|
10494
10661
|
const currentSfu = currentSfuClient.edgeName;
|
|
10495
10662
|
await this.join({ ...this.joinCallData, migrating_from: currentSfu });
|
|
@@ -10505,7 +10672,7 @@ class Call {
|
|
|
10505
10672
|
// Wait for the migration to complete, then close the previous SFU client
|
|
10506
10673
|
// and the peer connection instances. In case of failure, the migration
|
|
10507
10674
|
// task would throw an error and REJOIN would be attempted.
|
|
10508
|
-
await migrationTask;
|
|
10675
|
+
await migrationTask();
|
|
10509
10676
|
// in MIGRATE, we can consider the call as joined only after
|
|
10510
10677
|
// `participantMigrationComplete` event is received, signaled by
|
|
10511
10678
|
// the `migrationTask`
|
|
@@ -11361,6 +11528,14 @@ class Call {
|
|
|
11361
11528
|
this.dynascaleManager.setVideoTrackSubscriptionOverrides(enabled ? undefined : { enabled: false });
|
|
11362
11529
|
this.dynascaleManager.applyTrackSubscriptions();
|
|
11363
11530
|
};
|
|
11531
|
+
/**
|
|
11532
|
+
* Sets the maximum amount of time a user can remain waiting for a reconnect
|
|
11533
|
+
* after a network disruption
|
|
11534
|
+
* @param timeoutSeconds Timeout in seconds, or 0 to keep reconnecting indefinetely
|
|
11535
|
+
*/
|
|
11536
|
+
this.setDisconnectionTimeout = (timeoutSeconds) => {
|
|
11537
|
+
this.disconnectionTimeoutSeconds = timeoutSeconds;
|
|
11538
|
+
};
|
|
11364
11539
|
this.type = type;
|
|
11365
11540
|
this.id = id;
|
|
11366
11541
|
this.cid = `${type}:${id}`;
|
|
@@ -11514,33 +11689,6 @@ class Call {
|
|
|
11514
11689
|
}
|
|
11515
11690
|
}
|
|
11516
11691
|
|
|
11517
|
-
/**
|
|
11518
|
-
* Saving a long-lived reference to a promise that can reject can be unsafe,
|
|
11519
|
-
* since rejecting the promise causes an unhandled rejection error (even if the
|
|
11520
|
-
* rejection is handled everywhere promise result is expected).
|
|
11521
|
-
*
|
|
11522
|
-
* To avoid that, we add both resolution and rejection handlers to the promise.
|
|
11523
|
-
* That way, the saved promise never rejects. A callback is provided as return
|
|
11524
|
-
* value to build a *new* promise, that resolves and rejects along with
|
|
11525
|
-
* the original promise.
|
|
11526
|
-
* @param promise Promise to wrap, which possibly rejects
|
|
11527
|
-
* @returns Callback to build a new promise, which resolves and rejects along
|
|
11528
|
-
* with the original promise
|
|
11529
|
-
*/
|
|
11530
|
-
function makeSafePromise(promise) {
|
|
11531
|
-
let isPending = true;
|
|
11532
|
-
const safePromise = promise
|
|
11533
|
-
.then((result) => ({ status: 'resolved', result }), (error) => ({ status: 'rejected', error }))
|
|
11534
|
-
.finally(() => (isPending = false));
|
|
11535
|
-
const unwrapPromise = () => safePromise.then((fulfillment) => {
|
|
11536
|
-
if (fulfillment.status === 'rejected')
|
|
11537
|
-
throw fulfillment.error;
|
|
11538
|
-
return fulfillment.result;
|
|
11539
|
-
});
|
|
11540
|
-
unwrapPromise.checkPending = () => isPending;
|
|
11541
|
-
return unwrapPromise;
|
|
11542
|
-
}
|
|
11543
|
-
|
|
11544
11692
|
/**
|
|
11545
11693
|
* StableWSConnection - A WS connection that reconnects upon failure.
|
|
11546
11694
|
* - the browser will sometimes report that you're online or offline
|
|
@@ -11793,9 +11941,12 @@ class StableWSConnection {
|
|
|
11793
11941
|
* Schedules a next health check ping for websocket.
|
|
11794
11942
|
*/
|
|
11795
11943
|
this.scheduleNextPing = () => {
|
|
11944
|
+
const timers = getTimers();
|
|
11945
|
+
if (this.healthCheckTimeoutRef) {
|
|
11946
|
+
timers.clearTimeout(this.healthCheckTimeoutRef);
|
|
11947
|
+
}
|
|
11796
11948
|
// 30 seconds is the recommended interval (messenger uses this)
|
|
11797
|
-
|
|
11798
|
-
this.healthCheckTimeoutRef = setTimeout(() => {
|
|
11949
|
+
this.healthCheckTimeoutRef = timers.setTimeout(() => {
|
|
11799
11950
|
// send the healthcheck..., server replies with a health check event
|
|
11800
11951
|
const data = [{ type: 'health.check', client_id: this.client.clientID }];
|
|
11801
11952
|
// try to send on the connection
|
|
@@ -11938,8 +12089,12 @@ class StableWSConnection {
|
|
|
11938
12089
|
this.isConnecting = false;
|
|
11939
12090
|
this.isDisconnected = true;
|
|
11940
12091
|
// start by removing all the listeners
|
|
11941
|
-
|
|
11942
|
-
|
|
12092
|
+
if (this.healthCheckTimeoutRef) {
|
|
12093
|
+
getTimers().clearInterval(this.healthCheckTimeoutRef);
|
|
12094
|
+
}
|
|
12095
|
+
if (this.connectionCheckTimeoutRef) {
|
|
12096
|
+
clearInterval(this.connectionCheckTimeoutRef);
|
|
12097
|
+
}
|
|
11943
12098
|
removeConnectionEventListeners(this.onlineStatusChanged);
|
|
11944
12099
|
this.isHealthy = false;
|
|
11945
12100
|
let isClosedPromise;
|
|
@@ -12639,7 +12794,7 @@ class StreamClient {
|
|
|
12639
12794
|
return await this.wsConnection.connect(this.defaultWSTimeout);
|
|
12640
12795
|
};
|
|
12641
12796
|
this.getUserAgent = () => {
|
|
12642
|
-
const version = "1.11.
|
|
12797
|
+
const version = "1.11.13";
|
|
12643
12798
|
return (this.userAgent ||
|
|
12644
12799
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
12645
12800
|
};
|
|
@@ -13050,10 +13205,14 @@ class StreamVideoClient {
|
|
|
13050
13205
|
if (typeof apiKeyOrArgs === 'string') {
|
|
13051
13206
|
logLevel = opts?.logLevel || logLevel;
|
|
13052
13207
|
logger = opts?.logger || logger;
|
|
13208
|
+
if (opts?.expertimental_enableTimerWorker)
|
|
13209
|
+
enableTimerWorker();
|
|
13053
13210
|
}
|
|
13054
13211
|
else {
|
|
13055
13212
|
logLevel = apiKeyOrArgs.options?.logLevel || logLevel;
|
|
13056
13213
|
logger = apiKeyOrArgs.options?.logger || logger;
|
|
13214
|
+
if (apiKeyOrArgs.options?.expertimental_enableTimerWorker)
|
|
13215
|
+
enableTimerWorker();
|
|
13057
13216
|
}
|
|
13058
13217
|
setLogger(logger, logLevel);
|
|
13059
13218
|
this.logger = getLogger(['client']);
|