@camera.ui/browser 0.0.183 → 0.0.185

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/dist/index.d.ts CHANGED
@@ -288,6 +288,8 @@ export declare interface CodecCompatibility {
288
288
  /* Excluded from this release type: ContactSensorProperties */
289
289
 
290
290
  export declare interface CoreManagerInterface {
291
+ ingestTrainingCandidate(payload: TrainingCandidateIngest): Promise<TrainingIngestResult>;
292
+ getTrainingCollectionEnabled(): Promise<boolean>;
291
293
  getFFmpegPath(): Promise<string>;
292
294
  getServerAddresses(): Promise<string[]>;
293
295
  getCloudServerId(): Promise<string>;
@@ -998,6 +1000,7 @@ export declare interface ReactiveSensor<TProperties extends object = Record<stri
998
1000
  readonly displayName: Ref<string>;
999
1001
  readonly nativeId?: string;
1000
1002
  readonly pluginId: string;
1003
+ readonly boundCameraId?: string;
1001
1004
  readonly assignedCameraIds: Ref<string[]>;
1002
1005
  readonly exposed: Ref<boolean>;
1003
1006
  readonly connected: Ref<boolean>;
@@ -1338,6 +1341,25 @@ export declare interface TerminalSessionInfo {
1338
1341
  dimensions: { cols: number; rows: number };
1339
1342
  }
1340
1343
 
1344
+ declare interface TrainingCandidateBox {
1345
+ label: string;
1346
+ confidence: number;
1347
+ x: number;
1348
+ y: number;
1349
+ width: number;
1350
+ height: number;
1351
+ }
1352
+
1353
+ declare interface TrainingCandidateIngest {
1354
+ cameraId: string;
1355
+ eventId: string;
1356
+ capturedAt: number;
1357
+ boxes: TrainingCandidateBox[];
1358
+ scene: Uint8Array;
1359
+ }
1360
+
1361
+ declare type TrainingIngestResult = 'stored' | 'skip' | 'disabled';
1362
+
1341
1363
  export declare function useAllSensors(): UseSensorsReturn;
1342
1364
 
1343
1365
  export declare function useAudioSensor(camera: CameraIdentifier, preferredPluginId?: MaybeRefOrGetter<string | undefined>): UseSensorTypedReturn<ReactiveAudioSensor>;
package/dist/index.js CHANGED
@@ -419,9 +419,44 @@ var snapshotCache = /* @__PURE__ */ new Map();
419
419
  var timestampCache = /* @__PURE__ */ new Map();
420
420
  var urlCache = /* @__PURE__ */ new Map();
421
421
  var subscribers = /* @__PURE__ */ new Map();
422
+ var pendingLoads$2 = /* @__PURE__ */ new Map();
422
423
  function notify(cameraId) {
423
424
  subscribers.get(cameraId)?.forEach((cb) => cb());
424
425
  }
426
+ function fetchSnapshotShared(deviceManager, id, forceFresh = false) {
427
+ const pending = pendingLoads$2.get(id);
428
+ if (pending) return pending;
429
+ const promise = (async () => {
430
+ const device = await acquireCameraDevice(deviceManager, id);
431
+ try {
432
+ if (!device) return void 0;
433
+ const result = await device.fetchSnapshot(void 0, forceFresh ? true : void 0);
434
+ if (result) setSnapshot(id, result);
435
+ return result ?? void 0;
436
+ } finally {
437
+ if (device) releaseCameraDevice(id);
438
+ }
439
+ })().finally(() => pendingLoads$2.delete(id));
440
+ pendingLoads$2.set(id, promise);
441
+ return promise;
442
+ }
443
+ var reconnectHooked = false;
444
+ function hookReconnectRefresh(cameraUi, deviceManager) {
445
+ if (reconnectHooked) return;
446
+ reconnectHooked = true;
447
+ cameraUi.on("reconnected", () => {
448
+ let delay = 0;
449
+ for (const id of subscribers.keys()) {
450
+ if ((subscribers.get(id)?.size ?? 0) === 0) continue;
451
+ const cameraId = id;
452
+ setTimeout(() => {
453
+ if ((subscribers.get(cameraId)?.size ?? 0) === 0) return;
454
+ fetchSnapshotShared(deviceManager, cameraId).catch(() => void 0);
455
+ }, delay);
456
+ delay += 150;
457
+ }
458
+ });
459
+ }
425
460
  function deferRevoke(url) {
426
461
  setTimeout(() => URL.revokeObjectURL(url), REVOKE_DELAY_MS);
427
462
  }
@@ -468,6 +503,7 @@ function useSnapshot(cameraIdOrName) {
468
503
  const snapshot = shallowRef();
469
504
  const _isLoading = ref(false);
470
505
  const initialLoadDone = ref(false);
506
+ hookReconnectRefresh(cameraUi, deviceManager);
471
507
  const snapshotSrc = computed(() => {
472
508
  if (!snapshot.value) return void 0;
473
509
  const idOrName = toValue(cameraIdOrName);
@@ -524,18 +560,8 @@ function useSnapshot(cameraIdOrName) {
524
560
  }
525
561
  _isLoading.value = true;
526
562
  try {
527
- const device = await acquireCameraDevice(deviceManager, id);
528
- try {
529
- if (device) {
530
- const result = await device.fetchSnapshot();
531
- if (result) {
532
- setSnapshot(id, result);
533
- snapshot.value = result;
534
- }
535
- }
536
- } finally {
537
- if (device) releaseCameraDevice(id);
538
- }
563
+ const result = await fetchSnapshotShared(deviceManager, id);
564
+ if (result) snapshot.value = result;
539
565
  } catch {} finally {
540
566
  _isLoading.value = false;
541
567
  initialLoadDone.value = true;
@@ -551,18 +577,8 @@ function useSnapshot(cameraIdOrName) {
551
577
  if (isCameraDisabled(cameraIdName)) return;
552
578
  _isLoading.value = true;
553
579
  try {
554
- const device = await acquireCameraDevice(deviceManager, id);
555
- try {
556
- if (device) {
557
- const result = await device.fetchSnapshot(void 0, true);
558
- if (result) {
559
- setSnapshot(id, result);
560
- snapshot.value = result;
561
- }
562
- }
563
- } finally {
564
- if (device) releaseCameraDevice(id);
565
- }
580
+ const result = await fetchSnapshotShared(deviceManager, id, true);
581
+ if (result) snapshot.value = result;
566
582
  } catch {} finally {
567
583
  _isLoading.value = false;
568
584
  initialLoadDone.value = true;
@@ -589,15 +605,7 @@ function useSnapshot(cameraIdOrName) {
589
605
  snapshot.value = void 0;
590
606
  }
591
607
  }, { immediate: true });
592
- const onReconnected = () => {
593
- const idOrName = toValue(cameraIdOrName);
594
- if (isCameraDisabled(idOrName)) return;
595
- const id = typeof idOrName === "string" ? idOrName : idOrName._id;
596
- if (id) loadSnapshot(id, true);
597
- };
598
- cameraUi.on("reconnected", onReconnected);
599
608
  tryOnScopeDispose(() => {
600
- cameraUi.off("reconnected", onReconnected);
601
609
  unsubscribe?.();
602
610
  releaseHeldDevice();
603
611
  });
@@ -1258,6 +1266,7 @@ function createReactiveSensor(data, state, rpcRef) {
1258
1266
  displayName,
1259
1267
  nativeId: data.nativeId,
1260
1268
  pluginId: data.pluginId,
1269
+ boundCameraId: data.boundCameraId,
1261
1270
  assignedCameraIds,
1262
1271
  exposed,
1263
1272
  connected,
@@ -1777,18 +1786,25 @@ function useClassifierSensors(camera) {
1777
1786
  //#endregion
1778
1787
  //#region src/composables/resolvePluginId.ts
1779
1788
  var pluginIdCache = /* @__PURE__ */ new Map();
1789
+ var pendingResolves = /* @__PURE__ */ new Map();
1780
1790
  function clearPluginIdCache() {
1781
1791
  pluginIdCache.clear();
1782
1792
  }
1783
1793
  async function resolvePluginId(rpcRef, pluginName) {
1784
1794
  const cached = pluginIdCache.get(pluginName);
1785
1795
  if (cached) return cached;
1786
- const namespaces = NamespaceManager.coreManagerNamespaces();
1787
- const pluginInfo = await rpcCall(rpcRef, (rpc) => rpc.createProxy(namespaces.coreManagerRpc).getPlugin(pluginName));
1788
- if (pluginInfo) {
1789
- pluginIdCache.set(pluginName, pluginInfo.id);
1790
- return pluginInfo.id;
1791
- }
1796
+ const pending = pendingResolves.get(pluginName);
1797
+ if (pending) return pending;
1798
+ const promise = (async () => {
1799
+ const namespaces = NamespaceManager.coreManagerNamespaces();
1800
+ const pluginInfo = await rpcCall(rpcRef, (rpc) => rpc.createProxy(namespaces.coreManagerRpc).getPlugin(pluginName));
1801
+ if (pluginInfo) {
1802
+ pluginIdCache.set(pluginName, pluginInfo.id);
1803
+ return pluginInfo.id;
1804
+ }
1805
+ })().finally(() => pendingResolves.delete(pluginName));
1806
+ pendingResolves.set(pluginName, promise);
1807
+ return promise;
1792
1808
  }
1793
1809
  //#endregion
1794
1810
  //#region src/composables/useStorage.ts
@@ -1796,11 +1812,16 @@ function createReactiveStorage(proxy) {
1796
1812
  const config = shallowRef();
1797
1813
  const isLoading = ref(false);
1798
1814
  const error = ref();
1815
+ let inFlightConfig = null;
1799
1816
  async function getConfig() {
1817
+ if (inFlightConfig) return inFlightConfig;
1800
1818
  isLoading.value = true;
1801
1819
  error.value = void 0;
1802
1820
  try {
1803
- config.value = await proxy.getConfig();
1821
+ inFlightConfig = proxy.getConfig().finally(() => {
1822
+ inFlightConfig = null;
1823
+ });
1824
+ config.value = await inFlightConfig;
1804
1825
  return config.value;
1805
1826
  } catch (err) {
1806
1827
  error.value = err instanceof Error ? err : new Error(String(err));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camera.ui/browser",
3
- "version": "0.0.183",
3
+ "version": "0.0.185",
4
4
  "description": "camera.ui browser client",
5
5
  "author": "seydx (https://github.com/cameraui/clients)",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "prepublishOnly": "npm i --package-lock-only && npm run lint && npm run format && npm run build",
27
27
  "test": "vitest run --passWithNoTests",
28
28
  "test:watch": "vitest",
29
- "update": "updates --update ./"
29
+ "update": "updates -M npm,pypi,go,cargo,docker,make --update ./"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "@camera.ui/logger": ">=0.0.2",
@@ -61,9 +61,9 @@
61
61
  "typescript": "5.9.3",
62
62
  "typescript-eslint": "^8.69.0",
63
63
  "unplugin-dts": "^1.1.0",
64
- "updates": "^18.0.7",
64
+ "updates": "^18.1.0",
65
65
  "vite": "^8.2.2",
66
- "vitest": "^4.1.11",
66
+ "vitest": "^5.0.0",
67
67
  "vue": "^3.5.42",
68
68
  "vue-tsc": "^3.3.11"
69
69
  },