@camera.ui/browser 0.1.3 → 0.1.4

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.
Files changed (2) hide show
  1. package/dist/index.js +133 -120
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -545,6 +545,124 @@ function clearMark(lane) {
545
545
  deadMarks.delete(lane);
546
546
  }
547
547
  //#endregion
548
+ //#region src/composables/useTabVisibility.ts
549
+ var DEFAULT_TAB_PAUSE_MS = 3e4;
550
+ var log$2 = new Logger("TabVisibility");
551
+ var _isVisible = ref(typeof document === "undefined" ? true : document.visibilityState === "visible");
552
+ var _hiddenAt = null;
553
+ var _hiddenListeners = /* @__PURE__ */ new Set();
554
+ var _pausedListeners = /* @__PURE__ */ new Set();
555
+ var _visibleListeners = /* @__PURE__ */ new Set();
556
+ var _initialized = false;
557
+ function _firePausedEntry(entry) {
558
+ log$2.debug(`paused listener fired (delay ${entry.delayMs}ms reached)`);
559
+ try {
560
+ entry.cb();
561
+ } catch (err) {
562
+ log$2.error("onTabPaused listener threw:", err);
563
+ }
564
+ }
565
+ function _schedulePausedEntry(entry) {
566
+ log$2.debug(`paused listener scheduled in ${entry.delayMs}ms`);
567
+ entry.timer = setTimeout(() => {
568
+ entry.timer = null;
569
+ if (_isVisible.value) {
570
+ log$2.debug("paused listener skipped — tab visible before delay");
571
+ return;
572
+ }
573
+ _firePausedEntry(entry);
574
+ }, entry.delayMs);
575
+ }
576
+ function _cancelPausedEntries() {
577
+ for (const entry of _pausedListeners) if (entry.timer !== null) {
578
+ clearTimeout(entry.timer);
579
+ entry.timer = null;
580
+ }
581
+ }
582
+ function _init() {
583
+ if (_initialized || typeof document === "undefined") return;
584
+ _initialized = true;
585
+ document.addEventListener("visibilitychange", () => {
586
+ const visible = document.visibilityState === "visible";
587
+ if (!visible && _isVisible.value) {
588
+ _isVisible.value = false;
589
+ _hiddenAt = Date.now();
590
+ log$2.debug(`tab → hidden (hidden=${_hiddenListeners.size} paused=${_pausedListeners.size})`);
591
+ for (const entry of _hiddenListeners) try {
592
+ entry.cb();
593
+ } catch (err) {
594
+ log$2.error("onTabHidden listener threw:", err);
595
+ }
596
+ for (const entry of _pausedListeners) if (entry.delayMs <= 0) _firePausedEntry(entry);
597
+ else _schedulePausedEntry(entry);
598
+ } else if (visible && !_isVisible.value) {
599
+ _cancelPausedEntries();
600
+ const hiddenMs = _hiddenAt != null ? Date.now() - _hiddenAt : 0;
601
+ _hiddenAt = null;
602
+ _isVisible.value = true;
603
+ log$2.debug(`tab → visible (hiddenMs=${hiddenMs}, visible-listeners=${_visibleListeners.size})`);
604
+ for (const { cb } of _visibleListeners) try {
605
+ cb({ hiddenMs });
606
+ } catch (err) {
607
+ log$2.error("onTabVisible listener threw:", err);
608
+ }
609
+ }
610
+ });
611
+ document.addEventListener("freeze", () => {
612
+ for (const entry of _pausedListeners) {
613
+ if (entry.timer === null) continue;
614
+ clearTimeout(entry.timer);
615
+ entry.timer = null;
616
+ _firePausedEntry(entry);
617
+ }
618
+ });
619
+ }
620
+ function useTabVisibility() {
621
+ _init();
622
+ const isVisible = computed(() => _isVisible.value);
623
+ function onTabHidden(cb) {
624
+ const entry = { cb };
625
+ _hiddenListeners.add(entry);
626
+ const off = () => {
627
+ _hiddenListeners.delete(entry);
628
+ };
629
+ tryOnScopeDispose(off);
630
+ return off;
631
+ }
632
+ function onTabPaused(cb, options = {}) {
633
+ const entry = {
634
+ cb,
635
+ delayMs: options.delayMs ?? 3e4,
636
+ timer: null
637
+ };
638
+ _pausedListeners.add(entry);
639
+ const off = () => {
640
+ if (entry.timer !== null) {
641
+ clearTimeout(entry.timer);
642
+ entry.timer = null;
643
+ }
644
+ _pausedListeners.delete(entry);
645
+ };
646
+ tryOnScopeDispose(off);
647
+ return off;
648
+ }
649
+ function onTabVisible(cb) {
650
+ const entry = { cb };
651
+ _visibleListeners.add(entry);
652
+ const off = () => {
653
+ _visibleListeners.delete(entry);
654
+ };
655
+ tryOnScopeDispose(off);
656
+ return off;
657
+ }
658
+ return {
659
+ isVisible,
660
+ onTabHidden,
661
+ onTabPaused,
662
+ onTabVisible
663
+ };
664
+ }
665
+ //#endregion
548
666
  //#region src/composables/useSnapshot.ts
