@camstack/ui-library 0.1.39 → 0.1.40
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/composites/addon-global-settings-form.d.ts +60 -0
- package/dist/composites/addon-page-props.d.ts +12 -0
- package/dist/composites/agent-step-editor.d.ts +15 -0
- package/dist/composites/app-shell/app-shell.d.ts +19 -0
- package/dist/composites/app-shell/index.d.ts +3 -0
- package/dist/composites/app-shell/sidebar-item.d.ts +10 -0
- package/dist/composites/app-shell/sidebar.d.ts +14 -0
- package/dist/composites/audio-classification-list.d.ts +20 -0
- package/dist/composites/audio-level-waveform.d.ts +35 -0
- package/dist/composites/audio-waveform.d.ts +20 -0
- package/dist/composites/battery-badge.d.ts +12 -0
- package/dist/composites/breadcrumb.d.ts +25 -0
- package/dist/composites/camera-stream-player.d.ts +87 -0
- package/dist/composites/code-block.d.ts +6 -0
- package/dist/composites/config-form-builder.d.ts +18 -0
- package/dist/composites/config-form-field.d.ts +70 -0
- package/dist/composites/confirm-action-button.d.ts +41 -0
- package/dist/composites/confirm-dialog.d.ts +13 -0
- package/dist/composites/data-table/data-table-header.d.ts +10 -0
- package/dist/composites/data-table/data-table-pagination.d.ts +9 -0
- package/dist/composites/data-table/data-table-row.d.ts +10 -0
- package/dist/composites/data-table/data-table.d.ts +2 -0
- package/dist/composites/data-table/index.d.ts +2 -0
- package/dist/composites/data-table/types.d.ts +34 -0
- package/dist/composites/data-table.d.ts +37 -0
- package/dist/composites/detection-canvas.d.ts +29 -0
- package/dist/composites/detection-colors.d.ts +15 -0
- package/dist/composites/detection-overlay.d.ts +9 -0
- package/dist/composites/detection-result-tree.d.ts +11 -0
- package/dist/composites/dev-shell.d.ts +20 -0
- package/dist/composites/device-activity-panel.d.ts +29 -0
- package/dist/composites/device-card.d.ts +38 -0
- package/dist/composites/device-grid.d.ts +12 -0
- package/dist/composites/device-item/actions.d.ts +9 -0
- package/dist/composites/device-item/children-accordion.d.ts +11 -0
- package/dist/composites/device-item/features.d.ts +17 -0
- package/dist/composites/device-item/header.d.ts +14 -0
- package/dist/composites/device-item/helpers.d.ts +147 -0
- package/dist/composites/device-item/index.d.ts +5 -0
- package/dist/composites/device-item/preview.d.ts +23 -0
- package/dist/composites/device-item/status-dot.d.ts +5 -0
- package/dist/composites/device-list/empty-state.d.ts +6 -0
- package/dist/composites/device-list/filter-chips.d.ts +19 -0
- package/dist/composites/device-list/group.d.ts +6 -0
- package/dist/composites/device-list/index.d.ts +31 -0
- package/dist/composites/device-list/pagination.d.ts +18 -0
- package/dist/composites/device-list/url-state.d.ts +24 -0
- package/dist/composites/discovery-panel.d.ts +26 -0
- package/dist/composites/doorbell-recent-panel.d.ts +10 -0
- package/dist/composites/empty-state.d.ts +10 -0
- package/dist/composites/event-stream.d.ts +48 -0
- package/dist/composites/filter-bar.d.ts +28 -0
- package/dist/composites/form-field.d.ts +11 -0
- package/dist/composites/image-selector.d.ts +25 -0
- package/dist/composites/index.d.ts +99 -0
- package/dist/composites/inference-config-selector.d.ts +44 -0
- package/dist/composites/kebab-menu.d.ts +39 -0
- package/dist/composites/key-value-list.d.ts +9 -0
- package/dist/composites/log-stream.d.ts +61 -0
- package/dist/composites/login-form.d.ts +8 -0
- package/dist/composites/mount-addon-page.d.ts +16 -0
- package/dist/composites/node-picker.d.ts +15 -0
- package/dist/composites/page-header.d.ts +8 -0
- package/dist/composites/phase-icon.d.ts +5 -0
- package/dist/composites/pipeline-builder.d.ts +43 -0
- package/dist/composites/pipeline-runtime-selector.d.ts +16 -0
- package/dist/composites/pipeline-step.d.ts +65 -0
- package/dist/composites/pipeline-tree-matrix.d.ts +31 -0
- package/dist/composites/provider-badge.d.ts +7 -0
- package/dist/composites/ptz-overlay.d.ts +20 -0
- package/dist/composites/response-log.d.ts +9 -0
- package/dist/composites/slide-over-panel.d.ts +11 -0
- package/dist/composites/snapshot-button.d.ts +25 -0
- package/dist/composites/stat-card.d.ts +10 -0
- package/dist/composites/state-values-stream.d.ts +30 -0
- package/dist/composites/status-badge.d.ts +10 -0
- package/dist/composites/step-timings.d.ts +9 -0
- package/dist/composites/step-tree-master.d.ts +28 -0
- package/dist/composites/stream-panel.d.ts +143 -0
- package/dist/composites/version-badge.d.ts +24 -0
- package/dist/composites/widget-slot.d.ts +20 -0
- package/dist/contexts/custom-field-renderers.d.ts +26 -0
- package/dist/contexts/device-context.d.ts +20 -0
- package/dist/contexts/player-overlays.d.ts +56 -0
- package/dist/contexts/system-context.d.ts +19 -0
- package/dist/contexts/widget-registry.d.ts +68 -0
- package/dist/contexts/zone-editing.d.ts +59 -0
- package/dist/generated/system-hooks.d.ts +933 -0
- package/dist/hooks/index.d.ts +27 -0
- package/dist/hooks/use-cluster-nodes.d.ts +17 -0
- package/dist/hooks/use-debounced-string.d.ts +1 -0
- package/dist/hooks/use-device-battery.d.ts +14 -0
- package/dist/hooks/use-device-capability.d.ts +17 -0
- package/dist/hooks/use-device-detections.d.ts +50 -0
- package/dist/hooks/use-device-features.d.ts +25 -0
- package/dist/hooks/use-device-proxy.d.ts +106 -0
- package/dist/hooks/use-device-snapshot.d.ts +10 -0
- package/dist/hooks/use-device-webrtc.d.ts +108 -0
- package/dist/hooks/use-devices.d.ts +13 -0
- package/dist/hooks/use-doorbell-events.d.ts +20 -0
- package/dist/hooks/use-event-invalidation.d.ts +1 -0
- package/dist/hooks/use-event-stream.d.ts +5 -0
- package/dist/hooks/use-is-mobile.d.ts +8 -0
- package/dist/hooks/use-live-buffer.d.ts +8 -0
- package/dist/hooks/use-live-event.d.ts +3 -0
- package/dist/hooks/use-ptz.d.ts +54 -0
- package/dist/hooks/use-system-query.d.ts +12 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons/provider-icons.d.ts +3 -0
- package/dist/icons/status-icons.d.ts +3 -0
- package/dist/index.cjs +23484 -14252
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -3787
- package/dist/index.js +22810 -13741
- package/dist/index.js.map +1 -1
- package/dist/lib/cn.d.ts +2 -0
- package/dist/lib/index.d.ts +8 -0
- package/dist/lib/mf-runtime-init.d.ts +1 -0
- package/dist/lib/phase-config.d.ts +16 -0
- package/dist/lib/pipeline-mirror.d.ts +23 -0
- package/dist/lib/responsive.d.ts +81 -0
- package/dist/lib/shared-context.d.ts +5 -0
- package/dist/lib/validate-template.d.ts +2 -0
- package/dist/primitives/badge.d.ts +11 -0
- package/dist/primitives/bottom-sheet.d.ts +9 -0
- package/dist/primitives/button.d.ts +10 -0
- package/dist/primitives/card.d.ts +9 -0
- package/dist/primitives/checkbox.d.ts +4 -0
- package/dist/primitives/collapsible-card.d.ts +15 -0
- package/dist/primitives/dialog.d.ts +20 -0
- package/dist/primitives/dropdown.d.ts +19 -0
- package/dist/primitives/floating-panel.d.ts +22 -0
- package/dist/primitives/icon-button.d.ts +13 -0
- package/dist/primitives/index.d.ts +21 -0
- package/dist/primitives/input.d.ts +11 -0
- package/dist/primitives/label.d.ts +4 -0
- package/dist/primitives/mobile-drawer.d.ts +10 -0
- package/dist/primitives/popover.d.ts +10 -0
- package/dist/primitives/scroll-area.d.ts +4 -0
- package/dist/primitives/select.d.ts +9 -0
- package/dist/primitives/separator.d.ts +9 -0
- package/dist/primitives/skeleton.d.ts +4 -0
- package/dist/primitives/switch.d.ts +7 -0
- package/dist/primitives/tabs.d.ts +17 -0
- package/dist/primitives/tooltip.d.ts +6 -0
- package/dist/theme/create-theme.d.ts +2 -0
- package/dist/theme/defaults.d.ts +4 -0
- package/dist/theme/index.cjs +228 -248
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.d.ts +6 -128
- package/dist/theme/index.js +212 -214
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/theme-provider.d.ts +10 -0
- package/dist/theme/theme-to-css.d.ts +2 -0
- package/dist/theme/{index.d.cts → types.d.ts} +5 -27
- package/dist/theme/use-theme-mode.d.ts +2 -0
- package/dist/trpc-react.d.ts +7 -0
- package/package.json +5 -3
- package/dist/index.d.cts +0 -3787
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { useIsMobile, useIsMidWidth } from './use-is-mobile';
|
|
2
|
+
export { useDeviceDetections } from './use-device-detections';
|
|
3
|
+
export { useDeviceWebrtc } from './use-device-webrtc';
|
|
4
|
+
export { usePTZ } from './use-ptz';
|
|
5
|
+
export type { UsePTZResult, UsePTZOptions, PTZDirection, PTZTrpcProxy } from './use-ptz';
|
|
6
|
+
export { useDeviceBattery } from './use-device-battery';
|
|
7
|
+
export type { UseDeviceBatteryTrpc } from './use-device-battery';
|
|
8
|
+
export { useDoorbellEvents } from './use-doorbell-events';
|
|
9
|
+
export type { DoorbellPressEvent, UseDoorbellEventsResult, UseDoorbellEventsOptions } from './use-doorbell-events';
|
|
10
|
+
export { useClusterNodes } from './use-cluster-nodes';
|
|
11
|
+
export { useDebouncedString } from './use-debounced-string';
|
|
12
|
+
export { useEventStreamLatest, useEventStreamMap } from './use-event-stream';
|
|
13
|
+
export { useDeviceProxy, useDeviceStateSlice, useDeviceState } from './use-device-proxy';
|
|
14
|
+
export type { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
15
|
+
export { useDeviceCapability } from './use-device-capability';
|
|
16
|
+
export type { UseDeviceCapabilityOptions, UseDeviceCapabilityResult, } from './use-device-capability';
|
|
17
|
+
export { useDeviceSnapshotImage } from './use-device-snapshot';
|
|
18
|
+
export type { DeviceSnapshotImage } from './use-device-snapshot';
|
|
19
|
+
export type { ClusterNode } from './use-cluster-nodes';
|
|
20
|
+
export type { DeviceDetections, MotionState, MotionZone, MotionRawState, MotionRawBox, DetectionState, } from './use-device-detections';
|
|
21
|
+
export type { DeviceWebrtcResult, UseDeviceWebrtcTrpc, DevicePipelineMetrics } from './use-device-webrtc';
|
|
22
|
+
export { useLiveBuffer } from './use-live-buffer';
|
|
23
|
+
export type { LiveBuffer } from './use-live-buffer';
|
|
24
|
+
export { useDevices, useDevice } from './use-devices';
|
|
25
|
+
export { useSystemQuery, useSystemMutation, type SystemQuerySelector, type SystemMutationSelector, } from './use-system-query';
|
|
26
|
+
export { useLiveEvent, type LiveEventCallback } from './use-live-event';
|
|
27
|
+
export { useEventInvalidation } from './use-event-invalidation';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ClusterNode {
|
|
2
|
+
readonly id: string;
|
|
3
|
+
readonly name: string;
|
|
4
|
+
/** Compact label for pill bars: "HUB" for the hub, agent name for agents. */
|
|
5
|
+
readonly shortName: string;
|
|
6
|
+
readonly isHub: boolean;
|
|
7
|
+
readonly isOnline: boolean;
|
|
8
|
+
readonly localIps: readonly string[];
|
|
9
|
+
readonly addons: readonly {
|
|
10
|
+
readonly addonId: string;
|
|
11
|
+
readonly capabilities: readonly string[];
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
export declare function useClusterNodes(): {
|
|
15
|
+
readonly nodes: readonly ClusterNode[];
|
|
16
|
+
readonly isLoading: boolean;
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useDebouncedString(value: string, delayMs: number): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
2
|
+
export interface BatteryStatus {
|
|
3
|
+
readonly percentage: number;
|
|
4
|
+
readonly charging: 'dc' | 'solar' | 'none';
|
|
5
|
+
readonly sleeping: boolean;
|
|
6
|
+
readonly lastUpdated: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Backwards-compatible alias for the trpc shape — historically the
|
|
10
|
+
* hook took its own narrow contract; the proxy generalisation
|
|
11
|
+
* supersedes that.
|
|
12
|
+
*/
|
|
13
|
+
export type UseDeviceBatteryTrpc = UseDeviceProxyTrpc;
|
|
14
|
+
export declare function useDeviceBattery(trpc: UseDeviceProxyTrpc, deviceId: number | null): BatteryStatus | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DeviceProxy, SliceHandle } from '@camstack/types';
|
|
2
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
3
|
+
export interface UseDeviceCapabilityOptions<TCap, TSlice> {
|
|
4
|
+
readonly trpc: UseDeviceProxyTrpc;
|
|
5
|
+
readonly deviceId: number | null;
|
|
6
|
+
readonly cap: (dev: DeviceProxy) => TCap | undefined;
|
|
7
|
+
readonly slice: (dev: DeviceProxy) => SliceHandle<TSlice> | undefined;
|
|
8
|
+
readonly requireFeature?: string;
|
|
9
|
+
readonly deviceFeatures?: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
export interface UseDeviceCapabilityResult<TCap, TSlice> {
|
|
12
|
+
readonly dev: DeviceProxy | null;
|
|
13
|
+
readonly cap: TCap | undefined;
|
|
14
|
+
readonly slice: TSlice | undefined;
|
|
15
|
+
readonly available: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function useDeviceCapability<TCap, TSlice>(options: UseDeviceCapabilityOptions<TCap, TSlice>): UseDeviceCapabilityResult<TCap, TSlice>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ObjectDetection } from '@camstack/types';
|
|
2
|
+
export interface MotionZone {
|
|
3
|
+
readonly x: number;
|
|
4
|
+
readonly y: number;
|
|
5
|
+
readonly w: number;
|
|
6
|
+
readonly h: number;
|
|
7
|
+
readonly intensity: number;
|
|
8
|
+
}
|
|
9
|
+
export interface MotionState {
|
|
10
|
+
readonly zones: readonly MotionZone[];
|
|
11
|
+
readonly frameWidth: number;
|
|
12
|
+
readonly frameHeight: number;
|
|
13
|
+
}
|
|
14
|
+
export interface DetectionState {
|
|
15
|
+
readonly detections: readonly ObjectDetection[];
|
|
16
|
+
readonly frameWidth: number;
|
|
17
|
+
readonly frameHeight: number;
|
|
18
|
+
}
|
|
19
|
+
export interface MotionRawBox {
|
|
20
|
+
readonly bbox: readonly [number, number, number, number];
|
|
21
|
+
readonly changeScore: number;
|
|
22
|
+
}
|
|
23
|
+
export interface MotionRawState {
|
|
24
|
+
readonly boxes: readonly MotionRawBox[];
|
|
25
|
+
readonly frameWidth: number;
|
|
26
|
+
readonly frameHeight: number;
|
|
27
|
+
readonly motionScore: number;
|
|
28
|
+
}
|
|
29
|
+
export interface DeviceDetections {
|
|
30
|
+
readonly motion: MotionState | null;
|
|
31
|
+
readonly motionRaw: MotionRawState | null;
|
|
32
|
+
readonly detection: DetectionState | null;
|
|
33
|
+
readonly phase: string;
|
|
34
|
+
}
|
|
35
|
+
interface LiveOnEvent {
|
|
36
|
+
subscribe: (input: {
|
|
37
|
+
category: string;
|
|
38
|
+
}, opts: {
|
|
39
|
+
onData: (event: unknown) => void;
|
|
40
|
+
}) => {
|
|
41
|
+
unsubscribe: () => void;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
interface UseDetectionsTrpc {
|
|
45
|
+
live?: {
|
|
46
|
+
onEvent?: LiveOnEvent;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export declare function useDeviceDetections(trpc: UseDetectionsTrpc, deviceId: number | null): DeviceDetections;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
2
|
+
export type ResolvedFeatureKind = 'native' | 'enhanced' | 'marker';
|
|
3
|
+
export type ResolvedFeature = {
|
|
4
|
+
readonly kind: 'native';
|
|
5
|
+
readonly feature: string;
|
|
6
|
+
readonly capName: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'enhanced';
|
|
9
|
+
readonly feature: string;
|
|
10
|
+
readonly capName: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly kind: 'marker';
|
|
13
|
+
readonly feature: string;
|
|
14
|
+
};
|
|
15
|
+
export interface UseDeviceFeaturesResult {
|
|
16
|
+
/** Pending or unresolved (during initial bindings fetch). */
|
|
17
|
+
readonly loading: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Resolved list — features whose corresponding cap is in bindings,
|
|
20
|
+
* PLUS pure markers (FEATURE_TO_CAP_NAME has no entry). Features
|
|
21
|
+
* with a cap mapping that is NOT in bindings are filtered out.
|
|
22
|
+
*/
|
|
23
|
+
readonly resolved: readonly ResolvedFeature[];
|
|
24
|
+
}
|
|
25
|
+
export declare function useDeviceFeatures(trpc: UseDeviceProxyTrpc, deviceId: number | null, rawFeatures: readonly string[]): UseDeviceFeaturesResult;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { DeviceBinding, DeviceProxy } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive runtime-state read handle as exposed by the codegen
|
|
4
|
+
* `DeviceProxy` factory. Same shape useDeviceStateSlice expects —
|
|
5
|
+
* defined here so the combinator's selector parameter has a tight
|
|
6
|
+
* type without re-importing the codegen file.
|
|
7
|
+
*/
|
|
8
|
+
interface StateSliceHandle<T> {
|
|
9
|
+
readonly value: T | undefined;
|
|
10
|
+
subscribe(cb: (slice: T | undefined) => void): () => void;
|
|
11
|
+
}
|
|
12
|
+
interface QueryFn<I, O> {
|
|
13
|
+
query(input: I): Promise<O>;
|
|
14
|
+
}
|
|
15
|
+
interface SubscribeFn<I, T> {
|
|
16
|
+
subscribe(input: I, opts: {
|
|
17
|
+
onData: (evt: {
|
|
18
|
+
data: T;
|
|
19
|
+
}) => void;
|
|
20
|
+
onError?: (err: unknown) => void;
|
|
21
|
+
}): {
|
|
22
|
+
unsubscribe: () => void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Minimal vanilla tRPC proxy shape. Same contract `useDeviceWebrtc`,
|
|
27
|
+
* `useDeviceBattery` etc. use — both `BackendClient.trpc` and an
|
|
28
|
+
* addon page's injected `trpc` satisfy this structurally.
|
|
29
|
+
*
|
|
30
|
+
* The proxy is also passed (cast) into `createDeviceProxy` as the
|
|
31
|
+
* `AddonApi` argument — the cap-method dispatchers structurally
|
|
32
|
+
* match `client.<cap>.<method>.{query|mutate|subscribe}`.
|
|
33
|
+
*/
|
|
34
|
+
export interface UseDeviceProxyTrpc {
|
|
35
|
+
readonly deviceManager: {
|
|
36
|
+
readonly getBindings: QueryFn<{
|
|
37
|
+
deviceId: number;
|
|
38
|
+
}, DeviceBinding>;
|
|
39
|
+
};
|
|
40
|
+
readonly live?: {
|
|
41
|
+
readonly onEvent: SubscribeFn<{
|
|
42
|
+
category: string;
|
|
43
|
+
}, {
|
|
44
|
+
category?: string;
|
|
45
|
+
data?: unknown;
|
|
46
|
+
source?: {
|
|
47
|
+
type: string;
|
|
48
|
+
id: string | number;
|
|
49
|
+
};
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @returns the proxy, or `null` while bindings are still loading or
|
|
55
|
+
* when `deviceId` is null. Re-rendered when bindings change.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useDeviceProxy(trpc: UseDeviceProxyTrpc, deviceId: number | null): DeviceProxy | null;
|
|
58
|
+
/**
|
|
59
|
+
* Companion hook — reads a `SliceHandle` reactively, returning the
|
|
60
|
+
* current value and re-rendering on every push from the kernel
|
|
61
|
+
* mirror. Pass `dev?.state.battery` etc. as the handle.
|
|
62
|
+
*
|
|
63
|
+
* const dev = useDeviceProxy(trpc, deviceId)
|
|
64
|
+
* const battery = useDeviceStateSlice(dev?.state.battery)
|
|
65
|
+
*
|
|
66
|
+
* Why a hook (and not just `dev.state.battery.subscribe(...)` inline)?
|
|
67
|
+
* React doesn't observe external mutations on its own — a bare
|
|
68
|
+
* subscribe call inside a render would fire on every render (memory
|
|
69
|
+
* leak), wouldn't trigger a re-render on slice change, and wouldn't
|
|
70
|
+
* clean up at unmount. The hook bridges the imperative
|
|
71
|
+
* `(value, subscribe)` pair into React's declarative lifecycle via
|
|
72
|
+
* `useSyncExternalStore` (the canonical React 18 primitive for
|
|
73
|
+
* external stores — handles tearing in concurrent rendering and
|
|
74
|
+
* de-dups identical pushes).
|
|
75
|
+
*/
|
|
76
|
+
export declare function useDeviceStateSlice<T>(handle: StateSliceHandle<T> | undefined): T | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* One-line combinator — collapse the common
|
|
79
|
+
* `useDeviceProxy + useDeviceStateSlice(dev?.state.<cap>)` pair into a
|
|
80
|
+
* single hook. The selector receives the live `DeviceProxy['state']`
|
|
81
|
+
* bag (typed against the codegen, so `s.battery` etc. autocomplete)
|
|
82
|
+
* and returns one slice handle. Returns the slice value, undefined
|
|
83
|
+
* while the binding resolves OR when the slice has no cached push yet.
|
|
84
|
+
*
|
|
85
|
+
* Idiomatic call-site:
|
|
86
|
+
*
|
|
87
|
+
* const battery = useDeviceState(trpc, deviceId, (s) => s.battery)
|
|
88
|
+
* const zones = useDeviceState(trpc, deviceId, (s) => s.zones)
|
|
89
|
+
*
|
|
90
|
+
* vs. the manual pair:
|
|
91
|
+
*
|
|
92
|
+
* const dev = useDeviceProxy(trpc, deviceId)
|
|
93
|
+
* const battery = useDeviceStateSlice(dev?.state.battery)
|
|
94
|
+
* const zones = useDeviceStateSlice(dev?.state.zones)
|
|
95
|
+
*
|
|
96
|
+
* Use the manual pair when:
|
|
97
|
+
* - you also need the proxy's cap method bag (`dev.zones?.addZone(...)`)
|
|
98
|
+
* - you want to share the proxy across multiple slice reads with a
|
|
99
|
+
* single binding fetch (the combinator calls useDeviceProxy
|
|
100
|
+
* internally, which dedups bindings via React Query in practice
|
|
101
|
+
* but spawns one extra subscription per call site)
|
|
102
|
+
*
|
|
103
|
+
* Use the combinator when reading just one slice — most common case.
|
|
104
|
+
*/
|
|
105
|
+
export declare function useDeviceState<T>(trpc: UseDeviceProxyTrpc, deviceId: number | null, select: (state: DeviceProxy['state']) => StateSliceHandle<T>): T | undefined;
|
|
106
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
2
|
+
export interface DeviceSnapshotImage {
|
|
3
|
+
/** Data-URL for the most recently fetched snapshot, or `null`. */
|
|
4
|
+
readonly src: string | null;
|
|
5
|
+
/** True while a fetch is in flight. */
|
|
6
|
+
readonly loading: boolean;
|
|
7
|
+
/** Force the next fetch to bypass cache (single use). */
|
|
8
|
+
readonly refresh: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function useDeviceSnapshotImage(trpc: UseDeviceProxyTrpc, deviceId: number | null): DeviceSnapshotImage;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { StreamChoice } from '../composites/stream-panel';
|
|
2
|
+
import { ClientStreamHints, SignalingResult } from '../composites/camera-stream-player';
|
|
3
|
+
/**
|
|
4
|
+
* Discriminated WebRTC target — same shape as `WebrtcStreamTarget` on
|
|
5
|
+
* the backend cap. Repeated locally to keep the hook self-contained
|
|
6
|
+
* (no cross-package import from `@camstack/types`).
|
|
7
|
+
*/
|
|
8
|
+
export type WebrtcTarget = {
|
|
9
|
+
readonly kind: 'adaptive';
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: 'profile';
|
|
12
|
+
readonly profile: 'high' | 'mid' | 'low';
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'cam-stream';
|
|
15
|
+
readonly camStreamId: string;
|
|
16
|
+
};
|
|
17
|
+
/** Mutation call shape: `.mutate(input)` → Promise. */
|
|
18
|
+
interface MutateFn<I, O> {
|
|
19
|
+
mutate(input: I): Promise<O>;
|
|
20
|
+
}
|
|
21
|
+
/** Query call shape: `.query(input?)` → Promise. */
|
|
22
|
+
interface QueryFn<I, O> {
|
|
23
|
+
query(input: I): Promise<O>;
|
|
24
|
+
}
|
|
25
|
+
interface StreamChoiceRow {
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly target: WebrtcTarget;
|
|
29
|
+
readonly codec: string | null;
|
|
30
|
+
readonly resolution: {
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
} | null;
|
|
34
|
+
readonly status: string | null;
|
|
35
|
+
readonly inputFps: number | null;
|
|
36
|
+
readonly decodeFps: number | null;
|
|
37
|
+
readonly bitrateKbps: number | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Minimal subset of the tRPC proxy needed for WebRTC signaling.
|
|
41
|
+
* Both `BackendClient.trpc` and `AddonPageProps['trpc']` satisfy this
|
|
42
|
+
* at runtime.
|
|
43
|
+
*/
|
|
44
|
+
export interface UseDeviceWebrtcTrpc {
|
|
45
|
+
webrtcSession: {
|
|
46
|
+
listStreams: QueryFn<{
|
|
47
|
+
deviceId: number;
|
|
48
|
+
}, readonly StreamChoiceRow[]>;
|
|
49
|
+
createSession: MutateFn<{
|
|
50
|
+
deviceId: number;
|
|
51
|
+
target: WebrtcTarget;
|
|
52
|
+
hints?: ClientStreamHints;
|
|
53
|
+
}, {
|
|
54
|
+
sessionId: string;
|
|
55
|
+
sdpOffer: string;
|
|
56
|
+
}>;
|
|
57
|
+
handleAnswer: MutateFn<{
|
|
58
|
+
deviceId: number;
|
|
59
|
+
sessionId: string;
|
|
60
|
+
sdpAnswer: string;
|
|
61
|
+
}, void>;
|
|
62
|
+
closeSession: MutateFn<{
|
|
63
|
+
deviceId: number;
|
|
64
|
+
sessionId: string;
|
|
65
|
+
}, void>;
|
|
66
|
+
};
|
|
67
|
+
pipelineOrchestrator?: {
|
|
68
|
+
getCameraMetrics: QueryFn<{
|
|
69
|
+
deviceId: number;
|
|
70
|
+
}, {
|
|
71
|
+
phase: string;
|
|
72
|
+
actualFps: number;
|
|
73
|
+
avgInferenceTimeMs: number;
|
|
74
|
+
droppedFrames: number;
|
|
75
|
+
configuredFps: number;
|
|
76
|
+
} | null>;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Pipeline detection metrics for a device. */
|
|
80
|
+
export interface DevicePipelineMetrics {
|
|
81
|
+
readonly phase: string;
|
|
82
|
+
readonly detectionFps: number;
|
|
83
|
+
readonly avgInferenceMs: number;
|
|
84
|
+
readonly droppedFrames: number;
|
|
85
|
+
}
|
|
86
|
+
export interface DeviceWebrtcResult {
|
|
87
|
+
/** Available stream choices for the dropdown (Adaptive + assigned profiles). */
|
|
88
|
+
readonly streams: readonly StreamChoice[];
|
|
89
|
+
/** Whether the device has at least one assigned profile (can stream). */
|
|
90
|
+
readonly hasWebrtc: boolean;
|
|
91
|
+
/** Live pipeline metrics (phase, detection fps, inference time). */
|
|
92
|
+
readonly pipelineMetrics: DevicePipelineMetrics | null;
|
|
93
|
+
/** Server-offer signaling: create a WebRTC session. */
|
|
94
|
+
readonly createSession: (target: WebrtcTarget, hints?: ClientStreamHints) => Promise<SignalingResult>;
|
|
95
|
+
/** Server-offer signaling: send the client's SDP answer. */
|
|
96
|
+
readonly sendAnswer: (sessionId: string, sdpAnswer: string) => Promise<void>;
|
|
97
|
+
/** Close a WebRTC session on the server. */
|
|
98
|
+
readonly closeSession: (sessionId: string) => Promise<void>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Hook that provides WebRTC signaling callbacks and stream choices for a device.
|
|
102
|
+
*
|
|
103
|
+
* @param trpc - tRPC proxy (admin-ui BackendClient.trpc or addon page trpc)
|
|
104
|
+
* @param deviceId - numeric device ID (null = disabled)
|
|
105
|
+
* @param pollIntervalMs - how often to refresh profile slots (default: 5000)
|
|
106
|
+
*/
|
|
107
|
+
export declare function useDeviceWebrtc(trpc: UseDeviceWebrtcTrpc, deviceId: number | null, pollIntervalMs?: number): DeviceWebrtcResult;
|
|
108
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DeviceProxy, DeviceQueryFilters } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* Reactive list of devices matching the optional filter set. Returns a
|
|
4
|
+
* stable array reference between updates so consumers passing it as a
|
|
5
|
+
* prop don't tear down memoized children.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useDevices(filters?: DeviceQueryFilters): readonly DeviceProxy[];
|
|
8
|
+
/**
|
|
9
|
+
* Single-device variant. Returns `null` until the device is in the
|
|
10
|
+
* mirror; re-renders when the device is removed (back to `null`) or
|
|
11
|
+
* added.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useDevice(deviceId: number | null): DeviceProxy | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface DoorbellPressEvent {
|
|
2
|
+
readonly deviceId: number;
|
|
3
|
+
readonly timestamp: number;
|
|
4
|
+
}
|
|
5
|
+
export interface UseDoorbellEventsResult {
|
|
6
|
+
/** Most recent press, or null if none observed since mount. */
|
|
7
|
+
readonly latest: DoorbellPressEvent | null;
|
|
8
|
+
/** Recent presses, newest-first. Capped at `historyLimit`. */
|
|
9
|
+
readonly history: readonly DoorbellPressEvent[];
|
|
10
|
+
}
|
|
11
|
+
export interface UseDoorbellEventsOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Scope the subscription to a specific deviceId. Pass `null` (or
|
|
14
|
+
* omit) to receive every press across the cluster.
|
|
15
|
+
*/
|
|
16
|
+
readonly deviceId?: number | null;
|
|
17
|
+
/** Max history entries kept in memory. Defaults to 20. */
|
|
18
|
+
readonly historyLimit?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare function useDoorbellEvents(options?: UseDoorbellEventsOptions): UseDoorbellEventsResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useEventInvalidation(queryKey: readonly unknown[], categories: readonly string[]): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function useEventStreamLatest<T>(category: string, filter?: (data: T) => boolean): T | null;
|
|
2
|
+
export declare function useEventStreamMap<T, K extends string | number>(category: string, keyOf: (data: T) => K, filter?: (data: T) => boolean): {
|
|
3
|
+
readonly map: ReadonlyMap<K, T>;
|
|
4
|
+
readonly values: readonly T[];
|
|
5
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function useIsMobile(): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* True when the viewport is in the medium (`md`) Tailwind range —
|
|
4
|
+
* 768px ≤ width < 1024px. Use to drive layouts that should pack denser
|
|
5
|
+
* than full-desktop but more legibly than mobile (e.g. icons-only
|
|
6
|
+
* sidebar rail, narrower stat tiles).
|
|
7
|
+
*/
|
|
8
|
+
export declare function useIsMidWidth(): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface LiveBuffer<T> {
|
|
2
|
+
readonly entries: readonly T[];
|
|
3
|
+
/** Append one entry; oldest is evicted past `max`. */
|
|
4
|
+
readonly append: (entry: T) => void;
|
|
5
|
+
/** Replace all entries — used by Clear / scope-change resets. */
|
|
6
|
+
readonly reset: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function useLiveBuffer<T>(max: number): LiveBuffer<T>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { UseDeviceProxyTrpc } from './use-device-proxy';
|
|
2
|
+
/**
|
|
3
|
+
* Cardinal + intercardinal direction tokens. The hook translates them
|
|
4
|
+
* into normalised `(pan, tilt)` vectors before calling the underlying
|
|
5
|
+
* cap so the cap surface stays speed-vector-shaped.
|
|
6
|
+
*/
|
|
7
|
+
export type PTZDirection = 'up' | 'down' | 'left' | 'right' | 'up-left' | 'up-right' | 'down-left' | 'down-right';
|
|
8
|
+
interface PTZPreset {
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly name: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Backwards-compatible alias for the trpc shape — historically the
|
|
14
|
+
* hook took its own narrow contract; the proxy generalisation
|
|
15
|
+
* supersedes that.
|
|
16
|
+
*/
|
|
17
|
+
export type PTZTrpcProxy = UseDeviceProxyTrpc;
|
|
18
|
+
export interface UsePTZOptions {
|
|
19
|
+
/** Default speed (0..1) for moves when the caller omits one. */
|
|
20
|
+
readonly defaultSpeed?: number;
|
|
21
|
+
/** Pulse duration (ms) for one-shot `move` calls. */
|
|
22
|
+
readonly pulseMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Gate the hook's network calls. When `false`, the initial preset
|
|
25
|
+
* refresh is skipped and every method becomes a no-op. Use to avoid
|
|
26
|
+
* "provider not available" errors on devices that don't advertise
|
|
27
|
+
* the `ptz` capability.
|
|
28
|
+
*/
|
|
29
|
+
readonly enabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface UsePTZResult {
|
|
32
|
+
/** One-shot directional pulse. Stops itself after `pulseMs`. */
|
|
33
|
+
readonly move: (direction: PTZDirection, speed?: number) => Promise<void>;
|
|
34
|
+
/** Begin continuous motion in `direction` until `stopContinuous` is called. */
|
|
35
|
+
readonly startContinuous: (direction: PTZDirection, speed?: number) => Promise<void>;
|
|
36
|
+
/** Stop any ongoing continuous motion. Idempotent. */
|
|
37
|
+
readonly stopContinuous: () => Promise<void>;
|
|
38
|
+
/** Discrete zoom step (in or out). */
|
|
39
|
+
readonly zoom: (direction: 'in' | 'out', speed?: number) => Promise<void>;
|
|
40
|
+
/** Jump to the home preset (0 on most cameras). */
|
|
41
|
+
readonly goHome: () => Promise<void>;
|
|
42
|
+
/** Jump to a named preset. */
|
|
43
|
+
readonly goToPreset: (presetId: string) => Promise<void>;
|
|
44
|
+
/** List of presets reported by the camera. Empty until first refresh. */
|
|
45
|
+
readonly presets: readonly PTZPreset[];
|
|
46
|
+
/** Force a refresh of the presets list. */
|
|
47
|
+
readonly refreshPresets: () => Promise<void>;
|
|
48
|
+
/** True while a control call is in flight (any path). */
|
|
49
|
+
readonly busy: boolean;
|
|
50
|
+
/** Last error message from any cap call, or null. */
|
|
51
|
+
readonly error: string | null;
|
|
52
|
+
}
|
|
53
|
+
export declare function usePTZ(trpc: UseDeviceProxyTrpc, deviceId: number, options?: UsePTZOptions): UsePTZResult;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { QueryKey, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
|
|
2
|
+
import { System } from '@camstack/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* `select` MUST return a thunk that, when invoked, performs the
|
|
5
|
+
* request. Two-step factory keeps the query-key + thunk identities
|
|
6
|
+
* stable between renders: the hook re-creates the thunk on every
|
|
7
|
+
* render (cheap), but React Query keys off `[queryKey]` only.
|
|
8
|
+
*/
|
|
9
|
+
export type SystemQuerySelector<TData> = (system: System) => () => Promise<TData>;
|
|
10
|
+
export type SystemMutationSelector<TInput, TData> = (system: System) => (input: TInput) => Promise<TData>;
|
|
11
|
+
export declare function useSystemQuery<TData>(queryKey: QueryKey, select: SystemQuerySelector<TData>, opts?: Omit<UseQueryOptions<TData, Error, TData>, 'queryKey' | 'queryFn'>): UseQueryResult<TData, Error>;
|
|
12
|
+
export declare function useSystemMutation<TInput, TData>(select: SystemMutationSelector<TInput, TData>, opts?: Omit<UseMutationOptions<TData, Error, TInput>, 'mutationFn'>): UseMutationResult<TData, Error, TInput>;
|