@camera.ui/browser 0.0.146 → 0.0.148

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 (3) hide show
  1. package/dist/index.d.ts +89 -43
  2. package/dist/index.js +352 -143
  3. package/package.json +7 -7
package/dist/index.d.ts CHANGED
@@ -86,7 +86,7 @@ import { TemperatureProperty } from '@camera.ui/sdk';
86
86
  import { WatchSource } from 'vue';
87
87
  import { WsTransport } from '@camera.ui/transport/transports/ws';
88
88
 
89
- export declare function acquireSensorManager(cameraId: string, rpcOrContext: RPCClient | ReactiveCameraDeviceContext): CachedSensorManager;
89
+ export declare function acquireSensorManager(rpcOrContext: RPCClient | ReactiveCameraDeviceContext): CachedSensorManager;
90
90
 
91
91
  export declare interface ActivityMode extends ActivityModeState, ActivityModeActions {
92
92
  }
@@ -163,6 +163,8 @@ export declare interface CameraStream {
163
163
  readonly isPlaying: Ref<boolean>;
164
164
  readonly activeMode: Ref<'webrtc' | 'webrtc/tcp' | 'mse'>;
165
165
  readonly activeResolution: Ref<StreamingRole>;
166
+ readonly degradedFrom: Ref<StreamingRole | null>;
167
+ readonly unsupported: Ref<boolean>;
166
168
  readonly hasAudio: Ref<boolean>;
167
169
  readonly hasBackchannel: Ref<boolean>;
168
170
  readonly error: Ref<Error | undefined>;
@@ -286,7 +288,7 @@ export declare function createCameraUiPlugin(input: CameraUiContext | CameraUiPl
286
288
 
287
289
  export declare function createReactiveCameraDevice(rpcOrContext: RPCClient | ReactiveCameraDeviceContext, initialCamera: Camera): Promise<ReactiveCameraDevice>;
288
290
 
289
- export declare function createSensorManager(rpcOrContext: RPCClient | ReactiveCameraDeviceContext, cameraId: string, sensorSubjectNamespace: string, sensorRpcNamespace: string): ReactiveSensorManager;
291
+ export declare function createSensorManager(rpcOrContext: RPCClient | ReactiveCameraDeviceContext): ReactiveSensorManager;
290
292
 
291
293
  declare interface DBCamera extends BaseCamera {
292
294
  sources: CameraInputSettings[];
@@ -392,6 +394,12 @@ export declare const isReactiveTemperatureInfo: (sensor: ReactiveSensor<any>) =>
392
394
 
393
395
  /* Excluded from this release type: LeakSensorProperties */
394
396
 
397
+ /** @deprecated stub window for pre-standalone plugins, remove in the first minor after the standalone-sensors release */
398
+ declare interface LegacySensorNamespaces {
399
+ sensorSubject: string;
400
+ sensorRpc: string;
401
+ }
402
+
395
403
  /* Excluded from this release type: LicensePlateProperty */
396
404
 
397
405
  /* Excluded from this release type: LicensePlateSensorProperties */
@@ -466,29 +474,42 @@ export declare class NamespaceManager {
466
474
  };
467
475
  }
468
476
 
469
- static pluginSensorNamespaces(pluginId: string, cameraId: string, sensorId: string): PluginSensorNamespaces {
477
+ static pluginSensorNamespaces(pluginId: string, sensorId: string): PluginSensorNamespaces {
470
478
  return {
471
- sensorStorageRpc: `plugin.${pluginId}.camera.${cameraId}.sensor.${sensorId}.storage.rpc`,
479
+ sensorStorageRpc: `plugin.${pluginId}.sensor.${sensorId}.storage.rpc`,
472
480
  };
473
481
  }
474
482
 
475
- static sensorControllerNamespaces(cameraId: string): SensorControllerNamespaces {
483
+ static sensorRegistryNamespaces(): SensorRegistryNamespaces {
484
+ return {
485
+ sensorsSubject: 'sensors.subject',
486
+ sensorsRpc: 'sensors.rpc',
487
+ };
488
+ }
489
+
490
+ static sensorCameraViewNamespaces(cameraId: string): SensorCameraViewNamespaces {
476
491
  return {
477
- sensorSubject: `camera.${cameraId}.sensors.subject`,
478
- sensorRpc: `camera.${cameraId}.sensors.rpc`,
479
492
  sensorWriteSubject: `camera.${cameraId}.sensors.writes`,
480
493
  };
481
494
  }
482
495
 
483
- static sensorEventNamespaces(cameraId: string, sensorId: string): SensorEventNamespaces {
496
+ static sensorEventNamespaces(sensorId: string): SensorEventNamespaces {
484
497
  return {
485
- sensorSubject: `camera.${cameraId}.sensor.${sensorId}.subject`,
498
+ sensorSubject: `sensor.${sensorId}.subject`,
486
499
  };
487
500
  }
488
501
 
489
- static sensorProviderNamespaces(pluginId: string, cameraId: string, sensorId: string): SensorProviderNamespaces {
502
+ static sensorProviderNamespaces(pluginId: string, sensorId: string): SensorProviderNamespaces {
490
503
  return {
491
- sensorRpc: `plugin.${pluginId}.camera.${cameraId}.sensor.${sensorId}.rpc`,
504
+ sensorRpc: `plugin.${pluginId}.sensor.${sensorId}.rpc`,
505
+ };
506
+ }
507
+
508
+ /** @deprecated stub window for pre-standalone plugins, remove in the first minor after the standalone-sensors release */
509
+ static legacySensorNamespaces(cameraId: string): LegacySensorNamespaces {
510
+ return {
511
+ sensorSubject: `camera.${cameraId}.sensors.subject`,
512
+ sensorRpc: `camera.${cameraId}.sensors.rpc`,
492
513
  };
493
514
  }
494
515
 
@@ -504,10 +525,6 @@ export declare class NamespaceManager {
504
525
  };
505
526
  }
506
527
 
507
- static sensorControllerRpc(cameraId: string): string {
508
- return `camera.${cameraId}.sensors.controller.rpc`;
509
- }
510
-
511
528
  static terminalManagerNamespaces(): TerminalManagerNamespaces {
512
529
  return {
513
530
  terminalManagerSubject: 'terminalManager.subscriber',
@@ -782,7 +799,11 @@ export declare interface ReactiveSensor<TProperties extends object = Record<stri
782
799
  readonly type: SensorType;
783
800
  readonly name: string;
784
801
  readonly displayName: Ref<string>;
802
+ readonly nativeId?: string;
785
803
  readonly pluginId: string;
804
+ readonly assignedCameraIds: Ref<string[]>;
805
+ readonly exposed: Ref<boolean>;
806
+ readonly connected: Ref<boolean>;
786
807
  readonly capabilities: Ref<string[]>;
787
808
  readonly properties: TProperties;
788
809
  getProperty<T = unknown>(property: string): T | undefined;
@@ -837,6 +858,8 @@ export declare interface ReactiveStream {
837
858
  readonly requestedMode: Ref<VideoStreamingMode>;
838
859
  readonly activeResolution: Ref<StreamingRole>;
839
860
  readonly requestedResolution: Ref<StreamingRole>;
861
+ readonly degradedFrom: Ref<StreamingRole | null>;
862
+ readonly degradeReason: Ref<StreamDegradeReason | null>;
840
863
  readonly source: Ref<CameraSource | undefined>;
841
864
  readonly hasVideo: Ref<boolean>;
842
865
  readonly hasAudio: Ref<boolean>;
@@ -882,7 +905,7 @@ declare interface RefreshedStates {
882
905
  sensorStates: Record<string, SensorRefreshedState>;
883
906
  }
884
907
 
885
- export declare function releaseSensorManager(cameraId: string): void;
908
+ export declare function releaseSensorManager(): void;
886
909
 
887
910
  export declare function resetClientState(): void;
888
911
 
@@ -904,50 +927,57 @@ export { RPCClient }
904
927
  /* Excluded from this release type: SecuritySystemProperty */
905
928
 
906
929
  declare interface SensorAddedEvent {
907
- cameraId: string;
908
930
  sensor: StoredSensorData;
909
931
  state: SensorRefreshedState;
910
932
  }
911
933
 
912
- declare interface SensorCapabilitiesChangedEvent {
934
+ declare interface SensorAssignmentChangedEvent {
935
+ sensorId: string;
936
+ sensorType: SensorType;
913
937
  cameraId: string;
938
+ assigned: boolean;
939
+ }
940
+
941
+ export declare interface SensorCameraViewNamespaces {
942
+ sensorWriteSubject: string;
943
+ }
944
+
945
+ declare interface SensorCapabilitiesChangedEvent {
914
946
  sensorId: string;
915
947
  capabilities: string[];
916
948
  }
917
949
 
918
- export declare interface SensorControllerNamespaces {
919
- sensorSubject: string;
920
- sensorRpc: string;
921
- sensorWriteSubject: string;
950
+ declare interface SensorConnectedChangedEvent {
951
+ sensorId: string;
952
+ sensorType: SensorType;
953
+ connected: boolean;
922
954
  }
923
955
 
924
- export declare interface SensorControllerRPC {
925
- getSensors(): StoredSensorData[];
926
- getSensor(sensorId: string): StoredSensorData | undefined;
927
- getSensorByType(sensorType: SensorType): StoredSensorData | undefined;
928
- getSensorsByType(sensorType: SensorType): StoredSensorData[];
929
- getSensorState(sensorId: string): SensorRefreshedState;
930
- getSensorStates(): Record<string, SensorRefreshedState>;
931
- getPropertyValue(sensorId: string, property: string): unknown;
932
- getAllPropertyValues(sensorId: string): Record<string, unknown>;
933
- setDisplayName(sensorId: string, displayName: string): void;
956
+ declare interface SensorDeletedEvent {
957
+ sensorId: string;
958
+ sensorType: SensorType;
934
959
  }
935
960
 
936
961
  declare interface SensorDisplayNameChangedEvent {
937
- cameraId: string;
938
962
  sensorId: string;
939
963
  displayName: string;
940
964
  }
941
965
 
942
966
  export declare interface SensorEventMessage {
943
- type: 'property:changed' | 'sensor:added' | 'sensor:removed' | 'sensor:displayName:changed' | 'sensor:capabilities:changed';
944
- data: PropertyChangedEvent | SensorAddedEvent | SensorRemovedEvent | SensorDisplayNameChangedEvent | SensorCapabilitiesChangedEvent;
967
+ type: 'property:changed' | 'sensor:added' | 'sensor:deleted' | 'sensor:connected:changed' | 'sensor:displayName:changed' | 'sensor:capabilities:changed' | 'sensor:assignment:changed' | 'sensor:exposed:changed';
968
+ data: PropertyChangedEvent | SensorAddedEvent | SensorDeletedEvent | SensorConnectedChangedEvent | SensorDisplayNameChangedEvent | SensorCapabilitiesChangedEvent | SensorAssignmentChangedEvent | SensorExposedChangedEvent;
945
969
  }
946
970
 
947
971
  export declare interface SensorEventNamespaces {
948
972
  sensorSubject: string;
949
973
  }
950
974
 
975
+ declare interface SensorExposedChangedEvent {
976
+ sensorId: string;
977
+ sensorType: SensorType;
978
+ exposed: boolean;
979
+ }
980
+
951
981
  export declare interface SensorProviderNamespaces {
952
982
  sensorRpc: string;
953
983
  }
@@ -959,10 +989,19 @@ export declare interface SensorRefreshedState {
959
989
  displayName?: string;
960
990
  }
961
991
 
962
- declare interface SensorRemovedEvent {
963
- cameraId: string;
964
- sensorId: string;
965
- sensorType: SensorType;
992
+ export declare interface SensorRegistryNamespaces {
993
+ sensorsSubject: string;
994
+ sensorsRpc: string;
995
+ }
996
+
997
+ export declare interface SensorRegistryRPC {
998
+ getSensors(): StoredSensorData[];
999
+ getSensorRpc(sensorId: string): StoredSensorData | undefined;
1000
+ getSensorState(sensorId: string): SensorRefreshedState;
1001
+ getSensorStates(): Record<string, SensorRefreshedState>;
1002
+ getPropertyValue(sensorId: string, property: string): unknown;
1003
+ getAllPropertyValues(sensorId: string): Record<string, unknown>;
1004
+ setDisplayName(sensorId: string, displayName: string): void;
966
1005
  }
967
1006
 
968
1007
  /* Excluded from this release type: SirenControlProperties */
@@ -991,12 +1030,15 @@ export declare interface StorageRPC {
991
1030
 
992
1031
  export declare interface StoredSensorData {
993
1032
  id: string;
994
- stableId: string;
995
- globalId: string;
996
1033
  type: SensorType;
997
1034
  name: string;
998
1035
  displayName: string;
1036
+ nativeId?: string;
999
1037
  pluginId: string;
1038
+ assignedCameraIds: string[];
1039
+ boundCameraId?: string;
1040
+ exposed: boolean;
1041
+ connected: boolean;
1000
1042
  properties: Record<string, unknown>;
1001
1043
  capabilities: string[];
1002
1044
  requiresFrames?: boolean;
@@ -1023,6 +1065,8 @@ export declare const STREAM_CONFIG: {
1023
1065
  };
1024
1066
  };
1025
1067
 
1068
+ declare type StreamDegradeReason = 'codec';
1069
+
1026
1070
  export declare interface StreamOptions {
1027
1071
  camera: MaybeRefOrGetter<ReactiveCameraDevice | undefined>;
1028
1072
  videoElement: MaybeRefOrGetter<HTMLVideoElement | undefined | null>;
@@ -1034,7 +1078,7 @@ export declare interface StreamOptions {
1034
1078
  webrtcConnectTimeout?: number;
1035
1079
  }
1036
1080
 
1037
- export declare type StreamStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error' | 'closed';
1081
+ export declare type StreamStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'error' | 'unsupported' | 'closed';
1038
1082
 
1039
1083
  /* Excluded from this release type: SwitchControlProperties */
1040
1084
 
@@ -1071,6 +1115,8 @@ export declare interface TerminalSessionInfo {
1071
1115
  dimensions: { cols: number; rows: number };
1072
1116
  }
1073
1117
 
1118
+ export declare function useAllSensors(): UseSensorsReturn;
1119
+
1074
1120
  export declare function useAudioSensor(camera: CameraIdentifier): UseSensorTypedReturn<ReactiveAudioSensor>;
1075
1121
 
1076
1122
  export declare function useCameraById(cameraIdOrName: MaybeRefOrGetter<string>): UseCameraByIdReturn;
@@ -1206,7 +1252,7 @@ export declare interface UseSensorsReturn {
1206
1252
  error: Ref<Error | undefined>;
1207
1253
  }
1208
1254
 
1209
- export declare function useSensorStorage(camera: CameraIdentifier, sensorId: MaybeRefOrGetter<string | undefined>, pluginId: MaybeRefOrGetter<string | undefined>): UseStorageReturn;
1255
+ export declare function useSensorStorage(sensorId: MaybeRefOrGetter<string | undefined>, pluginId: MaybeRefOrGetter<string | undefined>): UseStorageReturn;
1210
1256
 
1211
1257
  export declare interface UseSensorsTypedReturn<T extends ReactiveSensor<any> = ReactiveSensor> {
1212
1258
  sensors: ComputedRef<T[]>;
package/dist/index.js CHANGED
@@ -149,21 +149,30 @@ var NamespaceManager = class {
149
149
  cameraImplRpc: `plugin.${pluginId}.camera.${cameraId}.impl.rpc`
150
150
  };
151
151
  }
152
- static pluginSensorNamespaces(pluginId, cameraId, sensorId) {
153
- return { sensorStorageRpc: `plugin.${pluginId}.camera.${cameraId}.sensor.${sensorId}.storage.rpc` };
152
+ static pluginSensorNamespaces(pluginId, sensorId) {
153
+ return { sensorStorageRpc: `plugin.${pluginId}.sensor.${sensorId}.storage.rpc` };
154
154
  }
155
- static sensorControllerNamespaces(cameraId) {
155
+ static sensorRegistryNamespaces() {
156
156
  return {
157
- sensorSubject: `camera.${cameraId}.sensors.subject`,
158
- sensorRpc: `camera.${cameraId}.sensors.rpc`,
159
- sensorWriteSubject: `camera.${cameraId}.sensors.writes`
157
+ sensorsSubject: "sensors.subject",
158
+ sensorsRpc: "sensors.rpc"
160
159
  };
161
160
  }
162
- static sensorEventNamespaces(cameraId, sensorId) {
163
- return { sensorSubject: `camera.${cameraId}.sensor.${sensorId}.subject` };
161
+ static sensorCameraViewNamespaces(cameraId) {
162
+ return { sensorWriteSubject: `camera.${cameraId}.sensors.writes` };
163
+ }
164
+ static sensorEventNamespaces(sensorId) {
165
+ return { sensorSubject: `sensor.${sensorId}.subject` };
164
166
  }
165
- static sensorProviderNamespaces(pluginId, cameraId, sensorId) {
166
- return { sensorRpc: `plugin.${pluginId}.camera.${cameraId}.sensor.${sensorId}.rpc` };
167
+ static sensorProviderNamespaces(pluginId, sensorId) {
168
+ return { sensorRpc: `plugin.${pluginId}.sensor.${sensorId}.rpc` };
169
+ }
170
+ /** @deprecated stub window for pre-standalone plugins, remove in the first minor after the standalone-sensors release */
171
+ static legacySensorNamespaces(cameraId) {
172
+ return {
173
+ sensorSubject: `camera.${cameraId}.sensors.subject`,
174
+ sensorRpc: `camera.${cameraId}.sensors.rpc`
175
+ };
167
176
  }
168
177
  static frameWorkerDetectionNamespaces(cameraId) {
169
178
  return { detectionRpc: `camera.${cameraId}.frameWorker.detection.rpc` };
@@ -171,9 +180,6 @@ var NamespaceManager = class {
171
180
  static detectionEventNamespaces(cameraId) {
172
181
  return { detectionEventSubject: `camera.${cameraId}.events.subject` };
173
182
  }
174
- static sensorControllerRpc(cameraId) {
175
- return `camera.${cameraId}.sensors.controller.rpc`;
176
- }
177
183
  static terminalManagerNamespaces() {
178
184
  return {
179
185
  terminalManagerSubject: "terminalManager.subscriber",
@@ -602,7 +608,7 @@ function useSnapshot(cameraIdOrName) {
602
608
  //#region src/composables/useCamera.ts
603
609
  async function createReactiveCameraDevice(rpcOrContext, initialCamera) {
604
610
  const cameraNamespaces = NamespaceManager.cameraNamespaces(initialCamera._id);
605
- const sensorNamespaces = NamespaceManager.sensorControllerNamespaces(initialCamera._id);
611
+ const sensorNamespaces = NamespaceManager.sensorRegistryNamespaces();
606
612
  const ctx = "rpc" in rpcOrContext && "value" in rpcOrContext.rpc ? rpcOrContext : void 0;
607
613
  const rpcRef = ctx ? ctx.rpc : shallowRef(rpcOrContext);
608
614
  let closeSubscription;
@@ -696,30 +702,47 @@ async function createReactiveCameraDevice(rpcOrContext, initialCamera) {
696
702
  case "frameWorkerState":
697
703
  frameWorkerConnected.value = event.data;
698
704
  break;
699
- case "snapshot:updated":
700
- setSnapshot(initialCamera._id, event.data.snapshot, Date.now());
701
- break;
705
+ case "snapshot:updated": setSnapshot(initialCamera._id, event.data.snapshot, Date.now());
702
706
  }
703
707
  }
704
708
  function handleSensorEvent(event) {
705
709
  if (event.type === "sensor:added") {
706
710
  const addedEvent = event.data;
711
+ if (!addedEvent.sensor.assignedCameraIds.includes(initialCamera._id)) return;
712
+ if (!addedEvent.sensor.connected) return;
707
713
  sensorStates.value = {
708
714
  ...sensorStates.value,
709
715
  [addedEvent.sensor.id]: addedEvent.state
710
716
  };
711
- } else if (event.type === "sensor:removed") {
712
- const removedEvent = event.data;
717
+ } else if (event.type === "sensor:deleted") {
718
+ const deletedEvent = event.data;
713
719
  const newStates = { ...sensorStates.value };
714
- delete newStates[removedEvent.sensorId];
720
+ delete newStates[deletedEvent.sensorId];
715
721
  sensorStates.value = newStates;
722
+ } else if (event.type === "sensor:connected:changed") {
723
+ const connectedEvent = event.data;
724
+ if (connectedEvent.connected) refreshStates().catch(() => {});
725
+ else {
726
+ const newStates = { ...sensorStates.value };
727
+ delete newStates[connectedEvent.sensorId];
728
+ sensorStates.value = newStates;
729
+ }
730
+ } else if (event.type === "sensor:assignment:changed") {
731
+ const assignmentEvent = event.data;
732
+ if (assignmentEvent.cameraId !== initialCamera._id) return;
733
+ if (assignmentEvent.assigned) refreshStates().catch(() => {});
734
+ else {
735
+ const newStates = { ...sensorStates.value };
736
+ delete newStates[assignmentEvent.sensorId];
737
+ sensorStates.value = newStates;
738
+ }
716
739
  }
717
740
  }
718
741
  async function init() {
719
742
  closeSubscription?.();
720
743
  closeSensorSubscription?.();
721
744
  closeSubscription = await rpcCall(rpcRef, (client) => client.subscribe(cameraNamespaces.cameraSubject, handleCameraEvent));
722
- closeSensorSubscription = await rpcCall(rpcRef, (client) => client.subscribe(sensorNamespaces.sensorSubject, handleSensorEvent));
745
+ closeSensorSubscription = await rpcCall(rpcRef, (client) => client.subscribe(sensorNamespaces.sensorsSubject, handleSensorEvent));
723
746
  await refreshStates();
724
747
  }
725
748
  async function close() {
@@ -1112,9 +1135,12 @@ var isReactiveOccupancySensor = createSensorTypeGuard(SensorType.Occupancy);
1112
1135
  var isReactiveSmokeSensor = createSensorTypeGuard(SensorType.Smoke);
1113
1136
  var isReactiveLeakSensor = createSensorTypeGuard(SensorType.Leak);
1114
1137
  var isReactiveGarageControl = createSensorTypeGuard(SensorType.Garage);
1115
- function createReactiveSensor(data, state, rpcRef, cameraId) {
1138
+ function createReactiveSensor(data, state, rpcRef) {
1116
1139
  const displayName = ref(state.displayName ?? data.displayName ?? data.name);
1117
1140
  const capabilities = ref(state.capabilities ?? data.capabilities ?? []);
1141
+ const assignedCameraIds = ref([...data.assignedCameraIds]);
1142
+ const exposed = ref(data.exposed);
1143
+ const connected = ref(data.connected);
1118
1144
  const properties = reactive({ ...state.properties });
1119
1145
  const capabilityCallbacks = [];
1120
1146
  return {
@@ -1122,19 +1148,23 @@ function createReactiveSensor(data, state, rpcRef, cameraId) {
1122
1148
  type: data.type,
1123
1149
  name: data.name,
1124
1150
  displayName,
1151
+ nativeId: data.nativeId,
1125
1152
  pluginId: data.pluginId,
1153
+ assignedCameraIds,
1154
+ exposed,
1155
+ connected,
1126
1156
  capabilities,
1127
1157
  properties,
1128
1158
  getProperty(property) {
1129
1159
  return properties[property];
1130
1160
  },
1131
1161
  async setProperty(property, value) {
1132
- const sensorNamespace = `plugin.${data.pluginId}.camera.${cameraId}.sensor.${data.id}.rpc`;
1162
+ const sensorNamespace = `plugin.${data.pluginId}.sensor.${data.id}.rpc`;
1133
1163
  await rpcCall(rpcRef, (client) => client.createProxy(sensorNamespace).updateValue(property, value));
1134
1164
  },
1135
1165
  async setDisplayName(newDisplayName) {
1136
- const namespace = NamespaceManager.sensorControllerNamespaces(cameraId);
1137
- await rpcCall(rpcRef, (client) => client.createProxy(namespace.sensorRpc).setDisplayName(data.id, newDisplayName));
1166
+ const namespace = NamespaceManager.sensorRegistryNamespaces();
1167
+ await rpcCall(rpcRef, (client) => client.createProxy(namespace.sensorsRpc).setDisplayName(data.id, newDisplayName));
1138
1168
  },
1139
1169
  hasCapability(capability) {
1140
1170
  return capabilities.value.includes(capability);
@@ -1151,7 +1181,8 @@ function createReactiveSensor(data, state, rpcRef, cameraId) {
1151
1181
  }
1152
1182
  };
1153
1183
  }
1154
- function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sensorRpcNamespace) {
1184
+ function createSensorManager(rpcOrContext) {
1185
+ const { sensorsSubject, sensorsRpc } = NamespaceManager.sensorRegistryNamespaces();
1155
1186
  const ctx = "rpc" in rpcOrContext && "value" in rpcOrContext.rpc ? rpcOrContext : void 0;
1156
1187
  const rpcRef = ctx ? ctx.rpc : shallowRef(rpcOrContext);
1157
1188
  const sensorMap = shallowRef(/* @__PURE__ */ new Map());
@@ -1176,7 +1207,7 @@ function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sen
1176
1207
  }
1177
1208
  async function subscribeToSensorEvents(sensorId) {
1178
1209
  if (sensorSubscriptions.has(sensorId)) return;
1179
- const namespace = NamespaceManager.sensorEventNamespaces(cameraId, sensorId);
1210
+ const namespace = NamespaceManager.sensorEventNamespaces(sensorId);
1180
1211
  const unsubscribe = await rpcCall(rpcRef, (c) => c.subscribe(namespace.sensorSubject, (msg) => handlePerSensorEvent(sensorId, msg)));
1181
1212
  sensorSubscriptions.set(sensorId, unsubscribe);
1182
1213
  }
@@ -1191,17 +1222,33 @@ function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sen
1191
1222
  if (message.type === "sensor:added") {
1192
1223
  const event = message.data;
1193
1224
  if (sensorMap.value.has(event.sensor.id)) return;
1194
- const reactiveSensor = createReactiveSensor(event.sensor, event.state, rpcRef, cameraId);
1225
+ const reactiveSensor = createReactiveSensor(event.sensor, event.state, rpcRef);
1195
1226
  const newMap = new Map(sensorMap.value);
1196
1227
  newMap.set(event.sensor.id, reactiveSensor);
1197
1228
  sensorMap.value = newMap;
1198
1229
  subscribeToSensorEvents(event.sensor.id);
1199
- } else if (message.type === "sensor:removed") {
1230
+ } else if (message.type === "sensor:deleted") {
1200
1231
  const event = message.data;
1201
1232
  unsubscribeFromSensorEvents(event.sensorId);
1202
1233
  const newMap = new Map(sensorMap.value);
1203
1234
  newMap.delete(event.sensorId);
1204
1235
  sensorMap.value = newMap;
1236
+ } else if (message.type === "sensor:connected:changed") {
1237
+ const event = message.data;
1238
+ const sensor = sensorMap.value.get(event.sensorId);
1239
+ if (sensor) sensor.connected.value = event.connected;
1240
+ } else if (message.type === "sensor:assignment:changed") {
1241
+ const event = message.data;
1242
+ const sensor = sensorMap.value.get(event.sensorId);
1243
+ if (!sensor) return;
1244
+ const cameras = new Set(sensor.assignedCameraIds.value);
1245
+ if (event.assigned) cameras.add(event.cameraId);
1246
+ else cameras.delete(event.cameraId);
1247
+ sensor.assignedCameraIds.value = [...cameras];
1248
+ } else if (message.type === "sensor:exposed:changed") {
1249
+ const event = message.data;
1250
+ const sensor = sensorMap.value.get(event.sensorId);
1251
+ if (sensor) sensor.exposed.value = event.exposed;
1205
1252
  }
1206
1253
  }
1207
1254
  async function doInit() {
@@ -1211,12 +1258,12 @@ function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sen
1211
1258
  sensorSubscriptions.clear();
1212
1259
  sensorMap.value = /* @__PURE__ */ new Map();
1213
1260
  let pendingEvents = [];
1214
- globalUnsubscribe = await rpcCall(rpcRef, (c) => c.subscribe(sensorSubjectNamespace, (msg) => {
1261
+ globalUnsubscribe = await rpcCall(rpcRef, (c) => c.subscribe(sensorsSubject, (msg) => {
1215
1262
  if (pendingEvents) pendingEvents.push(msg);
1216
1263
  else handleGlobalSensorEvent(msg);
1217
1264
  }));
1218
1265
  const [sensors, states] = await rpcCall(rpcRef, async (c) => {
1219
- const proxy = c.createProxy(sensorRpcNamespace);
1266
+ const proxy = c.createProxy(sensorsRpc);
1220
1267
  return Promise.all([proxy.getSensors(), proxy.getSensorStates()]);
1221
1268
  });
1222
1269
  const newMap = /* @__PURE__ */ new Map();
@@ -1225,7 +1272,7 @@ function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sen
1225
1272
  properties: {},
1226
1273
  capabilities: [],
1227
1274
  type: sensor.type
1228
- }, rpcRef, cameraId);
1275
+ }, rpcRef);
1229
1276
  newMap.set(sensor.id, reactiveSensor);
1230
1277
  }
1231
1278
  sensorMap.value = newMap;
@@ -1281,7 +1328,7 @@ function createSensorManager(rpcOrContext, cameraId, sensorSubjectNamespace, sen
1281
1328
  return sensors.value.some((s) => s.type === type);
1282
1329
  },
1283
1330
  async setDisplayName(sensorId, displayName) {
1284
- await rpcCall(rpcRef, (c) => c.createProxy(sensorRpcNamespace).setDisplayName(sensorId, displayName));
1331
+ await rpcCall(rpcRef, (c) => c.createProxy(sensorsRpc).setDisplayName(sensorId, displayName));
1285
1332
  },
1286
1333
  ensureInitialized,
1287
1334
  reconnect,
@@ -1300,33 +1347,29 @@ function reconnectAllSensorManagers() {
1300
1347
  cached.initPromise = cached.manager.reconnect();
1301
1348
  });
1302
1349
  }
1303
- function acquireSensorManager(cameraId, rpcOrContext) {
1304
- return sensorManagerCache.acquire(cameraId, () => {
1305
- const namespaces = NamespaceManager.sensorControllerNamespaces(cameraId);
1306
- return { manager: createSensorManager(rpcOrContext, cameraId, namespaces.sensorSubject, namespaces.sensorRpc) };
1307
- });
1350
+ var GLOBAL_SENSOR_MANAGER_KEY = "sensors";
1351
+ function acquireSensorManager(rpcOrContext) {
1352
+ return sensorManagerCache.acquire(GLOBAL_SENSOR_MANAGER_KEY, () => ({ manager: createSensorManager(rpcOrContext) }));
1308
1353
  }
1309
- function releaseSensorManager(cameraId) {
1310
- sensorManagerCache.release(cameraId);
1354
+ function releaseSensorManager() {
1355
+ sensorManagerCache.release(GLOBAL_SENSOR_MANAGER_KEY);
1311
1356
  }
1312
1357
  function createSensorComposableState() {
1313
1358
  return {
1314
- currentCameraId: void 0,
1359
+ acquired: false,
1315
1360
  cachedManager: void 0
1316
1361
  };
1317
1362
  }
1318
- async function ensureSensorManager(state, cameraUi, isConnected, cameraId, isLoading, error) {
1363
+ function sensorsForCamera(manager, cameraId) {
1364
+ return manager.sensors.value.filter((sensor) => sensor.assignedCameraIds.value.includes(cameraId));
1365
+ }
1366
+ async function ensureSensorManager(state, cameraUi, isConnected, isLoading, error) {
1319
1367
  if (!cameraUi.rpc.value || !isConnected) return void 0;
1320
- if (state.currentCameraId && state.currentCameraId !== cameraId) {
1321
- releaseSensorManager(state.currentCameraId);
1322
- state.currentCameraId = void 0;
1323
- state.cachedManager = void 0;
1324
- }
1325
1368
  isLoading.value = true;
1326
1369
  error.value = void 0;
1327
1370
  try {
1328
- const cached = acquireSensorManager(cameraId, cameraUi);
1329
- state.currentCameraId = cameraId;
1371
+ const cached = acquireSensorManager(cameraUi);
1372
+ state.acquired = true;
1330
1373
  state.cachedManager = cached.manager;
1331
1374
  if (!cached.initPromise) cached.initPromise = cached.manager.ensureInitialized();
1332
1375
  await cached.initPromise;
@@ -1339,9 +1382,9 @@ async function ensureSensorManager(state, cameraUi, isConnected, cameraId, isLoa
1339
1382
  }
1340
1383
  }
1341
1384
  function cleanupSensorComposable(state) {
1342
- if (state.currentCameraId) {
1343
- releaseSensorManager(state.currentCameraId);
1344
- state.currentCameraId = void 0;
1385
+ if (state.acquired) {
1386
+ releaseSensorManager();
1387
+ state.acquired = false;
1345
1388
  state.cachedManager = void 0;
1346
1389
  }
1347
1390
  }
@@ -1359,7 +1402,7 @@ function useSensorById(camera, sensorId) {
1359
1402
  () => toValue(sensorId)
1360
1403
  ], async ([connected, camId, senId]) => {
1361
1404
  if (connected && camId && senId) {
1362
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1405
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1363
1406
  sensor.value = manager?.getSensor(senId);
1364
1407
  initialLoadDone.value = true;
1365
1408
  } else {
@@ -1391,8 +1434,8 @@ function useSensorByType(camera, sensorType) {
1391
1434
  () => toValue(sensorType)
1392
1435
  ], async ([connected, camId, type]) => {
1393
1436
  if (connected && camId) {
1394
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1395
- sensor.value = manager?.getSensorsByType(type)[0];
1437
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1438
+ sensor.value = manager ? sensorsForCamera(manager, camId).find((s) => s.type === type) : void 0;
1396
1439
  initialLoadDone.value = true;
1397
1440
  } else {
1398
1441
  cleanupSensorComposable(state);
@@ -1424,9 +1467,9 @@ function useSensorsByType(camera, sensorType) {
1424
1467
  () => toValue(sensorType)
1425
1468
  ], async ([connected, camId, type]) => {
1426
1469
  if (connected && camId) {
1427
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1470
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1428
1471
  cachedManager.value = manager;
1429
- sensorsRef.value = manager?.getSensorsByType(type) ?? [];
1472
+ sensorsRef.value = manager ? sensorsForCamera(manager, camId).filter((s) => s.type === type) : [];
1430
1473
  initialLoadDone.value = true;
1431
1474
  } else {
1432
1475
  cleanupSensorComposable(state);
@@ -1436,8 +1479,10 @@ function useSensorsByType(camera, sensorType) {
1436
1479
  }, { immediate: true });
1437
1480
  const sensors = computed(() => {
1438
1481
  if (!cachedManager.value) return [];
1482
+ const camId = extractCameraId(toValue(camera));
1439
1483
  const type = toValue(sensorType);
1440
- return cachedManager.value.sensors.value.filter((s) => s.type === type);
1484
+ if (!camId) return [];
1485
+ return sensorsForCamera(cachedManager.value, camId).filter((s) => s.type === type);
1441
1486
  });
1442
1487
  tryOnScopeDispose(() => {
1443
1488
  cleanupSensorComposable(state);
@@ -1460,9 +1505,9 @@ function useSensors(camera) {
1460
1505
  const state = createSensorComposableState();
1461
1506
  watch([isConnected, () => extractCameraId(toValue(camera))], async ([connected, camId]) => {
1462
1507
  if (connected && camId) {
1463
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1508
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1464
1509
  cachedManager.value = manager;
1465
- sensorsRef.value = manager?.sensors.value ?? [];
1510
+ sensorsRef.value = manager ? sensorsForCamera(manager, camId) : [];
1466
1511
  initialLoadDone.value = true;
1467
1512
  } else {
1468
1513
  cleanupSensorComposable(state);
@@ -1470,7 +1515,12 @@ function useSensors(camera) {
1470
1515
  cachedManager.value = void 0;
1471
1516
  }
1472
1517
  }, { immediate: true });
1473
- const sensors = computed(() => cachedManager.value?.sensors.value ?? []);
1518
+ const sensors = computed(() => {
1519
+ if (!cachedManager.value) return [];
1520
+ const camId = extractCameraId(toValue(camera));
1521
+ if (!camId) return [];
1522
+ return sensorsForCamera(cachedManager.value, camId);
1523
+ });
1474
1524
  tryOnScopeDispose(() => {
1475
1525
  cleanupSensorComposable(state);
1476
1526
  sensorsRef.value = [];
@@ -1481,6 +1531,33 @@ function useSensors(camera) {
1481
1531
  error
1482
1532
  };
1483
1533
  }
1534
+ function useAllSensors() {
1535
+ const cameraUi = useCameraUi();
1536
+ const { isConnected } = cameraUi;
1537
+ const cachedManager = shallowRef();
1538
+ const _isLoading = ref(false);
1539
+ const initialLoadDone = ref(false);
1540
+ const error = ref();
1541
+ const state = createSensorComposableState();
1542
+ watch([isConnected], async ([connected]) => {
1543
+ if (connected) {
1544
+ cachedManager.value = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1545
+ initialLoadDone.value = true;
1546
+ } else {
1547
+ cleanupSensorComposable(state);
1548
+ cachedManager.value = void 0;
1549
+ }
1550
+ }, { immediate: true });
1551
+ const sensors = computed(() => cachedManager.value?.sensors.value ?? []);
1552
+ tryOnScopeDispose(() => {
1553
+ cleanupSensorComposable(state);
1554
+ });
1555
+ return {
1556
+ sensors,
1557
+ isLoading: computed(() => _isLoading.value || !initialLoadDone.value),
1558
+ error
1559
+ };
1560
+ }
1484
1561
  function useTypedSensor(camera, sensorType) {
1485
1562
  const cameraUi = useCameraUi();
1486
1563
  const { isConnected } = cameraUi;
@@ -1492,9 +1569,9 @@ function useTypedSensor(camera, sensorType) {
1492
1569
  const state = createSensorComposableState();
1493
1570
  watch([isConnected, () => extractCameraId(toValue(camera))], async ([connected, camId]) => {
1494
1571
  if (connected && camId) {
1495
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1572
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1496
1573
  cachedManager.value = manager;
1497
- sensor.value = manager?.getSensorsByType(sensorType)[0];
1574
+ sensor.value = manager ? sensorsForCamera(manager, camId).find((s) => s.type === sensorType) : void 0;
1498
1575
  initialLoadDone.value = true;
1499
1576
  } else {
1500
1577
  cleanupSensorComposable(state);
@@ -1503,11 +1580,13 @@ function useTypedSensor(camera, sensorType) {
1503
1580
  }, { immediate: true });
1504
1581
  watch(() => {
1505
1582
  if (!cachedManager.value) return void 0;
1506
- return cachedManager.value.getSensorsByType(sensorType)[0]?.id;
1583
+ const camId = extractCameraId(toValue(camera));
1584
+ if (!camId) return void 0;
1585
+ return sensorsForCamera(cachedManager.value, camId).find((s) => s.type === sensorType)?.id;
1507
1586
  }, () => {
1508
1587
  if (cachedManager.value) {
1509
- const sensors = cachedManager.value.getSensorsByType(sensorType);
1510
- sensor.value = sensors[0];
1588
+ const camId = extractCameraId(toValue(camera));
1589
+ sensor.value = camId ? sensorsForCamera(cachedManager.value, camId).find((s) => s.type === sensorType) : void 0;
1511
1590
  }
1512
1591
  });
1513
1592
  tryOnScopeDispose(() => {
@@ -1549,9 +1628,9 @@ function useClassifierSensors(camera) {
1549
1628
  const state = createSensorComposableState();
1550
1629
  watch([isConnected, () => extractCameraId(toValue(camera))], async ([connected, camId]) => {
1551
1630
  if (connected && camId) {
1552
- const manager = await ensureSensorManager(state, cameraUi, connected, camId, _isLoading, error);
1631
+ const manager = await ensureSensorManager(state, cameraUi, connected, _isLoading, error);
1553
1632
  cachedManager.value = manager;
1554
- sensorsRef.value = manager?.getSensorsByType(SensorType.Classifier) ?? [];
1633
+ sensorsRef.value = manager ? sensorsForCamera(manager, camId).filter((s) => s.type === SensorType.Classifier) : [];
1555
1634
  initialLoadDone.value = true;
1556
1635
  } else {
1557
1636
  cleanupSensorComposable(state);
@@ -1559,7 +1638,12 @@ function useClassifierSensors(camera) {
1559
1638
  cachedManager.value = void 0;
1560
1639
  }
1561
1640
  }, { immediate: true });
1562
- const sensors = computed(() => cachedManager.value?.getSensorsByType(SensorType.Classifier) ?? []);
1641
+ const sensors = computed(() => {
1642
+ if (!cachedManager.value) return [];
1643
+ const camId = extractCameraId(toValue(camera));
1644
+ if (!camId) return [];
1645
+ return sensorsForCamera(cachedManager.value, camId).filter((s) => s.type === SensorType.Classifier);
1646
+ });
1563
1647
  tryOnScopeDispose(() => {
1564
1648
  cleanupSensorComposable(state);
1565
1649
  sensorsRef.value = [];
@@ -1663,8 +1747,8 @@ function getPluginStorageKey(pluginId) {
1663
1747
  function getCameraStorageKey(pluginId, cameraId) {
1664
1748
  return `plugin:${pluginId}:camera:${cameraId}`;
1665
1749
  }
1666
- function getSensorStorageKey(pluginId, cameraId, sensorId) {
1667
- return `plugin:${pluginId}:camera:${cameraId}:sensor:${sensorId}`;
1750
+ function getSensorStorageKey(pluginId, sensorId) {
1751
+ return `plugin:${pluginId}:sensor:${sensorId}`;
1668
1752
  }
1669
1753
  function acquireStorage(key, createProxy) {
1670
1754
  return storageCache.acquire(key, () => {
@@ -1874,7 +1958,7 @@ function useCameraStorage(camera, pluginName) {
1874
1958
  submitValue: operations.submitValue
1875
1959
  };
1876
1960
  }
1877
- function useSensorStorage(camera, sensorId, pluginId) {
1961
+ function useSensorStorage(sensorId, pluginId) {
1878
1962
  const { rpc, isConnected: clientConnected } = useCameraUi();
1879
1963
  const config = shallowRef();
1880
1964
  const _isLoading = ref(false);
@@ -1883,14 +1967,14 @@ function useSensorStorage(camera, sensorId, pluginId) {
1883
1967
  const isConnected = ref(false);
1884
1968
  const state = createStorageState();
1885
1969
  const operations = createStorageOperations(state, config, _isLoading, error);
1886
- function connect(cameraId, senId, plugId) {
1970
+ function connect(senId, plugId) {
1887
1971
  if (!rpc.value || !clientConnected.value) return false;
1888
1972
  try {
1889
- const storageKey = getSensorStorageKey(plugId, cameraId, senId);
1973
+ const storageKey = getSensorStorageKey(plugId, senId);
1890
1974
  if (state.currentStorageKey && state.currentStorageKey !== storageKey) releaseStorage(state.currentStorageKey);
1891
1975
  state.currentStorageKey = storageKey;
1892
1976
  state.cachedStorage = acquireStorage(storageKey, () => {
1893
- const namespaces = NamespaceManager.pluginSensorNamespaces(plugId, cameraId, senId);
1977
+ const namespaces = NamespaceManager.pluginSensorNamespaces(plugId, senId);
1894
1978
  return rpc.value.createProxy(namespaces.sensorStorageRpc);
1895
1979
  });
1896
1980
  isConnected.value = true;
@@ -1902,23 +1986,21 @@ function useSensorStorage(camera, sensorId, pluginId) {
1902
1986
  }
1903
1987
  }
1904
1988
  async function getConfig() {
1905
- const cameraId = extractCameraId(toValue(camera));
1906
1989
  const senId = toValue(sensorId);
1907
1990
  const plugId = toValue(pluginId);
1908
- if (!cameraId || !senId || !plugId) return void 0;
1991
+ if (!senId || !plugId) return void 0;
1909
1992
  if (!state.cachedStorage) {
1910
- if (!connect(cameraId, senId, plugId)) return void 0;
1993
+ if (!connect(senId, plugId)) return void 0;
1911
1994
  }
1912
1995
  return operations.getConfig();
1913
1996
  }
1914
1997
  watch([
1915
1998
  clientConnected,
1916
- () => extractCameraId(toValue(camera)),
1917
1999
  () => toValue(sensorId),
1918
2000
  () => toValue(pluginId)
1919
- ], ([connected, cameraId, senId, plugId]) => {
1920
- if (connected && cameraId && senId && plugId) {
1921
- connect(cameraId, senId, plugId);
2001
+ ], ([connected, senId, plugId]) => {
2002
+ if (connected && senId && plugId) {
2003
+ connect(senId, plugId);
1922
2004
  operations.getConfig();
1923
2005
  } else cleanupStorage(state, isConnected, config);
1924
2006
  initialSetupDone.value = true;
@@ -2106,14 +2188,12 @@ function createActivityMode(options) {
2106
2188
  startIdleTimer();
2107
2189
  }
2108
2190
  break;
2109
- case "activity":
2110
- if (hasActivity.value) {
2111
- inStandby.value = false;
2112
- if (!isStreamPlaying()) onStreamStart();
2113
- } else activityTimeout = setTimeout(() => {
2114
- if (mode.value === "activity" && !hasActivity.value) goToStandby();
2115
- }, resolvedConfig.activityTimeout);
2116
- break;
2191
+ case "activity": if (hasActivity.value) {
2192
+ inStandby.value = false;
2193
+ if (!isStreamPlaying()) onStreamStart();
2194
+ } else activityTimeout = setTimeout(() => {
2195
+ if (mode.value === "activity" && !hasActivity.value) goToStandby();
2196
+ }, resolvedConfig.activityTimeout);
2117
2197
  }
2118
2198
  }
2119
2199
  function startIdleTimer() {
@@ -2154,7 +2234,6 @@ function createActivityMode(options) {
2154
2234
  if (!hasActivity.value) activityTimeout = setTimeout(() => {
2155
2235
  goToStandby();
2156
2236
  }, resolvedConfig.activityTimeout);
2157
- break;
2158
2237
  }
2159
2238
  }
2160
2239
  function resetIdleTimer() {
@@ -2293,7 +2372,7 @@ var STREAM_CONFIG = {
2293
2372
  ICE_SERVERS: [{ urls: "stun:stun.l.google.com:19302" }]
2294
2373
  },
2295
2374
  MSE: {
2296
- BUFFER_SIZE: 2 * 1024 * 1024,
2375
+ BUFFER_SIZE: 2097152,
2297
2376
  BUFFER_WINDOW: 5
2298
2377
  },
2299
2378
  CODECS: {
@@ -2322,6 +2401,7 @@ var STREAM_CONFIG = {
2322
2401
  };
2323
2402
  //#endregion
2324
2403
  //#region src/streaming/utils.ts
2404
+ var H265_TEST_CODEC = "hvc1.1.6.L153.B0";
2325
2405
  function safariVersion() {
2326
2406
  return navigator.userAgent.match(/version\/(\d+)/i);
2327
2407
  }
@@ -2354,14 +2434,27 @@ function isWebRTCCompatibleVideo(codec) {
2354
2434
  if (codec === "H265") return isH265Supported();
2355
2435
  return false;
2356
2436
  }
2357
- function isH265Supported() {
2358
- try {
2359
- const videoCodecs = RTCRtpSender?.getCapabilities("video")?.codecs;
2360
- if (!videoCodecs) return false;
2361
- return videoCodecs.some((c) => c.mimeType.toLowerCase().includes("h265") || c.mimeType.toLowerCase().includes("hevc"));
2437
+ var mseH265;
2438
+ var webrtcH265;
2439
+ function canPlayH265(transport) {
2440
+ if (transport === "auto") return canPlayH265("webrtc") || canPlayH265("mse");
2441
+ if (transport === "mse") {
2442
+ if (mseH265 === void 0) mseH265 = !!getMediaSourceConstructor()?.isTypeSupported(`video/mp4; codecs="${H265_TEST_CODEC}"`);
2443
+ return mseH265;
2444
+ }
2445
+ if (webrtcH265 === void 0) try {
2446
+ webrtcH265 = !!(RTCRtpReceiver?.getCapabilities("video")?.codecs)?.some((c) => c.mimeType.toLowerCase().includes("h265") || c.mimeType.toLowerCase().includes("hevc"));
2362
2447
  } catch {
2363
- return false;
2448
+ webrtcH265 = false;
2364
2449
  }
2450
+ return webrtcH265;
2451
+ }
2452
+ function reportH265DecodeFailure(transport) {
2453
+ if (transport === "mse") mseH265 = false;
2454
+ else webrtcH265 = false;
2455
+ }
2456
+ function isH265Supported() {
2457
+ return canPlayH265("webrtc");
2365
2458
  }
2366
2459
  function checkWebRTCCompatibility(probe) {
2367
2460
  const audioStreams = probe.audio.filter((s) => s.direction === "sendonly");
@@ -2741,9 +2834,7 @@ async function processWebRTCMessage(handler, msg) {
2741
2834
  case "webrtc/answer":
2742
2835
  await handler.handleAnswer(msg.value);
2743
2836
  break;
2744
- case "webrtc/candidate":
2745
- if (msg.value) await handler.handleCandidate(msg.value);
2746
- break;
2837
+ case "webrtc/candidate": if (msg.value) await handler.handleCandidate(msg.value);
2747
2838
  }
2748
2839
  }
2749
2840
  //#endregion
@@ -2755,6 +2846,8 @@ var StreamConnection = class {
2755
2846
  requestedMode;
2756
2847
  activeResolution;
2757
2848
  requestedResolution;
2849
+ degradedFrom;
2850
+ degradeReason;
2758
2851
  source;
2759
2852
  hasVideo;
2760
2853
  hasAudio;
@@ -2766,14 +2859,20 @@ var StreamConnection = class {
2766
2859
  paused;
2767
2860
  nativeWidth;
2768
2861
  nativeHeight;
2862
+ camera;
2863
+ videoElement;
2864
+ containerElement;
2865
+ target;
2866
+ isReady;
2867
+ effectiveMode;
2868
+ triedSourceIds = /* @__PURE__ */ new Set();
2769
2869
  options;
2870
+ wsTransport;
2871
+ scope = effectScope(true);
2770
2872
  connectionGeneration = 0;
2771
2873
  abortController = new AbortController();
2772
- scope = effectScope(true);
2773
- offTabVisible;
2774
- offTabPaused;
2874
+ probedSourceId;
2775
2875
  wasPausedByVisibility = false;
2776
- wsTransport;
2777
2876
  wsHandle;
2778
2877
  webrtcHandler;
2779
2878
  mseHandler;
@@ -2783,15 +2882,11 @@ var StreamConnection = class {
2783
2882
  lastMediaStream = null;
2784
2883
  stopWatchers = [];
2785
2884
  mseMonitorInterval;
2885
+ offTabVisible;
2886
+ offTabPaused;
2786
2887
  onVideoPauseBound;
2787
2888
  onVideoPlayBound;
2788
2889
  onVideoResizeBound;
2789
- camera;
2790
- videoElement;
2791
- containerElement;
2792
- target;
2793
- isReady;
2794
- effectiveMode;
2795
2890
  startWsConnectTimeout;
2796
2891
  stopWsConnectTimeout;
2797
2892
  startConnectTimeout;
@@ -2810,6 +2905,8 @@ var StreamConnection = class {
2810
2905
  this.status = ref("idle");
2811
2906
  this.activeMode = ref("webrtc");
2812
2907
  this.activeResolution = ref("low-resolution");
2908
+ this.degradedFrom = ref(null);
2909
+ this.degradeReason = ref(null);
2813
2910
  this.source = shallowRef();
2814
2911
  this.hasVideo = ref(false);
2815
2912
  this.hasAudio = ref(false);
@@ -2846,11 +2943,18 @@ var StreamConnection = class {
2846
2943
  this.activeMode.value = "mse";
2847
2944
  if (this.mseHandler?.isReady) this.status.value = "connected";
2848
2945
  else this.startMSE();
2849
- } else this.restart();
2946
+ } else {
2947
+ this.markSourceUndecodable();
2948
+ this.restart();
2949
+ }
2950
+ else if (this.status.value === "connected" && !this.isPlaying.value && !this.abortController.signal.aborted && this.sourceLikelyH265()) this.handleNoFramesWhileConnected();
2850
2951
  }, STREAM_CONFIG.WEBRTC.CONNECT_TIMEOUT, { immediate: false });
2851
2952
  const mseConnectTimeout = useTimeoutFn(() => {
2852
2953
  if (this.abortController.signal.aborted || this.status.value === "connected" || this.status.value === "closed") return;
2853
- if (this.mseHandler && !this.mseHandler.isReady) this.restart();
2954
+ if (this.mseHandler && !this.mseHandler.isReady) {
2955
+ this.markSourceUndecodable();
2956
+ this.restart();
2957
+ }
2854
2958
  }, STREAM_CONFIG.WEBRTC.CONNECT_TIMEOUT, { immediate: false });
2855
2959
  const reconnectTimeout = useTimeoutFn(() => {
2856
2960
  if (!this.abortController.signal.aborted) this.restart();
@@ -2901,22 +3005,43 @@ var StreamConnection = class {
2901
3005
  this.cleanup();
2902
3006
  this.abortController = new AbortController();
2903
3007
  const gen = ++this.connectionGeneration;
3008
+ this.triedSourceIds.clear();
2904
3009
  this.status.value = "connecting";
2905
3010
  this.error.value = void 0;
2906
3011
  this.isPlaying.value = false;
2907
3012
  try {
2908
- if (!this.initializeSource()) {
3013
+ const init = this.initializeSource();
3014
+ if (init === "unsupported") {
3015
+ log.debug("start() — no source with a playable codec");
3016
+ this.setUnsupported();
3017
+ return;
3018
+ }
3019
+ if (!init) {
2909
3020
  log.debug("start() — no streaming source available");
2910
3021
  this.error.value = /* @__PURE__ */ new Error("No streaming source available");
2911
3022
  this.status.value = "error";
2912
3023
  return;
2913
3024
  }
2914
- await this.probeStream();
2915
- if (gen !== this.connectionGeneration) {
2916
- log.debug("start() generation stale after probe, aborting");
2917
- return;
3025
+ for (let attempt = 0; attempt < 3; attempt++) {
3026
+ const probedSourceId = this.source.value?._id;
3027
+ const probe = await this.probeStream();
3028
+ if (gen !== this.connectionGeneration) {
3029
+ log.debug("start() — generation stale after probe, aborting");
3030
+ return;
3031
+ }
3032
+ if (probe && probedSourceId && this.probeSaysUnplayable(probe)) this.triedSourceIds.add(probedSourceId);
3033
+ const reinit = this.initializeSource();
3034
+ if (reinit === "unsupported") {
3035
+ this.setUnsupported();
3036
+ return;
3037
+ }
3038
+ if (!reinit) {
3039
+ this.error.value = /* @__PURE__ */ new Error("No streaming source available");
3040
+ this.status.value = "error";
3041
+ return;
3042
+ }
3043
+ if (!probe || this.source.value?._id === probedSourceId) break;
2918
3044
  }
2919
- this.initializeSource();
2920
3045
  log.debug("start() — connecting WebSocket");
2921
3046
  this.connectWebSocket();
2922
3047
  } catch (err) {
@@ -2940,15 +3065,27 @@ var StreamConnection = class {
2940
3065
  if (this.requestedMode.value === mode) return;
2941
3066
  this.requestedMode.value = mode;
2942
3067
  this.activeMode.value = mode === "auto" ? "webrtc" : mode;
3068
+ if (this.status.value === "unsupported") {
3069
+ this.stop();
3070
+ await this.start();
3071
+ return;
3072
+ }
2943
3073
  if (this.status.value === "connected") await this.restart();
2944
3074
  }
2945
3075
  async setResolution(resolution) {
2946
3076
  if (this.requestedResolution.value === resolution) return;
2947
3077
  this.requestedResolution.value = resolution;
3078
+ if (this.status.value === "unsupported") {
3079
+ this.stop();
3080
+ await this.start();
3081
+ return;
3082
+ }
2948
3083
  const result = this.getSourceForResolution(resolution);
2949
- if (result && result.source._id !== this.source.value?._id) {
3084
+ if (result && result !== "unsupported" && result.source._id !== this.source.value?._id) {
2950
3085
  this.source.value = result.source;
2951
3086
  this.activeResolution.value = result.effectiveResolution;
3087
+ this.degradedFrom.value = result.degradedFrom;
3088
+ this.degradeReason.value = result.degradedFrom ? "codec" : null;
2952
3089
  if (this.status.value === "connected") await this.restart();
2953
3090
  }
2954
3091
  }
@@ -3023,7 +3160,12 @@ var StreamConnection = class {
3023
3160
  return;
3024
3161
  }
3025
3162
  try {
3026
- if (!this.initializeSource()) {
3163
+ const init = this.initializeSource();
3164
+ if (init === "unsupported") {
3165
+ this.setUnsupported();
3166
+ return;
3167
+ }
3168
+ if (!init) {
3027
3169
  this.error.value = /* @__PURE__ */ new Error("No streaming source available");
3028
3170
  this.status.value = "error";
3029
3171
  return;
@@ -3057,6 +3199,12 @@ var StreamConnection = class {
3057
3199
  this.restart();
3058
3200
  });
3059
3201
  this.stopWatchers.push(stopAuthWatch);
3202
+ const stopSourcesWatch = watch(() => this.camera.value?.sources.value, () => {
3203
+ if (this.status.value !== "unsupported") return;
3204
+ this.stop();
3205
+ this.start();
3206
+ });
3207
+ this.stopWatchers.push(stopSourcesWatch);
3060
3208
  const stopModeWatch = watch(() => toValue(this.options.mode), (newMode) => {
3061
3209
  if (newMode !== void 0 && newMode !== this.requestedMode.value) this.setMode(newMode);
3062
3210
  });
@@ -3107,6 +3255,9 @@ var StreamConnection = class {
3107
3255
  if (newCamera !== oldCamera) {
3108
3256
  if (this.status.value === "connected") {
3109
3257
  if (newCamera && newVideo && newClient) this.restart();
3258
+ } else if (this.status.value === "unsupported" && newCamera && newVideo && newClient) {
3259
+ this.stop();
3260
+ this.start();
3110
3261
  }
3111
3262
  } else if (newVideo !== oldVideo && newVideo) {
3112
3263
  if (newVideo.srcObject instanceof MediaStream) {
@@ -3144,6 +3295,14 @@ var StreamConnection = class {
3144
3295
  });
3145
3296
  this.stopWatchers.push(stopCameraWatch);
3146
3297
  }
3298
+ isSourcePlayable(source) {
3299
+ if (this.triedSourceIds.has(source._id)) return false;
3300
+ if (source.videoCodec !== "H265") return true;
3301
+ const mode = this.requestedMode.value;
3302
+ if (mode === "auto") return canPlayH265("auto");
3303
+ if (mode === "mse") return canPlayH265("mse");
3304
+ return canPlayH265("webrtc");
3305
+ }
3147
3306
  getSourceForResolution(resolution) {
3148
3307
  const cam = this.camera.value;
3149
3308
  if (!cam) return void 0;
@@ -3152,43 +3311,89 @@ var StreamConnection = class {
3152
3311
  "mid-resolution",
3153
3312
  "low-resolution"
3154
3313
  ];
3155
- const exactSource = cam.sources.value.find((s) => s.role === resolution);
3156
- if (exactSource) return {
3157
- source: exactSource,
3158
- effectiveResolution: resolution
3159
- };
3160
- const startIndex = resolutionOrder.indexOf(resolution);
3314
+ const startIndex = Math.max(0, resolutionOrder.indexOf(resolution));
3315
+ let skippedUnplayable = false;
3161
3316
  for (let i = startIndex; i < resolutionOrder.length; i++) {
3162
3317
  const src = cam.sources.value.find((s) => s.role === resolutionOrder[i]);
3163
- if (src) return {
3318
+ if (!src) continue;
3319
+ if (!this.isSourcePlayable(src)) {
3320
+ skippedUnplayable = true;
3321
+ continue;
3322
+ }
3323
+ return {
3164
3324
  source: src,
3165
- effectiveResolution: resolutionOrder[i]
3325
+ effectiveResolution: resolutionOrder[i],
3326
+ degradedFrom: skippedUnplayable ? resolution : null
3166
3327
  };
3167
3328
  }
3168
3329
  const fallback = cam.streamSource.value;
3169
- if (fallback) return {
3330
+ if (fallback && this.isSourcePlayable(fallback)) return {
3170
3331
  source: fallback,
3171
- effectiveResolution: fallback.role ?? "low-resolution"
3332
+ effectiveResolution: fallback.role ?? "low-resolution",
3333
+ degradedFrom: skippedUnplayable ? resolution : null
3172
3334
  };
3335
+ if (skippedUnplayable || fallback) return "unsupported";
3173
3336
  }
3174
3337
  initializeSource() {
3175
3338
  const result = this.getSourceForResolution(this.requestedResolution.value);
3176
3339
  if (!result) return false;
3340
+ if (result === "unsupported") return "unsupported";
3177
3341
  this.source.value = result.source;
3178
3342
  this.activeResolution.value = result.effectiveResolution;
3343
+ this.degradedFrom.value = result.degradedFrom;
3344
+ this.degradeReason.value = result.degradedFrom ? "codec" : null;
3345
+ if (this.probedSourceId && this.probedSourceId !== result.source._id) {
3346
+ this.probeInfo.value = void 0;
3347
+ this.probedSourceId = void 0;
3348
+ this.hasVideo.value = false;
3349
+ this.hasAudio.value = false;
3350
+ this.hasBackchannel.value = false;
3351
+ }
3179
3352
  return true;
3180
3353
  }
3354
+ setUnsupported() {
3355
+ const codec = this.camera.value?.sources.value.find((s) => s.videoCodec)?.videoCodec ?? "H265";
3356
+ this.error.value = /* @__PURE__ */ new Error(`${codec} cannot be played on this device`);
3357
+ this.status.value = "unsupported";
3358
+ }
3359
+ probeSaysUnplayable(probe) {
3360
+ const video = probe.video.filter((v) => v.direction === "sendonly");
3361
+ if (!video.length) return false;
3362
+ if (!video.every((v) => v.codec === "H265")) return false;
3363
+ const mode = this.requestedMode.value;
3364
+ return !canPlayH265(mode === "auto" ? "auto" : mode === "mse" ? "mse" : "webrtc");
3365
+ }
3366
+ sourceLikelyH265() {
3367
+ const src = this.source.value;
3368
+ if (!src) return false;
3369
+ if (src.videoCodec === "H265") return true;
3370
+ if (src.videoCodec !== void 0) return false;
3371
+ const video = this.probeInfo.value?.video.filter((v) => v.direction === "sendonly") ?? [];
3372
+ return video.length > 0 && video.every((v) => v.codec === "H265");
3373
+ }
3374
+ markSourceUndecodable() {
3375
+ const src = this.source.value;
3376
+ if (!src || !this.sourceLikelyH265()) return;
3377
+ this.triedSourceIds.add(src._id);
3378
+ }
3379
+ handleNoFramesWhileConnected() {
3380
+ reportH265DecodeFailure(this.activeMode.value === "mse" ? "mse" : "webrtc");
3381
+ this.markSourceUndecodable();
3382
+ this.restart();
3383
+ }
3181
3384
  async probeStream() {
3182
3385
  const cam = this.camera.value;
3183
- if (!cam || !this.source.value || this.abortController.signal.aborted) return void 0;
3386
+ const source = this.source.value;
3387
+ if (!cam || !source || this.abortController.signal.aborted) return void 0;
3184
3388
  try {
3185
- const probe = await cam.probeStream(this.source.value._id, {
3389
+ const probe = await cam.probeStream(source._id, {
3186
3390
  video: true,
3187
3391
  audio: ["pcma", "opus"],
3188
3392
  microphone: true
3189
3393
  });
3190
3394
  if (probe && !this.abortController.signal.aborted) {
3191
3395
  this.probeInfo.value = probe;
3396
+ this.probedSourceId = source._id;
3192
3397
  this.hasBackchannel.value = probe.audio.some((a) => a.direction === "recvonly");
3193
3398
  this.hasAudio.value = probe.audio.filter((a) => a.direction === "sendonly").length > 0;
3194
3399
  this.hasVideo.value = probe.video.filter((v) => v.direction === "sendonly").length > 0;
@@ -3262,12 +3467,10 @@ var StreamConnection = class {
3262
3467
  case "mse":
3263
3468
  if (this.mseHandler && typeof msg.value === "string") this.mseHandler.initializeBuffer(msg.value);
3264
3469
  break;
3265
- case "error":
3266
- if (this.requestedMode.value !== "auto") {
3267
- this.error.value = new Error(msg.value);
3268
- this.status.value = "error";
3269
- }
3270
- break;
3470
+ case "error": if (this.requestedMode.value !== "auto") {
3471
+ this.error.value = new Error(msg.value);
3472
+ this.status.value = "error";
3473
+ }
3271
3474
  }
3272
3475
  }
3273
3476
  async startWebRTC(mode) {
@@ -3294,7 +3497,6 @@ var StreamConnection = class {
3294
3497
  if (this.abortController.signal.aborted) return;
3295
3498
  const video = this.videoElement.value;
3296
3499
  if (!video) return;
3297
- this.stopConnectTimeout();
3298
3500
  this.activeMode.value = this.requestedMode.value === "auto" ? "webrtc" : this.requestedMode.value;
3299
3501
  this.lastMediaStream = stream;
3300
3502
  video.srcObject = stream;
@@ -3393,7 +3595,10 @@ var StreamConnection = class {
3393
3595
  this.startWebRTC("webrtc");
3394
3596
  }
3395
3597
  handleFirstFrame() {
3396
- if (!this.isPlaying.value && !this.abortController.signal.aborted) this.isPlaying.value = true;
3598
+ if (!this.isPlaying.value && !this.abortController.signal.aborted) {
3599
+ this.stopConnectTimeout();
3600
+ this.isPlaying.value = true;
3601
+ }
3397
3602
  }
3398
3603
  monitorMseBuffer() {
3399
3604
  const video = this.videoElement.value;
@@ -3800,11 +4005,13 @@ function useCameraStream(options) {
3800
4005
  const isPlaying = computed(() => currentStream.value?.isPlaying.value ?? false);
3801
4006
  const activeMode = computed(() => currentStream.value?.activeMode.value ?? "webrtc");
3802
4007
  const activeResolution = computed(() => currentStream.value?.activeResolution.value ?? "low-resolution");
4008
+ const degradedFrom = computed(() => currentStream.value?.degradedFrom.value ?? null);
4009
+ const unsupported = computed(() => status.value === "unsupported");
3803
4010
  const hasAudio = computed(() => currentStream.value?.hasAudio.value ?? false);
3804
4011
  const hasBackchannel = computed(() => currentStream.value?.hasBackchannel.value ?? false);
3805
4012
  const error = computed(() => currentStream.value?.error.value);
3806
4013
  const isReconnecting = computed(() => status.value === "reconnecting");
3807
- const isBusy = computed(() => cameraDeviceLoading.value || !isPlaying.value && status.value !== "error");
4014
+ const isBusy = computed(() => cameraDeviceLoading.value || !isPlaying.value && status.value !== "error" && status.value !== "unsupported");
3808
4015
  const hasSound = computed(() => hasAudio.value && status.value === "connected");
3809
4016
  const hasIntercom = computed(() => Boolean(typeof navigator !== "undefined" && navigator.mediaDevices) && hasBackchannel.value);
3810
4017
  const muted = computed(() => currentStream.value?.muted.value ?? true);
@@ -4196,6 +4403,8 @@ function useCameraStream(options) {
4196
4403
  isPlaying,
4197
4404
  activeMode,
4198
4405
  activeResolution,
4406
+ degradedFrom,
4407
+ unsupported,
4199
4408
  hasAudio,
4200
4409
  hasBackchannel,
4201
4410
  error,
@@ -4441,4 +4650,4 @@ function useTerminal() {
4441
4650
  };
4442
4651
  }
4443
4652
  //#endregion
4444
- export { CAMERA_UI_INJECTION_KEY, NamespaceManager, STREAM_CONFIG, acquireSensorManager, clearCameraCache, clearOAuthCache, clearPluginCache, clearSensorCache, clearSnapshotCache, clearStorageCache, createActivityMode, createCameraUiPlugin, createReactiveCameraDevice, createSensorManager, getSnapshotUrl, isReactiveAudioSensor, isReactiveBatteryInfo, isReactiveClassifierSensor, isReactiveContactSensor, isReactiveDoorbellTrigger, isReactiveFaceSensor, isReactiveGarageControl, isReactiveHumidityInfo, isReactiveLeakSensor, isReactiveLicensePlateSensor, isReactiveLightControl, isReactiveLockControl, isReactiveMotionSensor, isReactiveObjectSensor, isReactiveOccupancySensor, isReactivePTZControl, isReactiveSecuritySystem, isReactiveSirenControl, isReactiveSmokeSensor, isReactiveSwitchControl, isReactiveTemperatureInfo, refreshClientSubscriptions, releaseSensorManager, resetClientState, rpcCall, useAudioSensor, useCameraById, useCameraStorage, useCameraStream, useCameraUi, useClassifierSensors, useCoreManager, useCuiFullscreen, useDeviceManager, useFaceSensor, useLicensePlateSensor, useMotionSensor, useOAuth, useObjectSensor, usePTZControl, usePlugin, usePluginStorage, useRpcCall, useRpcSubscription, useSensorById, useSensorByType, useSensorStorage, useSensors, useSensorsByType, useSnapshot, useTabVisibility, useTerminal, useTopmostFullscreenElement };
4653
+ export { CAMERA_UI_INJECTION_KEY, NamespaceManager, STREAM_CONFIG, acquireSensorManager, clearCameraCache, clearOAuthCache, clearPluginCache, clearSensorCache, clearSnapshotCache, clearStorageCache, createActivityMode, createCameraUiPlugin, createReactiveCameraDevice, createSensorManager, getSnapshotUrl, isReactiveAudioSensor, isReactiveBatteryInfo, isReactiveClassifierSensor, isReactiveContactSensor, isReactiveDoorbellTrigger, isReactiveFaceSensor, isReactiveGarageControl, isReactiveHumidityInfo, isReactiveLeakSensor, isReactiveLicensePlateSensor, isReactiveLightControl, isReactiveLockControl, isReactiveMotionSensor, isReactiveObjectSensor, isReactiveOccupancySensor, isReactivePTZControl, isReactiveSecuritySystem, isReactiveSirenControl, isReactiveSmokeSensor, isReactiveSwitchControl, isReactiveTemperatureInfo, refreshClientSubscriptions, releaseSensorManager, resetClientState, rpcCall, useAllSensors, useAudioSensor, useCameraById, useCameraStorage, useCameraStream, useCameraUi, useClassifierSensors, useCoreManager, useCuiFullscreen, useDeviceManager, useFaceSensor, useLicensePlateSensor, useMotionSensor, useOAuth, useObjectSensor, usePTZControl, usePlugin, usePluginStorage, useRpcCall, useRpcSubscription, useSensorById, useSensorByType, useSensorStorage, useSensors, useSensorsByType, useSnapshot, useTabVisibility, useTerminal, useTopmostFullscreenElement };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camera.ui/browser",
3
- "version": "0.0.146",
3
+ "version": "0.0.148",
4
4
  "description": "camera.ui browser client",
5
5
  "author": "seydx (https://github.com/cameraui/clients)",
6
6
  "type": "module",
@@ -31,15 +31,15 @@
31
31
  "peerDependencies": {
32
32
  "@camera.ui/logger": ">=0.0.2",
33
33
  "@camera.ui/rpc": ">=1.0.10",
34
- "@camera.ui/sdk": ">=0.0.31",
34
+ "@camera.ui/sdk": ">=1.2.0",
35
35
  "@camera.ui/transport": ">=0.0.1",
36
- "@vueuse/core": ">=14.3.0",
36
+ "@vueuse/core": ">=14.4.0",
37
37
  "vue": ">=3.5.40"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@camera.ui/logger": "file:../../packages/logger",
41
41
  "@camera.ui/rpc": "^1.0.10",
42
- "@camera.ui/sdk": "~0.0.31",
42
+ "@camera.ui/sdk": "~1.2.0",
43
43
  "@camera.ui/transport": "file:../../packages/transport",
44
44
  "@eneris/push-receiver": "^4.3.1",
45
45
  "@microsoft/api-extractor": "^7.58.12",
@@ -51,7 +51,7 @@
51
51
  "@vue/eslint-config-typescript": "^14.9.0",
52
52
  "@vue/language-core": "^3.3.8",
53
53
  "@vue/tsconfig": "^0.9.1",
54
- "@vueuse/core": "^14.3.0",
54
+ "@vueuse/core": "^14.4.0",
55
55
  "@webgpu/types": "^0.1.71",
56
56
  "eslint": "9.39.2",
57
57
  "eslint-plugin-vue": "^10.10.0",
@@ -61,8 +61,8 @@
61
61
  "typescript": "5.9.3",
62
62
  "typescript-eslint": "^8.65.0",
63
63
  "unplugin-dts": "^1.0.3",
64
- "updates": "^17.19.1",
65
- "vite": "^8.1.5",
64
+ "updates": "^17.20.1",
65
+ "vite": "^8.2.0",
66
66
  "vitest": "^4.1.10",
67
67
  "vue": "^3.5.40",
68
68
  "vue-tsc": "^3.3.8"