549
667
  var REVOKE_DELAY_MS = 5e3;
550
668
  var SERVER_CLOCK_STEP_MS = 6e4;
@@ -592,6 +710,12 @@ function hookReconnectRefresh(cameraUi, deviceManager) {
592
710
  }, 0);
593
711
  });
594
712
  }
713
+ function isOutdated(settings, fetchedAt) {
714
+ if (!settings || settings.mode === "onDemand") return false;
715
+ if (fetchedAt === void 0) return true;
716
+ const keptMs = (settings.mode === "interval" ? settings.interval : settings.maxAge) * 1e3;
717
+ return Date.now() - fetchedAt > keptMs;
718
+ }
595
719
  function deferRevoke(url) {
596
720
  setTimeout(() => URL.revokeObjectURL(url), REVOKE_DELAY_MS);
597
721
  }
@@ -655,6 +779,7 @@ function useSnapshot(cameraIdOrName) {
655
779
  const cameraUi = useCameraUi();
656
780
  const { isConnected } = cameraUi;
657
781
  const deviceManager = useDeviceManager();
782
+ const { onTabVisible } = useTabVisibility();
658
783
  const snapshot = shallowRef();
659
784
  const _isLoading = ref(false);
660
785
  const initialLoadDone = ref(false);
@@ -790,6 +915,12 @@ function useSnapshot(cameraIdOrName) {
790
915
  snapshot.value = void 0;
791
916
  }
792
917
  }, { immediate: true });
