@stream-io/video-client 1.11.12 → 1.11.14

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 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.14](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.13...@stream-io/video-client-1.11.14) (2024-12-04)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * prevent device list observable from erroring ([#1608](https://github.com/GetStream/stream-video-js/issues/1608)) ([06af3e7](https://github.com/GetStream/stream-video-js/commit/06af3e7e03b63551c781512c797ac10c0486d0c7))
11
+
12
+ ## [1.11.13](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.12...@stream-io/video-client-1.11.13) (2024-12-03)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * use worker to prevent timer throttling ([#1557](https://github.com/GetStream/stream-video-js/issues/1557)) ([c11c3ca](https://github.com/GetStream/stream-video-js/commit/c11c3caf455787fe531c83601bad71e7a0a0e9b9))
18
+
5
19
  ## [1.11.12](https://github.com/GetStream/stream-video-js/compare/@stream-io/video-client-1.11.11...@stream-io/video-client-1.11.12) (2024-12-03)
6
20
 
7
21
 
@@ -3297,7 +3297,7 @@ const retryable = async (rpc, signal) => {
3297
3297
  return result;
3298
3298
  };
3299
3299
 
3300
- const version = "1.11.12";
3300
+ const version = "1.11.14";
3301
3301
  const [major, minor, patch] = version.split('.');
3302
3302
  let sdkInfo = {
3303
3303
  type: SdkType.PLAIN_JAVASCRIPT,
@@ -6432,6 +6432,151 @@ const promiseWithResolvers = () => {
6432
6432
  };
6433
6433
  };
6434
6434
 
6435
+ const uninitialized = Symbol('uninitialized');
6436
+ /**
6437
+ * Lazily creates a value using a provided factory
6438
+ */
6439
+ function lazy(factory) {
6440
+ let value = uninitialized;
6441
+ return () => {
6442
+ if (value === uninitialized) {
6443
+ value = factory();
6444
+ }
6445
+ return value;
6446
+ };
6447
+ }
6448
+
6449
+ const timerWorker = {
6450
+ src: `var timerIdMapping = new Map();
6451
+ self.addEventListener('message', function (event) {
6452
+ var request = event.data;
6453
+ switch (request.type) {
6454
+ case 'setTimeout':
6455
+ case 'setInterval':
6456
+ timerIdMapping.set(request.id, (request.type === 'setTimeout' ? setTimeout : setInterval)(function () {
6457
+ tick(request.id);
6458
+ if (request.type === 'setTimeout') {
6459
+ timerIdMapping.delete(request.id);
6460
+ }
6461
+ }, request.timeout));
6462
+ break;
6463
+ case 'clearTimeout':
6464
+ case 'clearInterval':
6465
+ (request.type === 'clearTimeout' ? clearTimeout : clearInterval)(timerIdMapping.get(request.id));
6466
+ timerIdMapping.delete(request.id);
6467
+ break;
6468
+ }
6469
+ });
6470
+ function tick(id) {
6471
+ var message = { type: 'tick', id: id };
6472
+ self.postMessage(message);
6473
+ }`,
6474
+ };
6475
+
6476
+ class TimerWorker {
6477
+ constructor() {
6478
+ this.currentTimerId = 1;
6479
+ this.callbacks = new Map();
6480
+ this.fallback = false;
6481
+ }
6482
+ setup({ useTimerWorker = true } = {}) {
6483
+ if (!useTimerWorker) {
6484
+ this.fallback = true;
6485
+ return;
6486
+ }
6487
+ try {
6488
+ const source = timerWorker.src;
6489
+ const blob = new Blob([source], {
6490
+ type: 'application/javascript; charset=utf-8',
6491
+ });
6492
+ const script = URL.createObjectURL(blob);
6493
+ this.worker = new Worker(script, { name: 'str-timer-worker' });
6494
+ this.worker.addEventListener('message', (event) => {
6495
+ const { type, id } = event.data;
6496
+ if (type === 'tick') {
6497
+ this.callbacks.get(id)?.();
6498
+ }
6499
+ });
6500
+ }
6501
+ catch (err) {
6502
+ getLogger(['timer-worker'])('error', err);
6503
+ this.fallback = true;
6504
+ }
6505
+ }
6506
+ destroy() {
6507
+ this.callbacks.clear();
6508
+ this.worker?.terminate();
6509
+ this.worker = undefined;
6510
+ this.fallback = false;
6511
+ }
6512
+ get ready() {
6513
+ return this.fallback || Boolean(this.worker);
6514
+ }
6515
+ setInterval(callback, timeout) {
6516
+ return this.setTimer('setInterval', callback, timeout);
6517
+ }
6518
+ clearInterval(id) {
6519
+ this.clearTimer('clearInterval', id);
6520
+ }
6521
+ setTimeout(callback, timeout) {
6522
+ return this.setTimer('setTimeout', callback, timeout);
6523
+ }
6524
+ clearTimeout(id) {
6525
+ this.clearTimer('clearTimeout', id);
6526
+ }
6527
+ setTimer(type, callback, timeout) {
6528
+ if (!this.ready) {
6529
+ this.setup();
6530
+ }
6531
+ if (this.fallback) {
6532
+ return (type === 'setTimeout' ? setTimeout : setInterval)(callback, timeout);
6533
+ }
6534
+ const id = this.getTimerId();
6535
+ this.callbacks.set(id, () => {
6536
+ callback();
6537
+ // Timeouts are one-off operations, so no need to keep callback reference
6538
+ // after timer has fired
6539
+ if (type === 'setTimeout') {
6540
+ this.callbacks.delete(id);
6541
+ }
6542
+ });
6543
+ this.sendMessage({ type, id, timeout });
6544
+ return id;
6545
+ }
6546
+ clearTimer(type, id) {
6547
+ if (!id) {
6548
+ return;
6549
+ }
6550
+ if (!this.ready) {
6551
+ this.setup();
6552
+ }
6553
+ if (this.fallback) {
6554
+ (type === 'clearTimeout' ? clearTimeout : clearInterval)(id);
6555
+ return;
6556
+ }
6557
+ this.callbacks.delete(id);
6558
+ this.sendMessage({ type, id });
6559
+ }
6560
+ getTimerId() {
6561
+ return this.currentTimerId++;
6562
+ }
6563
+ sendMessage(message) {
6564
+ if (!this.worker) {
6565
+ throw new Error("Cannot use timer worker before it's set up");
6566
+ }
6567
+ this.worker.postMessage(message);
6568
+ }
6569
+ }
6570
+ let timerWorkerEnabled = false;
6571
+ const enableTimerWorker = () => {
6572
+ timerWorkerEnabled = true;
6573
+ };
6574
+ const getTimers = lazy(() => {
6575
+ const instance = new TimerWorker();
6576
+ instance.setup({ useTimerWorker: timerWorkerEnabled });
6577
+ return instance;
6578
+ });
6579
+
6435
6580
  /**
6436
6581
  * The client used for exchanging information with the SFU.
6437
6582
  */
@@ -6490,7 +6635,7 @@ class StreamSfuClient {
6490
6635
  };
6491
6636
  this.handleWebSocketClose = () => {
6492
6637
  this.signalWs.removeEventListener('close', this.handleWebSocketClose);
6493
- clearInterval(this.keepAliveInterval);
6638
+ getTimers().clearInterval(this.keepAliveInterval);
6494
6639
  clearTimeout(this.connectionCheckTimeout);
6495
6640
  this.onSignalClose?.();
6496
6641
  };
@@ -6646,8 +6791,9 @@ class StreamSfuClient {
6646
6791
  this.signalWs.send(SfuRequest.toBinary(message));
6647
6792
  };
6648
6793
  this.keepAlive = () => {
6649
- clearInterval(this.keepAliveInterval);
6650
- this.keepAliveInterval = setInterval(() => {
6794
+ const timers = getTimers();
6795
+ timers.clearInterval(this.keepAliveInterval);
6796
+ this.keepAliveInterval = timers.setInterval(() => {
6651
6797
  this.ping().catch((e) => {
6652
6798
  this.logger('error', 'Error sending healthCheckRequest to SFU', e);
6653
6799
  });
@@ -8166,7 +8312,7 @@ class BrowserPermission {
8166
8312
  return this.state;
8167
8313
  }
8168
8314
  async prompt({ forcePrompt = false, throwOnNotAllowed = false, } = {}) {
8169
- await withoutConcurrency(`permission-prompt-${this.permission.queryName}`, async () => {
8315
+ return await withoutConcurrency(`permission-prompt-${this.permission.queryName}`, async () => {
8170
8316
  if ((await this.getState()) !== 'prompt' ||
8171
8317
  (this.wasPrompted && !forcePrompt)) {
8172
8318
  const isGranted = this.state === 'granted';
@@ -8228,20 +8374,6 @@ function canQueryPermissions() {
8228
8374
  !!navigator.permissions?.query);
8229
8375
  }
8230
8376
 
8231
- const uninitialized = Symbol('uninitialized');
8232
- /**
8233
- * Lazily creates a value using a provided factory
8234
- */
8235
- function lazy(factory) {
8236
- let value = uninitialized;
8237
- return () => {
8238
- if (value === uninitialized) {
8239
- value = factory();
8240
- }
8241
- return value;
8242
- };
8243
- }
8244
-
8245
8377
  /**
8246
8378
  * Returns an Observable that emits the list of available devices
8247
8379
  * that meet the given constraints.
@@ -8255,8 +8387,7 @@ const getDevices = (permission, kind) => {
8255
8387
  // for privacy reasons, most browsers don't give you device labels
8256
8388
  // unless you have a corresponding camera or microphone permission
8257
8389
  const shouldPromptForBrowserPermission = devices.some((device) => device.kind === kind && device.label === '');
8258
- if (shouldPromptForBrowserPermission) {
8259
- await permission.prompt({ throwOnNotAllowed: true });
8390
+ if (shouldPromptForBrowserPermission && (await permission.prompt())) {
8260
8391
  devices = await navigator.mediaDevices.enumerateDevices();
8261
8392
  }
8262
8393
  return devices.filter((device) => device.kind === kind &&
@@ -11790,9 +11921,12 @@ class StableWSConnection {
11790
11921
  * Schedules a next health check ping for websocket.
11791
11922
  */
11792
11923
  this.scheduleNextPing = () => {
11924
+ const timers = getTimers();
11925
+ if (this.healthCheckTimeoutRef) {
11926
+ timers.clearTimeout(this.healthCheckTimeoutRef);
11927
+ }
11793
11928
  // 30 seconds is the recommended interval (messenger uses this)
11794
- clearTimeout(this.healthCheckTimeoutRef);
11795
- this.healthCheckTimeoutRef = setTimeout(() => {
11929
+ this.healthCheckTimeoutRef = timers.setTimeout(() => {
11796
11930
  // send the healthcheck..., server replies with a health check event
11797
11931
  const data = [{ type: 'health.check', client_id: this.client.clientID }];
11798
11932
  // try to send on the connection
@@ -11935,8 +12069,12 @@ class StableWSConnection {
11935
12069
  this.isConnecting = false;
11936
12070
  this.isDisconnected = true;
11937
12071
  // start by removing all the listeners
11938
- clearInterval(this.healthCheckTimeoutRef);
11939
- clearInterval(this.connectionCheckTimeoutRef);
12072
+ if (this.healthCheckTimeoutRef) {
12073
+ getTimers().clearInterval(this.healthCheckTimeoutRef);
12074
+ }
12075
+ if (this.connectionCheckTimeoutRef) {
12076
+ clearInterval(this.connectionCheckTimeoutRef);
12077
+ }
11940
12078
  removeConnectionEventListeners(this.onlineStatusChanged);
11941
12079
  this.isHealthy = false;
11942
12080
  let isClosedPromise;
@@ -12636,7 +12774,7 @@ class StreamClient {
12636
12774
  return await this.wsConnection.connect(this.defaultWSTimeout);
12637
12775
  };
12638
12776
  this.getUserAgent = () => {
12639
- const version = "1.11.12";
12777
+ const version = "1.11.14";
12640
12778
  return (this.userAgent ||
12641
12779
  `stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
12642
12780
  };
@@ -13047,10 +13185,14 @@ class StreamVideoClient {
13047
13185
  if (typeof apiKeyOrArgs === 'string') {
13048
13186
  logLevel = opts?.logLevel || logLevel;
13049
13187
  logger = opts?.logger || logger;
13188
+ if (opts?.expertimental_enableTimerWorker)
13189
+ enableTimerWorker();
13050
13190
  }
13051
13191
  else {
13052
13192
  logLevel = apiKeyOrArgs.options?.logLevel || logLevel;
13053
13193
  logger = apiKeyOrArgs.options?.logger || logger;
13194
+ if (apiKeyOrArgs.options?.expertimental_enableTimerWorker)
13195
+ enableTimerWorker();
13054
13196
  }
13055
13197
  setLogger(logger, logLevel);
13056
13198
  this.logger = getLogger(['client']);