918
+ onTabVisible(() => {
919
+ const id = currentId();
920
+ if (!isConnected.value || !heldDevice || heldDeviceId !== id) return;
921
+ if (!isOutdated(heldDevice.camera.value.snapshotSettings, timestampCache.get(id))) return;
922
+ fetchSnapshotShared(deviceManager, id).catch(() => void 0);
923
+ });
793
924
  tryOnScopeDispose(() => {
794
925
  disposed = true;
795
926
  cancelHoldRetry();
@@ -3223,7 +3354,7 @@ function refreshClientStates() {
3223
3354
  //#endregion
3224
3355
  //#region src/plugin.ts
3225
3356
  var CAMERA_UI_INJECTION_KEY = Symbol("camera-ui");
3226
- var log$2 = new Logger("plugin");
3357
+ var log$1 = new Logger("plugin");
3227
3358
  function isContext(input) {
3228
3359
  return "rpc" in input && "isConnected" in input;
3229
3360
  }
@@ -3258,7 +3389,7 @@ function makeContextFromTransport(input) {
3258
3389
  for (const cb of set) try {
3259
3390
  cb();
3260
3391
  } catch (err) {
3261
- log$2.warn("context listener threw:", err);
3392
+ log$1.warn("context listener threw:", err);
3262
3393
  }
3263
3394
  }
3264
3395
  natsTransport.subscribeClient((next) => {
@@ -3478,124 +3609,6 @@ function createActivityMode(options) {
3478
3609
  };
3479
3610
  }
3480
3611
  //#endregion
3481
- //#region src/composables/useTabVisibility.ts
3482
- var DEFAULT_TAB_PAUSE_MS = 3e4;
3483
- var log$1 = new Logger("TabVisibility");
3484
- var _isVisible = ref(typeof document === "undefined" ? true : document.visibilityState === "visible");
3485
- var _hiddenAt = null;
3486
- var _hiddenListeners = /* @__PURE__ */ new Set();
3487
- var _pausedListeners = /* @__PURE__ */ new Set();
3488
- var _visibleListeners = /* @__PURE__ */ new Set();
3489
- var _initialized = false;
3490
- function _firePausedEntry(entry) {
3491
- log$1.debug(`paused listener fired (delay ${entry.delayMs}ms reached)`);
3492
- try {
3493
- entry.cb();
3494
- } catch (err) {
3495
- log$1.error("onTabPaused listener threw:", err);
3496
- }
3497
- }
3498
- function _schedulePausedEntry(entry) {
3499
- log$1.debug(`paused listener scheduled in ${entry.delayMs}ms`);
3500
- entry.timer = setTimeout(() => {
3501
- entry.timer = null;
3502
- if (_isVisible.value) {
3503
- log$1.debug("paused listener skipped — tab visible before delay");
3504
- return;
3505
- }
3506
- _firePausedEntry(entry);
3507
- }, entry.delayMs);
3508
- }
3509
- function _cancelPausedEntries() {
3510
- for (const entry of _pausedListeners) if (entry.timer !== null) {
3511
- clearTimeout(entry.timer);
3512
- entry.timer = null;
3513
- }
3514
- }
3515
- function _init() {
3516
- if (_initialized || typeof document === "undefined") return;
3517
- _initialized = true;
3518
- document.addEventListener("visibilitychange", () => {
3519
- const visible = document.visibilityState === "visible";
3520
- if (!visible && _isVisible.value) {
3521
- _isVisible.value = false;
3522
- _hiddenAt = Date.now();
3523
- log$1.debug(`tab → hidden (hidden=${_hiddenListeners.size} paused=${_pausedListeners.size})`);
3524
- for (const entry of _hiddenListeners) try {
3525
- entry.cb();
3526
- } catch (err) {
3527
- log$1.error("onTabHidden listener threw:", err);
3528
- }
3529
- for (const entry of _pausedListeners) if (entry.delayMs <= 0) _firePausedEntry(entry);
3530
- else _schedulePausedEntry(entry);
3531
- } else if (visible && !_isVisible.value) {
3532
- _cancelPausedEntries();
3533
- const hiddenMs = _hiddenAt != null ? Date.now() - _hiddenAt : 0;
3534
- _hiddenAt = null;
3535
- _isVisible.value = true;
3536
- log$1.debug(`tab → visible (hiddenMs=${hiddenMs}, visible-listeners=${_visibleListeners.size})`);
3537
- for (const { cb } of _visibleListeners) try {
3538
- cb({ hiddenMs });
3539
- } catch (err) {
3540
- log$1.error("onTabVisible listener threw:", err);
3541
- }
3542
- }
3543
- });
3544
- document.addEventListener("freeze", () => {
3545
- for (const entry of _pausedListeners) {
3546
- if (entry.timer === null) continue;
3547
- clearTimeout(entry.timer);
3548
- entry.timer = null;
3549
- _firePausedEntry(entry);
3550
- }
3551
- });
3552
- }
3553
- function useTabVisibility() {
3554
- _init();
3555
- const isVisible = computed(() => _isVisible.value);
3556
- function onTabHidden(cb) {
3557
- const entry = { cb };
3558
- _hiddenListeners.add(entry);
3559
- const off = () => {
3560
- _hiddenListeners.delete(entry);
3561
- };
3562
- tryOnScopeDispose(off);
3563
- return off;
3564
- }
3565
- function onTabPaused(cb, options = {}) {
3566
- const entry = {
3567
- cb,
3568
- delayMs: options.delayMs ?? 3e4,
3569
- timer: null
3570
- };
3571
- _pausedListeners.add(entry);
3572
- const off = () => {
3573
- if (entry.timer !== null) {
3574
- clearTimeout(entry.timer);
3575
- entry.timer = null;
3576
- }
3577
- _pausedListeners.delete(entry);
3578
- };
3579
- tryOnScopeDispose(off);
3580
- return off;
3581
- }
3582
- function onTabVisible(cb) {
3583
- const entry = { cb };
3584
- _visibleListeners.add(entry);
3585
- const off = () => {
3586
- _visibleListeners.delete(entry);
3587
- };
3588
- tryOnScopeDispose(off);
3589
- return off;
3590
- }
3591
- return {
3592
- isVisible,
3593
- onTabHidden,
3594
- onTabPaused,
3595
- onTabVisible
3596
- };
3597
- }
3598
- //#endregion
3599
3612
  //#region src/streaming/config.ts
3600
3613
  var STREAM_CONFIG = {
3601
3614
  WEBRTC: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camera.ui/browser",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "camera.ui browser client",
5
5
  "author": "seydx (https://github.com/cameraui/clients)",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  "devDependencies": {
40
40
  "@camera.ui/logger": "file:../../packages/logger",
41
41
  "@camera.ui/rpc": "^1.1.1",
42
- "@camera.ui/sdk": "~1.4.3",
42
+ "@camera.ui/sdk": "~1.4.4",
43
43
  "@camera.ui/transport": "file:../../packages/transport",
44
44
  "@eneris/push-receiver": "^4.4.0",
45
45
  "@microsoft/api-extractor": "^7.59.4",