@camstack/types 0.1.1 → 0.1.3
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/__tests__/addon-capability-provider.test.d.ts +2 -0
- package/dist/__tests__/addon-capability-provider.test.d.ts.map +1 -0
- package/dist/__tests__/addon-declaration.test.d.ts +2 -0
- package/dist/__tests__/addon-declaration.test.d.ts.map +1 -0
- package/dist/__tests__/capability.test.d.ts +2 -0
- package/dist/__tests__/capability.test.d.ts.map +1 -0
- package/dist/catalogs/coco-classmap.d.ts +5 -0
- package/dist/catalogs/coco-classmap.d.ts.map +1 -0
- package/dist/catalogs/index.d.ts +2 -0
- package/dist/catalogs/index.d.ts.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/generated/addon-api.d.ts +4870 -0
- package/dist/generated/addon-api.d.ts.map +1 -0
- package/dist/index.d.ts +82 -3053
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +377 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +369 -7
- package/dist/index.mjs.map +1 -1
- package/dist/interfaces/addon-i18n.d.ts +41 -0
- package/dist/interfaces/addon-i18n.d.ts.map +1 -0
- package/dist/interfaces/addon-routes.d.ts +50 -0
- package/dist/interfaces/addon-routes.d.ts.map +1 -0
- package/dist/interfaces/addon.d.ts +294 -0
- package/dist/interfaces/addon.d.ts.map +1 -0
- package/dist/interfaces/advanced-notifier.d.ts +59 -0
- package/dist/interfaces/advanced-notifier.d.ts.map +1 -0
- package/dist/interfaces/agent-protocol.d.ts +189 -0
- package/dist/interfaces/agent-protocol.d.ts.map +1 -0
- package/dist/interfaces/agent.d.ts +87 -0
- package/dist/interfaces/agent.d.ts.map +1 -0
- package/dist/interfaces/analysis-persistence.d.ts +278 -0
- package/dist/interfaces/analysis-persistence.d.ts.map +1 -0
- package/dist/interfaces/analysis.d.ts +27 -0
- package/dist/interfaces/analysis.d.ts.map +1 -0
- package/dist/interfaces/api-shared.d.ts +168 -0
- package/dist/interfaces/api-shared.d.ts.map +1 -0
- package/dist/interfaces/auth-provider.d.ts +39 -0
- package/dist/interfaces/auth-provider.d.ts.map +1 -0
- package/dist/interfaces/auth.d.ts +47 -0
- package/dist/interfaces/auth.d.ts.map +1 -0
- package/dist/interfaces/camera-pipeline.d.ts +121 -0
- package/dist/interfaces/camera-pipeline.d.ts.map +1 -0
- package/dist/interfaces/capability.d.ts +84 -0
- package/dist/interfaces/capability.d.ts.map +1 -0
- package/dist/interfaces/classifier.d.ts +8 -0
- package/dist/interfaces/classifier.d.ts.map +1 -0
- package/dist/interfaces/config-ui.d.ts +152 -0
- package/dist/interfaces/config-ui.d.ts.map +1 -0
- package/dist/interfaces/context.d.ts +44 -0
- package/dist/interfaces/context.d.ts.map +1 -0
- package/dist/interfaces/cropper.d.ts +8 -0
- package/dist/interfaces/cropper.d.ts.map +1 -0
- package/dist/interfaces/decoder.d.ts +27 -0
- package/dist/interfaces/decoder.d.ts.map +1 -0
- package/dist/interfaces/detection-addon.d.ts +15 -0
- package/dist/interfaces/detection-addon.d.ts.map +1 -0
- package/dist/interfaces/detector.d.ts +8 -0
- package/dist/interfaces/detector.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/accessory.d.ts +14 -0
- package/dist/interfaces/device-capabilities/accessory.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/audio-detector.d.ts +12 -0
- package/dist/interfaces/device-capabilities/audio-detector.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/camera.d.ts +22 -0
- package/dist/interfaces/device-capabilities/camera.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/doorbell.d.ts +10 -0
- package/dist/interfaces/device-capabilities/doorbell.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/events.d.ts +47 -0
- package/dist/interfaces/device-capabilities/events.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/index.d.ts +15 -0
- package/dist/interfaces/device-capabilities/index.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/motion-sensor.d.ts +7 -0
- package/dist/interfaces/device-capabilities/motion-sensor.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/native-detection.d.ts +14 -0
- package/dist/interfaces/device-capabilities/native-detection.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/object-detector.d.ts +59 -0
- package/dist/interfaces/device-capabilities/object-detector.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/pan-tilt-zoom.d.ts +29 -0
- package/dist/interfaces/device-capabilities/pan-tilt-zoom.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/recording.d.ts +18 -0
- package/dist/interfaces/device-capabilities/recording.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/siren.d.ts +8 -0
- package/dist/interfaces/device-capabilities/siren.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/status-light.d.ts +7 -0
- package/dist/interfaces/device-capabilities/status-light.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/switch.d.ts +8 -0
- package/dist/interfaces/device-capabilities/switch.d.ts.map +1 -0
- package/dist/interfaces/device-capabilities/two-way-audio.d.ts +8 -0
- package/dist/interfaces/device-capabilities/two-way-audio.d.ts.map +1 -0
- package/dist/interfaces/device-capability.d.ts +14 -0
- package/dist/interfaces/device-capability.d.ts.map +1 -0
- package/dist/interfaces/device-provider.d.ts +43 -0
- package/dist/interfaces/device-provider.d.ts.map +1 -0
- package/dist/interfaces/device.d.ts +40 -0
- package/dist/interfaces/device.d.ts.map +1 -0
- package/dist/interfaces/event-bus.d.ts +22 -0
- package/dist/interfaces/event-bus.d.ts.map +1 -0
- package/dist/interfaces/feature-flags.d.ts +14 -0
- package/dist/interfaces/feature-flags.d.ts.map +1 -0
- package/dist/interfaces/ffmpeg.d.ts +10 -0
- package/dist/interfaces/ffmpeg.d.ts.map +1 -0
- package/dist/interfaces/inference-capabilities.d.ts +101 -0
- package/dist/interfaces/inference-capabilities.d.ts.map +1 -0
- package/dist/interfaces/inference-engine.d.ts +17 -0
- package/dist/interfaces/inference-engine.d.ts.map +1 -0
- package/dist/interfaces/lifecycle.d.ts +19 -0
- package/dist/interfaces/lifecycle.d.ts.map +1 -0
- package/dist/interfaces/logging.d.ts +33 -0
- package/dist/interfaces/logging.d.ts.map +1 -0
- package/dist/interfaces/model-catalog.d.ts +25 -0
- package/dist/interfaces/model-catalog.d.ts.map +1 -0
- package/dist/interfaces/network-quality.d.ts +25 -0
- package/dist/interfaces/network-quality.d.ts.map +1 -0
- package/dist/interfaces/network.d.ts +43 -0
- package/dist/interfaces/network.d.ts.map +1 -0
- package/dist/interfaces/notification.d.ts +53 -0
- package/dist/interfaces/notification.d.ts.map +1 -0
- package/dist/interfaces/pipeline-runner.d.ts +23 -0
- package/dist/interfaces/pipeline-runner.d.ts.map +1 -0
- package/dist/interfaces/pipeline-slot.d.ts +10 -0
- package/dist/interfaces/pipeline-slot.d.ts.map +1 -0
- package/dist/interfaces/platform.d.ts +55 -0
- package/dist/interfaces/platform.d.ts.map +1 -0
- package/dist/interfaces/process.d.ts +41 -0
- package/dist/interfaces/process.d.ts.map +1 -0
- package/dist/interfaces/python-env.d.ts +20 -0
- package/dist/interfaces/python-env.d.ts.map +1 -0
- package/dist/interfaces/refiner.d.ts +8 -0
- package/dist/interfaces/refiner.d.ts.map +1 -0
- package/dist/interfaces/repl.d.ts +26 -0
- package/dist/interfaces/repl.d.ts.map +1 -0
- package/dist/interfaces/repositories.d.ts +20 -0
- package/dist/interfaces/repositories.d.ts.map +1 -0
- package/dist/interfaces/restreamer.d.ts +24 -0
- package/dist/interfaces/restreamer.d.ts.map +1 -0
- package/dist/interfaces/router.d.ts +30 -0
- package/dist/interfaces/router.d.ts.map +1 -0
- package/dist/interfaces/scene-intelligence.d.ts +21 -0
- package/dist/interfaces/scene-intelligence.d.ts.map +1 -0
- package/dist/interfaces/scoped-token.d.ts +22 -0
- package/dist/interfaces/scoped-token.d.ts.map +1 -0
- package/dist/interfaces/server-analysis.d.ts +146 -0
- package/dist/interfaces/server-analysis.d.ts.map +1 -0
- package/dist/interfaces/server-network.d.ts +78 -0
- package/dist/interfaces/server-network.d.ts.map +1 -0
- package/dist/interfaces/storage-backend.d.ts +27 -0
- package/dist/interfaces/storage-backend.d.ts.map +1 -0
- package/dist/interfaces/storage.d.ts +174 -0
- package/dist/interfaces/storage.d.ts.map +1 -0
- package/dist/interfaces/stream-broker.d.ts +92 -0
- package/dist/interfaces/stream-broker.d.ts.map +1 -0
- package/dist/interfaces/streaming.d.ts +29 -0
- package/dist/interfaces/streaming.d.ts.map +1 -0
- package/dist/interfaces/task-handler.d.ts +46 -0
- package/dist/interfaces/task-handler.d.ts.map +1 -0
- package/dist/interfaces/webrtc-provider.d.ts +11 -0
- package/dist/interfaces/webrtc-provider.d.ts.map +1 -0
- package/dist/interfaces/worker-protocol.d.ts +110 -0
- package/dist/interfaces/worker-protocol.d.ts.map +1 -0
- package/dist/schemas/system-settings-schemas.d.ts +27 -0
- package/dist/schemas/system-settings-schemas.d.ts.map +1 -0
- package/dist/types/analytics.d.ts +75 -0
- package/dist/types/analytics.d.ts.map +1 -0
- package/dist/types/benchmark.d.ts +112 -0
- package/dist/types/benchmark.d.ts.map +1 -0
- package/dist/types/camera-detection.d.ts +34 -0
- package/dist/types/camera-detection.d.ts.map +1 -0
- package/dist/types/config.d.ts +37 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/detection.d.ts +93 -0
- package/dist/types/detection.d.ts.map +1 -0
- package/dist/types/device-type.d.ts +10 -0
- package/dist/types/device-type.d.ts.map +1 -0
- package/dist/types/entities.d.ts +35 -0
- package/dist/types/entities.d.ts.map +1 -0
- package/dist/types/events.d.ts +35 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/io.d.ts +25 -0
- package/dist/types/io.d.ts.map +1 -0
- package/dist/types/labels.d.ts +12 -0
- package/dist/types/labels.d.ts.map +1 -0
- package/dist/types/live-state.d.ts +47 -0
- package/dist/types/live-state.d.ts.map +1 -0
- package/dist/types/models.d.ts +79 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/pipeline-schema.d.ts +78 -0
- package/dist/types/pipeline-schema.d.ts.map +1 -0
- package/dist/types/pipeline.d.ts +42 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/tracked.d.ts +21 -0
- package/dist/types/tracked.d.ts.map +1 -0
- package/dist/types/zones.d.ts +48 -0
- package/dist/types/zones.d.ts.map +1 -0
- package/dist/utils/cosine-similarity.d.ts +3 -0
- package/dist/utils/cosine-similarity.d.ts.map +1 -0
- package/dist/utils/hf-url.d.ts +2 -0
- package/dist/utils/hf-url.d.ts.map +1 -0
- package/package.json +16 -5
- package/dist/index.d.mts +0 -3053
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/interfaces/storage-backend.ts","../src/interfaces/feature-flags.ts","../src/interfaces/agent-protocol.ts","../src/interfaces/server-analysis.ts","../src/interfaces/analysis-persistence.ts","../src/constants.ts","../src/utils/hf-url.ts","../src/utils/cosine-similarity.ts","../src/catalogs/coco-classmap.ts"],"sourcesContent":["import type { StorageLocationName } from './storage.js'\n\n/**\n * Abstract storage backend -- resolves subpaths to absolute filesystem paths.\n */\nexport interface IStorageBackend {\n /** Backend type identifier */\n readonly type: string\n\n /** Base path of this backend */\n readonly basePath: string\n\n /** Resolve a subpath to an absolute path */\n resolve(subpath: string): string\n /** Also support location-based resolution */\n resolve(location: StorageLocationName, ...segments: string[]): string\n\n /** Check if the backend path exists and is writable */\n isAvailable(location?: StorageLocationName): boolean\n\n /** Ensure base directory exists (mkdir -p equivalent) */\n initialize(): Promise<void>\n\n /** Get the absolute path for a named storage location */\n getLocationPath?(location: StorageLocationName): string\n}\n\n/** @deprecated Use IStorageProvider from storage.ts instead */\nexport interface IStorageProviderLegacy {\n getLocation(name: string): string\n setLocationPath?(name: StorageLocationName, absolutePath: string): void\n}\n\n/** Configuration for a storage location */\nexport interface StorageLocationConfig {\n readonly name: string\n readonly basePath: string\n readonly backendType?: string\n}\n\n/** Default storage location paths, relative to dataPath */\nexport const DEFAULT_LOCATION_SUBPATHS: Record<string, string> = {\n data: 'db',\n media: 'media',\n recordings: 'recordings',\n models: 'models',\n cache: '/tmp/camstack-cache',\n logs: 'logs',\n}\n","export interface FeatureManifest {\n streaming: boolean\n notifications: boolean\n objectDetection: boolean\n remoteAccess: boolean\n agentCluster: boolean\n smartHome: boolean\n recordings: boolean\n backup: boolean\n repl: boolean\n}\n\nexport type FeatureFlag = keyof FeatureManifest\n\nexport const DEFAULT_FEATURES: FeatureManifest = {\n streaming: true,\n notifications: true,\n objectDetection: false,\n remoteAccess: true,\n agentCluster: false,\n smartHome: true,\n recordings: true,\n backup: true,\n repl: true,\n}\n","import type { TaskProgress } from './task-handler.js'\n\n// --- Agent capabilities & roles ---\nexport type AgentCapability = 'decoder' | 'transcoder' | 'detector' | 'recorder'\nexport type RolePriority = 'primary' | 'backup' | 'overflow'\n\nexport interface CameraRoleAssignment {\n cameraId: string\n role: AgentCapability\n agentId: string\n priority: RolePriority\n rtspUrl?: string\n detectionConfig?: {\n modelId: string\n runtime: string\n confidence: number\n fps: number\n classes?: string[]\n }\n}\n\n// --- Hub -> Agent messages ---\nexport type HubToAgentMessage =\n | { type: 'assign'; assignment: CameraRoleAssignment }\n | { type: 'unassign'; cameraId: string; role: AgentCapability }\n | { type: 'recording.start'; cameraId: string; rtspUrl: string }\n | { type: 'recording.stop'; cameraId: string }\n | { type: 'benchmark.run'; config: RemoteBenchmarkConfig }\n | { type: 'config.update'; addonId: string; config: Record<string, unknown> }\n | { type: 'task.execute'; taskId: string; taskType: string; payload: unknown }\n | { type: 'task.cancel'; taskId: string }\n | { type: 'addon.install'; package: string; version?: string }\n | { type: 'addon.uninstall'; package: string }\n | { type: 'addon.update'; package: string; version?: string }\n | { type: 'addon.restart' }\n | { type: 'ping' }\n\n// --- Agent -> Hub messages ---\nexport type AgentToHubMessage =\n | { type: 'register'; info: AgentRegistrationInfo }\n | { type: 'heartbeat'; status: AgentRuntimeStatus }\n | { type: 'detection.result'; cameraId: string; detections: DetectionResult[]; timestamp: number; inferenceMs: number }\n | { type: 'recording.segment'; cameraId: string; segment: RecordingSegmentInfo }\n | { type: 'recording.status'; cameraId: string; recording: boolean }\n | { type: 'benchmark.progress'; event: BenchmarkStreamEvent }\n | { type: 'benchmark.result'; report: BenchmarkReport }\n | { type: 'task.result'; taskId: string; success: boolean; result?: unknown; error?: string }\n | { type: 'task.progress'; taskId: string; progress: TaskProgress }\n | { type: 'addon.install-result'; package: string; success: boolean; version?: string; error?: string }\n | { type: 'addon.uninstall-result'; package: string; success: boolean; error?: string }\n | { type: 'addon.update-result'; package: string; success: boolean; version?: string; error?: string }\n | { type: 'log'; level: string; scope: string; message: string }\n | { type: 'pong' }\n\n// --- Binary frame header (29 bytes) ---\nexport const BINARY_FRAME_HEADER_SIZE = 29\nexport const BINARY_FRAME_TYPE = 0x01\n\nexport interface AgentRegistrationInfo {\n id: string\n name: string\n capabilities: AgentCapability[]\n host: string\n port: number\n platform: string\n arch: string\n cpuCores: number\n memoryMB: number\n gpuModel?: string\n pythonRuntimes: string[]\n httpPort: number\n /** Task types this agent can handle (e.g., 'pipeline.decode', 'system.info') */\n taskTypes?: string[]\n /** Installed addons on this agent */\n installedAddons?: string[]\n}\n\nexport interface AgentRuntimeStatus {\n activeCameras: number\n cpuPercent: number\n memoryPercent: number\n fps: Record<string, number>\n errors: string[]\n}\n\nexport interface DetectionResult {\n className: string\n score: number\n bbox: [number, number, number, number]\n}\n\nexport interface RecordingSegmentInfo {\n id: string\n startTime: number\n endTime: number\n duration: number\n sizeBytes: number\n path: string\n format: 'mp4' | 'ts'\n}\n\nexport interface RemoteBenchmarkConfig {\n runtime: string\n modelId?: string\n durationMs: number\n warmupMs: number\n inputWidth: number\n inputHeight: number\n}\n\nexport interface BenchmarkStreamEvent {\n phase: 'warmup' | 'running'\n iteration: number\n inferenceMs: number\n}\n\nexport interface BenchmarkReport {\n runtime: string\n modelId?: string\n iterations: number\n meanMs: number\n p50Ms: number\n p95Ms: number\n p99Ms: number\n minMs: number\n maxMs: number\n}\n","/**\n * Detection Analysis Pipeline -- processes raw detections through\n * configurable stages to produce tracked, enriched, actionable events.\n */\n\nimport type { Detection } from './device-capabilities/object-detector.js'\nimport type { VideoFrame } from './camera-pipeline.js'\n\n// --- Detection type const unions ---\n\nexport const DETECTION_TYPES = ['person', 'vehicle', 'animal', 'package'] as const\nexport type DetectionType = typeof DETECTION_TYPES[number]\n\nexport const SUB_DETECTION_TYPES = ['face', 'plate'] as const\nexport type SubDetectionType = typeof SUB_DETECTION_TYPES[number]\n\nexport const RECOGNITION_TYPES = ['face', 'plate', 'clip', 'custom'] as const\nexport type RecognitionType = typeof RECOGNITION_TYPES[number]\n\n// --- Analysis Context ---\n\nexport interface AnalysisContext {\n readonly deviceId: string\n readonly frame: VideoFrame\n readonly timestamp: number\n readonly rawDetections: readonly Detection[]\n readonly trackedDetections: readonly ServerTrackedDetection[]\n readonly events: readonly AnalysisEvent[]\n readonly metadata: Readonly<Record<string, unknown>>\n}\n\n// --- Tracked Detection ---\n\nexport interface ServerTrackedDetection {\n readonly trackId: string\n readonly detection: Detection\n readonly crop?: Buffer\n readonly tracking: TrackingInfo\n readonly subDetections: readonly SubDetection[]\n readonly recognitions: readonly RecognitionResult[]\n readonly zones: readonly string[]\n readonly previousZones: readonly string[]\n}\n\nexport interface TrackingInfo {\n readonly age: number\n readonly state: 'moving' | 'stationary' | 'new' | 'lost'\n readonly stationaryDuration: number\n readonly velocity: { readonly dx: number; readonly dy: number }\n readonly positionHistory: ReadonlyArray<{ readonly x: number; readonly y: number; readonly t: number }>\n}\n\n// --- Sub-Detection ---\n\nexport interface SubDetection {\n readonly detectionType: SubDetectionType\n readonly boundingBox: readonly [number, number, number, number]\n readonly score: number\n readonly crop?: Buffer\n}\n\n// --- Recognition ---\n\nexport interface RecognitionResult {\n readonly recognitionType: RecognitionType\n readonly label: string\n readonly score: number\n readonly embedding?: readonly number[]\n readonly metadata?: Readonly<Record<string, unknown>>\n}\n\n// --- Analysis Events ---\n\nexport interface AnalysisEvent {\n readonly category: string\n readonly severity: 'info' | 'warning' | 'alert'\n readonly detection: ServerTrackedDetection\n readonly description: string\n readonly data: Readonly<Record<string, unknown>>\n}\n\n// --- Analysis Stage ---\n\nexport interface IAnalysisStage {\n readonly id: string\n readonly name: string\n readonly priority: number\n enabled: boolean\n process(ctx: AnalysisContext): Promise<AnalysisContext>\n}\n\n// --- Sub-Detector Interface ---\n\nexport interface ISubDetector {\n readonly detectionType: SubDetectionType\n readonly targetClasses: readonly string[]\n detect(crop: Buffer, cropWidth: number, cropHeight: number): Promise<SubDetection[]>\n}\n\nexport interface IFaceDetector extends ISubDetector {\n readonly detectionType: 'face'\n}\n\nexport interface IPlateDetector extends ISubDetector {\n readonly detectionType: 'plate'\n}\n\n// --- Recognizer Interface ---\n\nexport interface IRecognizer {\n readonly recognitionType: RecognitionType\n recognize(crop: Buffer, width: number, height: number): Promise<RecognitionResult | null>\n}\n\nexport interface IFaceRecognizer extends IRecognizer {\n getEmbedding(crop: Buffer): Promise<Float32Array>\n registerKnown(label: string, embedding: Float32Array): void\n}\n\nexport interface IPlateRecognizer extends IRecognizer {\n readonly recognitionType: 'plate'\n}\n\n// --- Audio Classifier ---\n\nexport interface IAudioClassifier {\n readonly ready: boolean\n initialize(): Promise<void>\n classify(\n audioSamples: Float32Array,\n sampleRate: number,\n topN?: number,\n ): Promise<readonly AudioClassification[]>\n release(): Promise<void>\n}\n\nexport interface AudioClassification {\n readonly classIndex: number\n readonly className: string\n readonly score: number\n readonly isSurveillanceRelevant: boolean\n}\n\n// --- Pipeline Stage Interfaces ---\n\nexport interface IClassFilterStage extends IAnalysisStage {\n readonly id: 'class-filter'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n getConfig(deviceId: string): Record<string, unknown>\n}\n\nexport interface ITrackerStage extends IAnalysisStage {\n readonly id: 'tracker'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n getConfig(deviceId: string): Record<string, unknown>\n resetDevice(deviceId: string): void\n}\n\nexport interface ISubDetectionStage extends IAnalysisStage {\n readonly id: 'sub-detection'\n registerDetector(detector: ISubDetector): void\n}\n\nexport interface IRecognitionStage extends IAnalysisStage {\n readonly id: 'recognition'\n registerRecognizer(recognizer: IRecognizer): void\n}\n\nexport interface IZoneAnalysisStage extends IAnalysisStage {\n readonly id: 'zone-analysis'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\nexport interface IEventGenerationStage extends IAnalysisStage {\n readonly id: 'event-generation'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\nexport interface IObjectSnapshotStage extends IAnalysisStage {\n readonly id: 'object-snapshot'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\n// --- Analysis Pipeline ---\n\nexport interface IAnalysisPipeline {\n addStage(stage: IAnalysisStage): void\n removeStage(stageId: string): void\n getStages(): readonly IAnalysisStage[]\n analyze(deviceId: string, frame: VideoFrame, rawDetections: Detection[]): Promise<AnalysisContext>\n}\n\n// --- Helper functions ---\n\nexport function createAnalysisContext(\n deviceId: string,\n frame: VideoFrame,\n rawDetections: Detection[],\n): AnalysisContext {\n return {\n deviceId,\n frame,\n timestamp: frame.timestamp,\n rawDetections,\n trackedDetections: [],\n events: [],\n metadata: {},\n }\n}\n\nexport function enrichContext(\n ctx: AnalysisContext,\n updates: Partial<Pick<AnalysisContext, 'trackedDetections' | 'events' | 'metadata'>>,\n): AnalysisContext {\n return {\n ...ctx,\n trackedDetections: updates.trackedDetections ?? ctx.trackedDetections,\n events: updates.events ?? ctx.events,\n metadata: updates.metadata ? { ...ctx.metadata, ...updates.metadata } : ctx.metadata,\n }\n}\n","/**\n * Analysis Persistence Types — interfaces for event persistence, track trails,\n * retention, session tracking, and known faces.\n *\n * These interfaces define the contracts used by the server; concrete\n * implementations live in addon-pipeline and are received via CapabilityRegistry.\n */\n\nimport type { ServerTrackedDetection } from './server-analysis.js'\n\n// ---------------------------------------------------------------------------\n// Event Persistence\n// ---------------------------------------------------------------------------\n\nexport interface ObjectSnapshotResult {\n readonly trackId: string\n readonly thumbnail?: Buffer\n readonly fullCrop?: Buffer\n}\n\nexport interface AnnotatedSnapshotResult {\n readonly thumbnail: Buffer\n readonly full: Buffer\n}\n\nexport interface PersistableEvent {\n readonly id: string\n readonly timestamp: number\n readonly deviceId: string\n readonly category: string\n readonly className: string\n readonly score: number\n readonly trackId: string\n readonly severity: string\n readonly description: string\n readonly data: Record<string, unknown>\n readonly mediaFiles: readonly string[]\n}\n\nexport interface EventBufferStatus {\n readonly eventCount: number\n readonly mediaCount: number\n readonly mediaSizeMB: number\n}\n\nexport type TrackMediaType =\n | 'crop-thumb'\n | 'crop-full'\n | 'debug-annotated-thumb'\n | 'debug-annotated-full'\n | 'original'\n | 'original-thumb'\n | 'inline-crop'\n | 'unknown'\n\nexport interface TrackMediaFile {\n readonly path: string\n readonly type: TrackMediaType\n readonly data: Buffer\n readonly source: 'buffer' | 'storage'\n}\n\n// ---------------------------------------------------------------------------\n// Track Trail\n// ---------------------------------------------------------------------------\n\nexport interface TrackCaptureConfig {\n readonly enabled: boolean\n readonly snapshotIntervalMs: number\n readonly maxTrailLength: number\n readonly saveThumbnails: boolean\n readonly thumbnailSize: { readonly width: number; readonly height: number }\n}\n\nexport interface TrackPosition {\n readonly x: number\n readonly y: number\n readonly timestamp: number\n readonly bbox: readonly [number, number, number, number]\n}\n\nexport interface TrackSnapshot {\n readonly timestamp: number\n readonly position: TrackPosition\n readonly thumbnailPath: string\n}\n\nexport interface TrackTrail {\n readonly trackId: string\n readonly deviceId: string\n readonly className: string\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly positions: readonly TrackPosition[]\n readonly snapshots: readonly TrackSnapshot[]\n readonly totalDistance: number\n readonly zonesVisited: readonly string[]\n readonly active: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\nexport interface RetentionConfig {\n readonly cleanupIntervalMs: number\n readonly detectionEventsDays: number\n readonly audioLevelsDays: number\n /** @deprecated — snapshots are tied to events, use detectionEventsDays */\n readonly snapshotsDays: number\n readonly deviceOverrides?: Readonly<Record<string, Partial<Pick<RetentionConfig, 'detectionEventsDays' | 'audioLevelsDays' | 'snapshotsDays'>>>>\n}\n\nexport const DEFAULT_RETENTION: RetentionConfig = {\n cleanupIntervalMs: 60 * 60 * 1000,\n detectionEventsDays: 30,\n audioLevelsDays: 7,\n snapshotsDays: 14,\n}\n\nexport interface RetentionReport {\n readonly deletedEvents: number\n readonly deletedAudioRecords: number\n readonly deletedSnapshots: number\n}\n\n// ---------------------------------------------------------------------------\n// Session Tracker\n// ---------------------------------------------------------------------------\n\nexport interface SessionTrack {\n readonly trackId: string\n readonly deviceId: string\n readonly className: string\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly totalFrames: number\n readonly lastDetection: ServerTrackedDetection\n readonly state: string\n readonly positions: ReadonlyArray<{ readonly x: number; readonly y: number; readonly t: number }>\n readonly embedding?: Float32Array\n readonly globalId?: string\n readonly bestCrop?: Buffer\n}\n\nexport interface GlobalIdentity {\n readonly globalId: string\n readonly embedding: Float32Array\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly deviceIds: ReadonlyArray<string>\n}\n\n// ---------------------------------------------------------------------------\n// Known Faces\n// ---------------------------------------------------------------------------\n\nexport interface ClipRecognizer {\n getEmbedding(imageBuffer: Buffer): Promise<Float32Array>\n}\n\nexport interface KnownFaceEntry {\n readonly id: string\n readonly label: string\n readonly group?: string\n readonly embedding: readonly number[]\n readonly cropBase64: string\n readonly createdAt: number\n readonly updatedAt: number\n readonly source?: string\n readonly metadata?: Readonly<Record<string, unknown>>\n}\n\n// ---------------------------------------------------------------------------\n// Recording Addon (generic interface for recording engine access)\n// ---------------------------------------------------------------------------\n\n/**\n * Interface for the recording addon — the server uses this instead of\n * importing PipelineAddon directly from addon-pipeline.\n */\nexport interface IRecordingAddon {\n getCoordinator(): IRecordingCoordinator\n getRecordingDb(): IRecordingDb\n}\n\n/**\n * Minimal coordinator interface for the server's recording router.\n */\nexport interface IRecordingCoordinator {\n enableRecording(deviceId: string, options: {\n policy: unknown\n ffmpegOverrides?: unknown\n }): Promise<void>\n disableRecording(deviceId: string): Promise<void>\n isRecording(deviceId: string): boolean\n readonly playlistGenerator: {\n generate(\n deviceId: string,\n streamId: string,\n startTime: number,\n endTime: number,\n options?: { live?: boolean },\n ): unknown\n }\n readonly storageEstimator: {\n estimateForDevice(\n deviceId: string,\n motionInput?: { avgEventsPerDay: number; avgDurationSec: number },\n ): { totalEstimatedGb: number; [key: string]: unknown }\n }\n}\n\n/**\n * Minimal recording database interface for the server's recording router.\n */\nexport interface IRecordingDb {\n upsertStorageConfig(config: {\n deviceId: string\n dataCategory: string\n storageName: string\n subDirectory: string\n retentionDays: number | null\n retentionGb: number | null\n }): void\n getPolicy(deviceId: string): unknown\n getEnabledPolicies(): Array<{ deviceId: string; [key: string]: unknown }>\n querySegments(deviceId: string, streamId: string, startTime: number, endTime: number): unknown\n getAvailability(deviceId: string, startTime: number, endTime: number): unknown\n getStorageUsage(deviceId: string, streamId: string): unknown\n upsertPolicy(policy: unknown): void\n findNearestThumbnail(deviceId: string, timestamp: number, category: string): unknown\n getMotionStats(deviceId: string, startTime: number, endTime: number): {\n avgEventsPerDay: number\n avgDurationSec: number\n dutyCyclePercent: number\n totalEvents: number\n }\n resolveStorageConfig(deviceId: string, dataCategory: string): unknown\n}\n\n// ---------------------------------------------------------------------------\n// Sub-service interfaces — used by the server's thin NestJS wrappers\n// to receive delegates via CapabilityRegistry.\n// ---------------------------------------------------------------------------\n\nexport interface IEventPersistence {\n start(): void\n stop(): void\n saveDetectionCrops(eventId: string, crops: readonly ObjectSnapshotResult[]): void\n saveAnnotatedFrame(eventId: string, result: AnnotatedSnapshotResult): void\n saveOriginalFrame(eventId: string, frame: import('./camera-pipeline.js').VideoFrame): Promise<void>\n getEventMedia(eventId: string): Promise<unknown>\n getTrackMedia(trackId: string): Promise<unknown>\n getDeviceMedia(deviceId: string, since?: number, until?: number): Promise<unknown>\n getBufferStatus(): unknown\n flush(): Promise<void>\n}\n\nexport interface ITrackTrail {\n setConfig(deviceId: string, config: Partial<TrackCaptureConfig>): void\n getConfig(deviceId: string): unknown\n recordFrame(ctx: unknown): Promise<void>\n getActiveTrail(trackId: string): unknown\n getActiveTrails(deviceId: string): unknown\n getPersistedTrail(trackId: string): Promise<unknown>\n getTrail(trackId: string): Promise<unknown>\n listTrails(deviceId: string, options?: {\n since?: number\n until?: number\n limit?: number\n className?: string\n }): Promise<unknown>\n}\n\nexport interface IRetention {\n start(): void\n stop(): void\n runCleanup(): Promise<unknown>\n setConfig(update: Partial<RetentionConfig>): void\n getConfig(): unknown\n forceCleanup(): Promise<unknown>\n}\n\nexport interface ISessionTracker {\n updateFromAnalysis(deviceId: string, ctx: unknown): void\n getActiveTracks(deviceId: string): unknown\n getAllActiveTracks(): unknown\n getTrack(deviceId: string, trackId: string): unknown\n getTrackCounts(): unknown\n clearDevice(deviceId: string): void\n clearAll(): void\n getGlobalPool(): unknown\n}\n\nexport interface IKnownFaces {\n register(entry: KnownFaceEntry): Promise<void>\n listAll(): Promise<unknown>\n delete(id: string): Promise<void>\n update(id: string, updates: Partial<Pick<KnownFaceEntry, 'label' | 'group'>>): Promise<void>\n recalculateEmbedding(id: string, clipRecognizer: ClipRecognizer): Promise<void>\n findMatch(embedding: Float32Array, threshold: number): Promise<unknown>\n batchRegister(\n entries: ReadonlyArray<{ readonly label: string; readonly cropBase64: string; readonly group?: string }>,\n clipRecognizer: ClipRecognizer,\n ): Promise<unknown>\n}\n\n/**\n * Composite interface exposed via CapabilityRegistry as the\n * 'analysis-data-persistence' singleton. Each sub-service is wired\n * individually to the corresponding NestJS wrapper service.\n */\nexport interface IAnalysisDataPersistence {\n readonly eventPersistence: IEventPersistence\n readonly knownFaces: IKnownFaces\n readonly sessionTracker: ISessionTracker\n readonly retention: IRetention\n readonly trackTrail: ITrackTrail\n}\n\n// ---------------------------------------------------------------------------\n// Provider Connection Testing\n// ---------------------------------------------------------------------------\n\nexport interface TestConnectionResult {\n readonly success: boolean\n readonly version?: string\n readonly cameraCount?: number\n readonly error?: string\n}\n\n/**\n * Generic interface for testing provider connections.\n * Each provider addon can expose a connection tester.\n */\nexport interface IProviderConnectionTester {\n testConnection(): Promise<TestConnectionResult>\n}\n","export const HF_REPO = 'camstack/camstack-models'\nexport const HF_BASE_URL = `https://huggingface.co/${HF_REPO}/resolve/main`\n","export function hfModelUrl(repo: string, path: string): string {\n return `https://huggingface.co/${repo}/resolve/main/${path}`\n}\n","/** Cosine similarity between two embedding vectors */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) return 0\n let dotProduct = 0\n let normA = 0\n let normB = 0\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!\n normA += a[i]! * a[i]!\n normB += b[i]! * b[i]!\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB)\n return denom === 0 ? 0 : dotProduct / denom\n}\n","import type { LabelDefinition, ClassMapDefinition } from '../types/labels.js'\n\nexport const COCO_80_LABELS: readonly LabelDefinition[] = [\n { id: 'person', name: 'Person' },\n { id: 'bicycle', name: 'Bicycle' },\n { id: 'car', name: 'Car' },\n { id: 'motorcycle', name: 'Motorcycle' },\n { id: 'airplane', name: 'Airplane' },\n { id: 'bus', name: 'Bus' },\n { id: 'train', name: 'Train' },\n { id: 'truck', name: 'Truck' },\n { id: 'boat', name: 'Boat' },\n { id: 'traffic light', name: 'Traffic Light' },\n { id: 'fire hydrant', name: 'Fire Hydrant' },\n { id: 'stop sign', name: 'Stop Sign' },\n { id: 'parking meter', name: 'Parking Meter' },\n { id: 'bench', name: 'Bench' },\n { id: 'bird', name: 'Bird' },\n { id: 'cat', name: 'Cat' },\n { id: 'dog', name: 'Dog' },\n { id: 'horse', name: 'Horse' },\n { id: 'sheep', name: 'Sheep' },\n { id: 'cow', name: 'Cow' },\n { id: 'elephant', name: 'Elephant' },\n { id: 'bear', name: 'Bear' },\n { id: 'zebra', name: 'Zebra' },\n { id: 'giraffe', name: 'Giraffe' },\n { id: 'backpack', name: 'Backpack' },\n { id: 'umbrella', name: 'Umbrella' },\n { id: 'handbag', name: 'Handbag' },\n { id: 'tie', name: 'Tie' },\n { id: 'suitcase', name: 'Suitcase' },\n { id: 'frisbee', name: 'Frisbee' },\n { id: 'skis', name: 'Skis' },\n { id: 'snowboard', name: 'Snowboard' },\n { id: 'sports ball', name: 'Sports Ball' },\n { id: 'kite', name: 'Kite' },\n { id: 'baseball bat', name: 'Baseball Bat' },\n { id: 'baseball glove', name: 'Baseball Glove' },\n { id: 'skateboard', name: 'Skateboard' },\n { id: 'surfboard', name: 'Surfboard' },\n { id: 'tennis racket', name: 'Tennis Racket' },\n { id: 'bottle', name: 'Bottle' },\n { id: 'wine glass', name: 'Wine Glass' },\n { id: 'cup', name: 'Cup' },\n { id: 'fork', name: 'Fork' },\n { id: 'knife', name: 'Knife' },\n { id: 'spoon', name: 'Spoon' },\n { id: 'bowl', name: 'Bowl' },\n { id: 'banana', name: 'Banana' },\n { id: 'apple', name: 'Apple' },\n { id: 'sandwich', name: 'Sandwich' },\n { id: 'orange', name: 'Orange' },\n { id: 'broccoli', name: 'Broccoli' },\n { id: 'carrot', name: 'Carrot' },\n { id: 'hot dog', name: 'Hot Dog' },\n { id: 'pizza', name: 'Pizza' },\n { id: 'donut', name: 'Donut' },\n { id: 'cake', name: 'Cake' },\n { id: 'chair', name: 'Chair' },\n { id: 'couch', name: 'Couch' },\n { id: 'potted plant', name: 'Potted Plant' },\n { id: 'bed', name: 'Bed' },\n { id: 'dining table', name: 'Dining Table' },\n { id: 'toilet', name: 'Toilet' },\n { id: 'tv', name: 'TV' },\n { id: 'laptop', name: 'Laptop' },\n { id: 'mouse', name: 'Mouse' },\n { id: 'remote', name: 'Remote' },\n { id: 'keyboard', name: 'Keyboard' },\n { id: 'cell phone', name: 'Cell Phone' },\n { id: 'microwave', name: 'Microwave' },\n { id: 'oven', name: 'Oven' },\n { id: 'toaster', name: 'Toaster' },\n { id: 'sink', name: 'Sink' },\n { id: 'refrigerator', name: 'Refrigerator' },\n { id: 'book', name: 'Book' },\n { id: 'clock', name: 'Clock' },\n { id: 'vase', name: 'Vase' },\n { id: 'scissors', name: 'Scissors' },\n { id: 'teddy bear', name: 'Teddy Bear' },\n { id: 'hair drier', name: 'Hair Drier' },\n { id: 'toothbrush', name: 'Toothbrush' },\n] as const\n\nexport const MACRO_LABELS: readonly LabelDefinition[] = [\n { id: 'person', name: 'Person' },\n { id: 'vehicle', name: 'Vehicle' },\n { id: 'animal', name: 'Animal' },\n] as const\n\nexport const COCO_TO_MACRO: ClassMapDefinition = {\n mapping: {\n person: 'person',\n bicycle: 'vehicle',\n car: 'vehicle',\n motorcycle: 'vehicle',\n airplane: 'vehicle',\n bus: 'vehicle',\n train: 'vehicle',\n truck: 'vehicle',\n boat: 'vehicle',\n bird: 'animal',\n cat: 'animal',\n dog: 'animal',\n horse: 'animal',\n sheep: 'animal',\n cow: 'animal',\n elephant: 'animal',\n bear: 'animal',\n zebra: 'animal',\n giraffe: 'animal',\n },\n preserveOriginal: true,\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/interfaces/storage-backend.ts","../src/interfaces/addon-i18n.ts","../src/interfaces/feature-flags.ts","../src/interfaces/agent-protocol.ts","../src/interfaces/server-analysis.ts","../src/interfaces/analysis-persistence.ts","../src/schemas/system-settings-schemas.ts","../src/constants.ts","../src/utils/hf-url.ts","../src/utils/cosine-similarity.ts","../src/catalogs/coco-classmap.ts","../src/types/device-type.ts"],"sourcesContent":["/**\n * @deprecated — This file contains legacy storage backend interfaces.\n * Use the new interfaces from './storage.ts' instead:\n * - IStorageProvider (capability: 'storage')\n * - ISettingsBackend (capability: 'settings-store')\n * - IEmbeddingsBackend (capability: 'embeddings')\n */\n\nimport type { StorageLocationType } from './storage.js'\n\n/** @deprecated Use IStorageProvider from storage.ts */\nexport interface IStorageBackend {\n readonly type: string\n readonly basePath: string\n resolve(subpath: string): string\n resolve(location: StorageLocationType, ...segments: string[]): string\n isAvailable(location?: StorageLocationType): boolean\n initialize(): Promise<void>\n getLocationPath?(location: StorageLocationType): string\n}\n\n/** @deprecated */\nexport interface StorageLocationConfig {\n readonly name: string\n readonly basePath: string\n readonly backendType?: string\n}\n\n/** @deprecated Use DEFAULT_LOCATION_SUBDIRS from storage.ts */\nexport const DEFAULT_LOCATION_SUBPATHS: Record<string, string> = {\n 'recordings-high': 'recordings-high',\n 'recordings-low': 'recordings-low',\n 'recordings-clips': 'recordings-clips',\n 'event-images': 'event-images',\n 'models': 'models',\n 'addons-data': 'addons-data',\n 'cache': '/tmp/camstack-cache',\n 'logs': 'logs',\n}\n","/**\n * Addon i18n interface -- allows addons to provide translations\n * for their UI labels, descriptions, and config schema fields.\n *\n * Addons implement IAddonTranslationProvider to supply translations\n * either as a static map or via a dynamic lookup method.\n */\n\n/** A flat key-value map of translation strings for a single locale */\nexport type TranslationMap = Readonly<Record<string, string>>\n\n/** A complete translations bundle keyed by locale code (e.g. 'en', 'it', 'de') */\nexport type TranslationBundle = Readonly<Record<string, TranslationMap>>\n\n/**\n * Provider interface for addons that supply translations.\n *\n * Addons can provide translations in two ways:\n * 1. A static bundle via `getTranslationBundle()` containing all locales\n * 2. A per-locale lookup via `getTranslations(locale)` for lazy loading\n *\n * At least one method must be implemented. If both are present,\n * `getTranslations()` takes precedence for the requested locale.\n */\nexport interface IAddonTranslationProvider {\n readonly id: string\n\n /**\n * Return translations for a specific locale.\n * Returns undefined if the locale is not supported.\n */\n getTranslations?(locale: string): TranslationMap | undefined\n\n /**\n * Return the full translation bundle containing all supported locales.\n * Useful when the addon ships all translations statically.\n */\n getTranslationBundle?(): TranslationBundle\n}\n\n/**\n * Resolve a translation key against a provider for the given locale.\n * Falls back to 'en' if the requested locale is not available,\n * then falls back to the key itself if no translation is found.\n */\nexport function resolveTranslation(\n provider: IAddonTranslationProvider,\n locale: string,\n key: string,\n): string {\n // Try provider's per-locale method first\n if (provider.getTranslations) {\n const map = provider.getTranslations(locale)\n if (map && key in map) return map[key]!\n\n // Fallback to 'en' if different locale was requested\n if (locale !== 'en') {\n const fallback = provider.getTranslations('en')\n if (fallback && key in fallback) return fallback[key]!\n }\n }\n\n // Try static bundle\n if (provider.getTranslationBundle) {\n const bundle = provider.getTranslationBundle()\n const map = bundle[locale]\n if (map && key in map) return map[key]!\n\n // Fallback to 'en'\n if (locale !== 'en') {\n const fallback = bundle['en']\n if (fallback && key in fallback) return fallback[key]!\n }\n }\n\n // No translation found -- return the key as-is\n return key\n}\n","export interface FeatureManifest {\n streaming: boolean\n notifications: boolean\n objectDetection: boolean\n remoteAccess: boolean\n agentCluster: boolean\n smartHome: boolean\n recordings: boolean\n backup: boolean\n repl: boolean\n}\n\nexport type FeatureFlag = keyof FeatureManifest\n\nexport const DEFAULT_FEATURES: FeatureManifest = {\n streaming: true,\n notifications: true,\n objectDetection: false,\n remoteAccess: true,\n agentCluster: false,\n smartHome: true,\n recordings: true,\n backup: true,\n repl: true,\n}\n","import type { TaskProgress } from './task-handler.js'\n\n// --- Agent capabilities & roles ---\nexport type AgentCapability = 'decoder' | 'transcoder' | 'detector' | 'recorder'\nexport type RolePriority = 'primary' | 'backup' | 'overflow'\n\nexport interface CameraRoleAssignment {\n cameraId: string\n role: AgentCapability\n agentId: string\n priority: RolePriority\n rtspUrl?: string\n detectionConfig?: {\n modelId: string\n runtime: string\n confidence: number\n fps: number\n classes?: string[]\n }\n}\n\n// --- Hub -> Agent messages ---\nexport type HubToAgentMessage =\n | { type: 'assign'; assignment: CameraRoleAssignment }\n | { type: 'unassign'; cameraId: string; role: AgentCapability }\n | { type: 'recording.start'; cameraId: string; rtspUrl: string }\n | { type: 'recording.stop'; cameraId: string }\n | { type: 'benchmark.run'; config: RemoteBenchmarkConfig }\n | { type: 'config.update'; addonId: string; config: Record<string, unknown> }\n | { type: 'task.execute'; taskId: string; taskType: string; payload: unknown }\n | { type: 'task.cancel'; taskId: string }\n | { type: 'addon.install'; package: string; version?: string }\n | { type: 'addon.uninstall'; package: string }\n | { type: 'addon.update'; package: string; version?: string }\n | { type: 'addon.restart' }\n | { type: 'ping' }\n\n// --- Agent -> Hub messages ---\nexport type AgentToHubMessage =\n | { type: 'register'; info: AgentRegistrationInfo }\n | { type: 'heartbeat'; status: AgentRuntimeStatus }\n | { type: 'detection.result'; cameraId: string; detections: DetectionResult[]; timestamp: number; inferenceMs: number }\n | { type: 'recording.segment'; cameraId: string; segment: RecordingSegmentInfo }\n | { type: 'recording.status'; cameraId: string; recording: boolean }\n | { type: 'benchmark.progress'; event: BenchmarkStreamEvent }\n | { type: 'benchmark.result'; report: BenchmarkReport }\n | { type: 'task.result'; taskId: string; success: boolean; result?: unknown; error?: string }\n | { type: 'task.progress'; taskId: string; progress: TaskProgress }\n | { type: 'addon.install-result'; package: string; success: boolean; version?: string; error?: string }\n | { type: 'addon.uninstall-result'; package: string; success: boolean; error?: string }\n | { type: 'addon.update-result'; package: string; success: boolean; version?: string; error?: string }\n | { type: 'log'; level: string; scope: string; message: string }\n | { type: 'pong' }\n\n// --- Binary frame header (29 bytes) ---\nexport const BINARY_FRAME_HEADER_SIZE = 29\nexport const BINARY_FRAME_TYPE = 0x01\n\nexport interface AgentRegistrationInfo {\n id: string\n name: string\n capabilities: AgentCapability[]\n host: string\n port: number\n platform: string\n arch: string\n cpuCores: number\n memoryMB: number\n gpuModel?: string\n pythonRuntimes: string[]\n httpPort: number\n /** Task types this agent can handle (e.g., 'pipeline.decode', 'system.info') */\n taskTypes?: string[]\n /** Installed addons on this agent */\n installedAddons?: string[]\n}\n\nexport interface AgentRuntimeStatus {\n activeCameras: number\n cpuPercent: number\n memoryPercent: number\n fps: Record<string, number>\n errors: string[]\n}\n\nexport interface DetectionResult {\n className: string\n score: number\n bbox: [number, number, number, number]\n}\n\nexport interface RecordingSegmentInfo {\n id: string\n startTime: number\n endTime: number\n duration: number\n sizeBytes: number\n path: string\n format: 'mp4' | 'ts'\n}\n\nexport interface RemoteBenchmarkConfig {\n runtime: string\n modelId?: string\n durationMs: number\n warmupMs: number\n inputWidth: number\n inputHeight: number\n}\n\nexport interface BenchmarkStreamEvent {\n phase: 'warmup' | 'running'\n iteration: number\n inferenceMs: number\n}\n\nexport interface BenchmarkReport {\n runtime: string\n modelId?: string\n iterations: number\n meanMs: number\n p50Ms: number\n p95Ms: number\n p99Ms: number\n minMs: number\n maxMs: number\n}\n","/**\n * Detection Analysis Pipeline -- processes raw detections through\n * configurable stages to produce tracked, enriched, actionable events.\n */\n\nimport type { Detection } from './device-capabilities/object-detector.js'\nimport type { VideoFrame } from './camera-pipeline.js'\n\n// --- Detection type const unions ---\n\nexport const DETECTION_TYPES = ['person', 'vehicle', 'animal', 'package'] as const\nexport type DetectionType = typeof DETECTION_TYPES[number]\n\nexport const SUB_DETECTION_TYPES = ['face', 'plate'] as const\nexport type SubDetectionType = typeof SUB_DETECTION_TYPES[number]\n\nexport const RECOGNITION_TYPES = ['face', 'plate', 'clip', 'custom'] as const\nexport type RecognitionType = typeof RECOGNITION_TYPES[number]\n\n// --- Analysis Context ---\n\nexport interface AnalysisContext {\n readonly deviceId: string\n readonly frame: VideoFrame\n readonly timestamp: number\n readonly rawDetections: readonly Detection[]\n readonly trackedDetections: readonly ServerTrackedDetection[]\n readonly events: readonly AnalysisEvent[]\n readonly metadata: Readonly<Record<string, unknown>>\n}\n\n// --- Tracked Detection ---\n\nexport interface ServerTrackedDetection {\n readonly trackId: string\n readonly detection: Detection\n readonly crop?: Buffer\n readonly tracking: TrackingInfo\n readonly subDetections: readonly SubDetection[]\n readonly recognitions: readonly RecognitionResult[]\n readonly zones: readonly string[]\n readonly previousZones: readonly string[]\n}\n\nexport interface TrackingInfo {\n readonly age: number\n readonly state: 'moving' | 'stationary' | 'new' | 'lost'\n readonly stationaryDuration: number\n readonly velocity: { readonly dx: number; readonly dy: number }\n readonly positionHistory: ReadonlyArray<{ readonly x: number; readonly y: number; readonly t: number }>\n}\n\n// --- Sub-Detection ---\n\nexport interface SubDetection {\n readonly detectionType: SubDetectionType\n readonly boundingBox: readonly [number, number, number, number]\n readonly score: number\n readonly crop?: Buffer\n}\n\n// --- Recognition ---\n\nexport interface RecognitionResult {\n readonly recognitionType: RecognitionType\n readonly label: string\n readonly score: number\n readonly embedding?: readonly number[]\n readonly metadata?: Readonly<Record<string, unknown>>\n}\n\n// --- Analysis Events ---\n\nexport interface AnalysisEvent {\n readonly category: string\n readonly severity: 'info' | 'warning' | 'alert'\n readonly detection: ServerTrackedDetection\n readonly description: string\n readonly data: Readonly<Record<string, unknown>>\n}\n\n// --- Analysis Stage ---\n\nexport interface IAnalysisStage {\n readonly id: string\n readonly name: string\n readonly priority: number\n enabled: boolean\n process(ctx: AnalysisContext): Promise<AnalysisContext>\n}\n\n// --- Sub-Detector Interface ---\n\nexport interface ISubDetector {\n readonly detectionType: SubDetectionType\n readonly targetClasses: readonly string[]\n detect(crop: Buffer, cropWidth: number, cropHeight: number): Promise<SubDetection[]>\n}\n\nexport interface IFaceDetector extends ISubDetector {\n readonly detectionType: 'face'\n}\n\nexport interface IPlateDetector extends ISubDetector {\n readonly detectionType: 'plate'\n}\n\n// --- Recognizer Interface ---\n\nexport interface IRecognizer {\n readonly recognitionType: RecognitionType\n recognize(crop: Buffer, width: number, height: number): Promise<RecognitionResult | null>\n}\n\nexport interface IFaceRecognizer extends IRecognizer {\n getEmbedding(crop: Buffer): Promise<Float32Array>\n registerKnown(label: string, embedding: Float32Array): void\n}\n\nexport interface IPlateRecognizer extends IRecognizer {\n readonly recognitionType: 'plate'\n}\n\n// --- Audio Classifier ---\n\nexport interface IAudioClassifier {\n readonly ready: boolean\n initialize(): Promise<void>\n classify(\n audioSamples: Float32Array,\n sampleRate: number,\n topN?: number,\n ): Promise<readonly AudioClassification[]>\n release(): Promise<void>\n}\n\nexport interface AudioClassification {\n readonly classIndex: number\n readonly className: string\n readonly score: number\n readonly isSurveillanceRelevant: boolean\n}\n\n// --- Pipeline Stage Interfaces ---\n\nexport interface IClassFilterStage extends IAnalysisStage {\n readonly id: 'class-filter'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n getConfig(deviceId: string): Record<string, unknown>\n}\n\nexport interface ITrackerStage extends IAnalysisStage {\n readonly id: 'tracker'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n getConfig(deviceId: string): Record<string, unknown>\n resetDevice(deviceId: string): void\n}\n\nexport interface ISubDetectionStage extends IAnalysisStage {\n readonly id: 'sub-detection'\n registerDetector(detector: ISubDetector): void\n}\n\nexport interface IRecognitionStage extends IAnalysisStage {\n readonly id: 'recognition'\n registerRecognizer(recognizer: IRecognizer): void\n}\n\nexport interface IZoneAnalysisStage extends IAnalysisStage {\n readonly id: 'zone-analysis'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\nexport interface IEventGenerationStage extends IAnalysisStage {\n readonly id: 'event-generation'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\nexport interface IObjectSnapshotStage extends IAnalysisStage {\n readonly id: 'object-snapshot'\n setConfig(deviceId: string, config: Record<string, unknown>): void\n}\n\n// --- Analysis Pipeline ---\n\nexport interface IAnalysisPipeline {\n addStage(stage: IAnalysisStage): void\n removeStage(stageId: string): void\n getStages(): readonly IAnalysisStage[]\n analyze(deviceId: string, frame: VideoFrame, rawDetections: Detection[]): Promise<AnalysisContext>\n}\n\n// --- Helper functions ---\n\nexport function createAnalysisContext(\n deviceId: string,\n frame: VideoFrame,\n rawDetections: Detection[],\n): AnalysisContext {\n return {\n deviceId,\n frame,\n timestamp: frame.timestamp,\n rawDetections,\n trackedDetections: [],\n events: [],\n metadata: {},\n }\n}\n\nexport function enrichContext(\n ctx: AnalysisContext,\n updates: Partial<Pick<AnalysisContext, 'trackedDetections' | 'events' | 'metadata'>>,\n): AnalysisContext {\n return {\n ...ctx,\n trackedDetections: updates.trackedDetections ?? ctx.trackedDetections,\n events: updates.events ?? ctx.events,\n metadata: updates.metadata ? { ...ctx.metadata, ...updates.metadata } : ctx.metadata,\n }\n}\n","/**\n * Analysis Persistence Types — interfaces for event persistence, track trails,\n * retention, session tracking, and known faces.\n *\n * These interfaces define the contracts used by the server; concrete\n * implementations live in addon-pipeline and are received via CapabilityRegistry.\n */\n\nimport type { ServerTrackedDetection } from './server-analysis.js'\n\n// ---------------------------------------------------------------------------\n// Event Persistence\n// ---------------------------------------------------------------------------\n\nexport interface ObjectSnapshotResult {\n readonly trackId: string\n readonly thumbnail?: Buffer\n readonly fullCrop?: Buffer\n}\n\nexport interface AnnotatedSnapshotResult {\n readonly thumbnail: Buffer\n readonly full: Buffer\n}\n\nexport interface PersistableEvent {\n readonly id: string\n readonly timestamp: number\n readonly deviceId: string\n readonly category: string\n readonly className: string\n readonly score: number\n readonly trackId: string\n readonly severity: string\n readonly description: string\n readonly data: Record<string, unknown>\n readonly mediaFiles: readonly string[]\n}\n\nexport interface EventBufferStatus {\n readonly eventCount: number\n readonly mediaCount: number\n readonly mediaSizeMB: number\n}\n\nexport type TrackMediaType =\n | 'crop-thumb'\n | 'crop-full'\n | 'debug-annotated-thumb'\n | 'debug-annotated-full'\n | 'original'\n | 'original-thumb'\n | 'inline-crop'\n | 'unknown'\n\nexport interface TrackMediaFile {\n readonly path: string\n readonly type: TrackMediaType\n readonly data: Buffer\n readonly source: 'buffer' | 'storage'\n}\n\n// ---------------------------------------------------------------------------\n// Track Trail\n// ---------------------------------------------------------------------------\n\nexport interface TrackCaptureConfig {\n readonly enabled: boolean\n readonly snapshotIntervalMs: number\n readonly maxTrailLength: number\n readonly saveThumbnails: boolean\n readonly thumbnailSize: { readonly width: number; readonly height: number }\n}\n\nexport interface TrackPosition {\n readonly x: number\n readonly y: number\n readonly timestamp: number\n readonly bbox: readonly [number, number, number, number]\n}\n\nexport interface TrackSnapshot {\n readonly timestamp: number\n readonly position: TrackPosition\n readonly thumbnailPath: string\n}\n\nexport interface TrackTrail {\n readonly trackId: string\n readonly deviceId: string\n readonly className: string\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly positions: readonly TrackPosition[]\n readonly snapshots: readonly TrackSnapshot[]\n readonly totalDistance: number\n readonly zonesVisited: readonly string[]\n readonly active: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Retention\n// ---------------------------------------------------------------------------\n\nexport interface RetentionConfig {\n readonly cleanupIntervalMs: number\n readonly detectionEventsDays: number\n readonly audioLevelsDays: number\n /** @deprecated — snapshots are tied to events, use detectionEventsDays */\n readonly snapshotsDays: number\n readonly deviceOverrides?: Readonly<Record<string, Partial<Pick<RetentionConfig, 'detectionEventsDays' | 'audioLevelsDays' | 'snapshotsDays'>>>>\n}\n\nexport const DEFAULT_RETENTION: RetentionConfig = {\n cleanupIntervalMs: 60 * 60 * 1000,\n detectionEventsDays: 30,\n audioLevelsDays: 7,\n snapshotsDays: 14,\n}\n\nexport interface RetentionReport {\n readonly deletedEvents: number\n readonly deletedAudioRecords: number\n readonly deletedSnapshots: number\n}\n\n// ---------------------------------------------------------------------------\n// Session Tracker\n// ---------------------------------------------------------------------------\n\nexport interface SessionTrack {\n readonly trackId: string\n readonly deviceId: string\n readonly className: string\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly totalFrames: number\n readonly lastDetection: ServerTrackedDetection\n readonly state: string\n readonly positions: ReadonlyArray<{ readonly x: number; readonly y: number; readonly t: number }>\n readonly embedding?: Float32Array\n readonly globalId?: string\n readonly bestCrop?: Buffer\n}\n\nexport interface GlobalIdentity {\n readonly globalId: string\n readonly embedding: Float32Array\n readonly label?: string\n readonly firstSeen: number\n readonly lastSeen: number\n readonly deviceIds: ReadonlyArray<string>\n}\n\n// ---------------------------------------------------------------------------\n// Known Faces\n// ---------------------------------------------------------------------------\n\nexport interface ClipRecognizer {\n getEmbedding(imageBuffer: Buffer): Promise<Float32Array>\n}\n\nexport interface KnownFaceEntry {\n readonly id: string\n readonly label: string\n readonly group?: string\n readonly embedding: readonly number[]\n readonly cropBase64: string\n readonly createdAt: number\n readonly updatedAt: number\n readonly source?: string\n readonly metadata?: Readonly<Record<string, unknown>>\n}\n\n// ---------------------------------------------------------------------------\n// Recording Addon (generic interface for recording engine access)\n// ---------------------------------------------------------------------------\n\n/**\n * Interface for the recording addon — the server uses this instead of\n * importing PipelineAddon directly from addon-pipeline.\n */\nexport interface IRecordingAddon {\n getCoordinator(): IRecordingCoordinator\n getRecordingDb(): IRecordingDb\n}\n\n/**\n * Minimal coordinator interface for the server's recording router.\n */\nexport interface IRecordingCoordinator {\n enableRecording(deviceId: string, options: {\n policy: unknown\n ffmpegOverrides?: unknown\n }): Promise<void>\n disableRecording(deviceId: string): Promise<void>\n isRecording(deviceId: string): boolean\n readonly playlistGenerator: {\n generate(\n deviceId: string,\n streamId: string,\n startTime: number,\n endTime: number,\n options?: { live?: boolean },\n ): unknown\n }\n readonly storageEstimator: {\n estimateForDevice(\n deviceId: string,\n motionInput?: { avgEventsPerDay: number; avgDurationSec: number },\n ): { totalEstimatedGb: number; [key: string]: unknown }\n }\n}\n\n/**\n * Minimal recording database interface for the server's recording router.\n */\nexport interface IRecordingDb {\n upsertStorageConfig(config: {\n deviceId: string\n dataCategory: string\n storageName: string\n subDirectory: string\n retentionDays: number | null\n retentionGb: number | null\n }): void\n getPolicy(deviceId: string): unknown\n getEnabledPolicies(): Array<{ deviceId: string; [key: string]: unknown }>\n querySegments(deviceId: string, streamId: string, startTime: number, endTime: number): unknown\n getAvailability(deviceId: string, startTime: number, endTime: number): unknown\n getStorageUsage(deviceId: string, streamId: string): unknown\n upsertPolicy(policy: unknown): void\n findNearestThumbnail(deviceId: string, timestamp: number, category: string): unknown\n getMotionStats(deviceId: string, startTime: number, endTime: number): {\n avgEventsPerDay: number\n avgDurationSec: number\n dutyCyclePercent: number\n totalEvents: number\n }\n resolveStorageConfig(deviceId: string, dataCategory: string): unknown\n}\n\n// ---------------------------------------------------------------------------\n// Sub-service interfaces — used by the server's thin NestJS wrappers\n// to receive delegates via CapabilityRegistry.\n// ---------------------------------------------------------------------------\n\nexport interface IEventPersistence {\n start(): void\n stop(): void\n saveDetectionCrops(eventId: string, crops: readonly ObjectSnapshotResult[]): void\n saveAnnotatedFrame(eventId: string, result: AnnotatedSnapshotResult): void\n saveOriginalFrame(eventId: string, frame: import('./camera-pipeline.js').VideoFrame): Promise<void>\n getEventMedia(eventId: string): Promise<unknown>\n getTrackMedia(trackId: string): Promise<unknown>\n getDeviceMedia(deviceId: string, since?: number, until?: number): Promise<unknown>\n getBufferStatus(): unknown\n flush(): Promise<void>\n}\n\nexport interface ITrackTrail {\n setConfig(deviceId: string, config: Partial<TrackCaptureConfig>): void\n getConfig(deviceId: string): unknown\n recordFrame(ctx: unknown): Promise<void>\n getActiveTrail(trackId: string): unknown\n getActiveTrails(deviceId: string): unknown\n getPersistedTrail(trackId: string): Promise<unknown>\n getTrail(trackId: string): Promise<unknown>\n listTrails(deviceId: string, options?: {\n since?: number\n until?: number\n limit?: number\n className?: string\n }): Promise<unknown>\n}\n\nexport interface IRetention {\n start(): void\n stop(): void\n runCleanup(): Promise<unknown>\n setConfig(update: Partial<RetentionConfig>): void\n getConfig(): unknown\n forceCleanup(): Promise<unknown>\n}\n\nexport interface ISessionTracker {\n updateFromAnalysis(deviceId: string, ctx: unknown): void\n getActiveTracks(deviceId: string): unknown\n getAllActiveTracks(): unknown\n getTrack(deviceId: string, trackId: string): unknown\n getTrackCounts(): unknown\n clearDevice(deviceId: string): void\n clearAll(): void\n getGlobalPool(): unknown\n}\n\nexport interface IKnownFaces {\n register(entry: KnownFaceEntry): Promise<void>\n listAll(): Promise<unknown>\n delete(id: string): Promise<void>\n update(id: string, updates: Partial<Pick<KnownFaceEntry, 'label' | 'group'>>): Promise<void>\n recalculateEmbedding(id: string, clipRecognizer: ClipRecognizer): Promise<void>\n findMatch(embedding: Float32Array, threshold: number): Promise<unknown>\n batchRegister(\n entries: ReadonlyArray<{ readonly label: string; readonly cropBase64: string; readonly group?: string }>,\n clipRecognizer: ClipRecognizer,\n ): Promise<unknown>\n}\n\n/**\n * Composite interface exposed via CapabilityRegistry as the\n * 'analysis-data-persistence' singleton. Each sub-service is wired\n * individually to the corresponding NestJS wrapper service.\n */\nexport interface IAnalysisDataPersistence {\n readonly eventPersistence: IEventPersistence\n readonly knownFaces: IKnownFaces\n readonly sessionTracker: ISessionTracker\n readonly retention: IRetention\n readonly trackTrail: ITrackTrail\n}\n\n// ---------------------------------------------------------------------------\n// Provider Connection Testing\n// ---------------------------------------------------------------------------\n\nexport interface TestConnectionResult {\n readonly success: boolean\n readonly version?: string\n readonly cameraCount?: number\n readonly error?: string\n}\n\n/**\n * Generic interface for testing provider connections.\n * Each provider addon can expose a connection tester.\n */\nexport interface IProviderConnectionTester {\n testConnection(): Promise<TestConnectionResult>\n}\n","/**\n * System settings UI schemas — the single source of truth for all settings sections.\n *\n * These are defined in @camstack/types so that:\n * - The backend can serve them via API\n * - Addons can reference/extend them\n * - The frontend fetches them at runtime (no hardcoded duplication)\n *\n * Values are stored in the SQL system_settings table, not config.yaml.\n * Only `server` is read-only (loaded from config.yaml at bootstrap).\n */\n\nimport type { ConfigUISchema } from '../interfaces/config-ui.js'\n\n// ---------------------------------------------------------------------------\n// Section type\n// ---------------------------------------------------------------------------\n\nexport type SystemSettingsSection =\n | 'server' | 'auth' | 'features' | 'storage' | 'logging' | 'addons'\n | 'recording' | 'streaming' | 'ffmpeg' | 'detection' | 'backup' | 'retention'\n\n/** Sections where fields are read-only (bootstrap from config.yaml). */\nexport const READ_ONLY_SECTIONS: ReadonlySet<SystemSettingsSection> = new Set<SystemSettingsSection>([\n 'server',\n])\n\n// ---------------------------------------------------------------------------\n// Tab definitions (rendering order)\n// ---------------------------------------------------------------------------\n\nexport interface SettingsTabDef {\n readonly id: SystemSettingsSection\n readonly label: string\n}\n\nexport const SETTINGS_TABS: readonly SettingsTabDef[] = [\n { id: 'server', label: 'Server' },\n { id: 'logging', label: 'Logs' },\n { id: 'recording', label: 'Recording' },\n { id: 'ffmpeg', label: 'FFmpeg' },\n { id: 'detection', label: 'Detection' },\n { id: 'auth', label: 'Auth' },\n { id: 'retention', label: 'Retention' },\n] as const\n\n// ---------------------------------------------------------------------------\n// Schemas\n// ---------------------------------------------------------------------------\n\nconst SERVER_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'server-info',\n title: 'Server',\n description: 'Core server connection settings (read-only)',\n columns: 2,\n fields: [\n {\n type: 'info',\n key: 'server-restart-note',\n label: 'Restart required',\n content: 'Server settings are read-only. Change them in config.yaml and restart.',\n variant: 'warning',\n },\n {\n type: 'text',\n key: 'port',\n label: 'Port',\n disabled: true,\n description: 'Listening port',\n },\n {\n type: 'text',\n key: 'host',\n label: 'Host',\n disabled: true,\n description: 'Bind address',\n },\n {\n type: 'text',\n key: 'dataPath',\n label: 'Data Path',\n disabled: true,\n description: 'Root data directory',\n span: 2,\n },\n ],\n },\n ],\n}\n\n// Storage paths are managed via CAMSTACK_DATA env var — no UI settings needed.\nconst STORAGE_SCHEMA: ConfigUISchema = {\n sections: [],\n}\n\nconst LOGGING_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'logging-settings',\n title: 'Logging',\n description: 'Global log verbosity. Retention is managed per log-destination addon.',\n columns: 1,\n fields: [\n {\n type: 'select',\n key: 'level',\n label: 'Log Level',\n options: [\n { value: 'debug', label: 'Debug' },\n { value: 'info', label: 'Info' },\n { value: 'warn', label: 'Warn' },\n { value: 'error', label: 'Error' },\n ],\n },\n ],\n },\n ],\n}\n\nconst RECORDING_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'recording-settings',\n title: 'Recording',\n description: 'Video recording segment and retention defaults',\n columns: 2,\n fields: [\n {\n type: 'number',\n key: 'segmentDurationSeconds',\n label: 'Segment Duration',\n description: 'Length of each recording segment',\n min: 1,\n max: 60,\n step: 1,\n unit: 'seconds',\n },\n {\n type: 'number',\n key: 'defaultRetentionDays',\n label: 'Default Retention',\n description: 'Days to keep recordings before auto-delete',\n min: 1,\n max: 365,\n step: 1,\n unit: 'days',\n },\n ],\n },\n ],\n}\n\n// Streaming ports are addon-specific (go2rtc owns its ports).\n// No system-level streaming schema needed.\n\nconst FFMPEG_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'ffmpeg-settings',\n title: 'FFmpeg',\n description: 'FFmpeg binary and hardware acceleration settings',\n columns: 2,\n fields: [\n {\n type: 'text',\n key: 'binaryPath',\n label: 'Binary Path',\n description: 'Path to ffmpeg executable',\n placeholder: 'ffmpeg',\n span: 2,\n },\n {\n type: 'select',\n key: 'hwAccel',\n label: 'Hardware Acceleration',\n description: 'GPU decoding/encoding backend',\n options: [\n { value: 'auto', label: 'Auto-detect' },\n { value: 'none', label: 'None (CPU only)' },\n { value: 'videotoolbox', label: 'VideoToolbox (macOS)' },\n { value: 'vaapi', label: 'VA-API (Linux Intel/AMD)' },\n { value: 'qsv', label: 'QSV (Intel Quick Sync)' },\n { value: 'cuda', label: 'CUDA (NVIDIA)' },\n ],\n },\n {\n type: 'number',\n key: 'threadCount',\n label: 'Thread Count',\n description: '0 = auto (let FFmpeg decide)',\n min: 0,\n max: 16,\n step: 1,\n },\n ],\n },\n ],\n}\n\nconst DETECTION_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'detection-fps',\n title: 'Frame Rates',\n description: 'Default analysis frame rates for new cameras',\n columns: 2,\n fields: [\n {\n type: 'number',\n key: 'defaultMotionFps',\n label: 'Motion FPS',\n description: 'Frames per second for motion detection',\n min: 1,\n max: 30,\n step: 1,\n unit: 'fps',\n },\n {\n type: 'number',\n key: 'defaultDetectionFps',\n label: 'Detection FPS',\n description: 'Frames per second for object detection',\n min: 1,\n max: 30,\n step: 1,\n unit: 'fps',\n },\n ],\n },\n {\n id: 'detection-thresholds',\n title: 'Thresholds',\n description: 'Default confidence and cooldown for detections',\n columns: 2,\n fields: [\n {\n type: 'slider',\n key: 'defaultConfidenceThreshold',\n label: 'Confidence Threshold',\n description: 'Minimum confidence to trigger a detection event',\n min: 0.1,\n max: 1.0,\n step: 0.05,\n showValue: true,\n },\n {\n type: 'number',\n key: 'defaultCooldownSeconds',\n label: 'Cooldown',\n description: 'Seconds between duplicate events',\n min: 0,\n max: 300,\n step: 1,\n unit: 'seconds',\n },\n ],\n },\n {\n id: 'detection-tracker',\n title: 'Tracker',\n description: 'SORT/IoU tracker parameters',\n columns: 3,\n fields: [\n {\n type: 'number',\n key: 'trackerMaxAgeFrames',\n label: 'Max Age',\n description: 'Frames before a lost track is removed',\n min: 1,\n max: 120,\n step: 1,\n unit: 'frames',\n },\n {\n type: 'number',\n key: 'trackerMinHits',\n label: 'Min Hits',\n description: 'Consecutive detections to confirm a track',\n min: 1,\n max: 20,\n step: 1,\n },\n {\n type: 'slider',\n key: 'trackerIouThreshold',\n label: 'IoU Threshold',\n description: 'Minimum IoU to associate detection with track',\n min: 0.1,\n max: 0.9,\n step: 0.05,\n showValue: true,\n },\n ],\n },\n ],\n}\n\n// Backup retention is addon-specific (local-backup owns its retention count).\n// No system-level backup schema needed.\n\nconst AUTH_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'auth-settings',\n title: 'Authentication',\n description: 'Token and session settings',\n columns: 1,\n fields: [\n {\n type: 'text',\n key: 'tokenExpiry',\n label: 'Token Expiry',\n description: 'JWT token lifetime (e.g. 24h, 7d, 1h)',\n placeholder: '24h',\n },\n ],\n },\n ],\n}\n\nconst RETENTION_SCHEMA: ConfigUISchema = {\n sections: [\n {\n id: 'retention-settings',\n title: 'Retention',\n description: 'Data retention periods for analytics data',\n columns: 1,\n fields: [\n {\n type: 'slider',\n key: 'detectionEventsDays',\n label: 'Detection Events Retention',\n min: 1,\n max: 365,\n unit: 'days',\n showValue: true,\n span: 1,\n },\n {\n type: 'slider',\n key: 'audioLevelsDays',\n label: 'Audio Levels Retention',\n min: 1,\n max: 90,\n unit: 'days',\n showValue: true,\n span: 1,\n },\n ],\n },\n ],\n}\n\n// ---------------------------------------------------------------------------\n// Registry: section → schema\n// ---------------------------------------------------------------------------\n\nexport const SYSTEM_SETTINGS_SCHEMAS: Readonly<Record<SystemSettingsSection, ConfigUISchema>> = {\n server: SERVER_SCHEMA,\n storage: STORAGE_SCHEMA,\n logging: LOGGING_SCHEMA,\n recording: RECORDING_SCHEMA,\n ffmpeg: FFMPEG_SCHEMA,\n detection: DETECTION_SCHEMA,\n auth: AUTH_SCHEMA,\n retention: RETENTION_SCHEMA,\n // These sections have no UI form — managed programmatically or addon-specific\n streaming: { sections: [] },\n backup: { sections: [] },\n features: { sections: [] },\n addons: { sections: [] },\n}\n\n/**\n * Get the UI schema for a settings section.\n * Returns undefined for unknown sections.\n */\nexport function getSystemSettingsSchema(section: string): ConfigUISchema | undefined {\n return (SYSTEM_SETTINGS_SCHEMAS as Record<string, ConfigUISchema>)[section]\n}\n","export const HF_REPO = 'camstack/camstack-models'\nexport const HF_BASE_URL = `https://huggingface.co/${HF_REPO}/resolve/main`\n","export function hfModelUrl(repo: string, path: string): string {\n return `https://huggingface.co/${repo}/resolve/main/${path}`\n}\n","/** Cosine similarity between two embedding vectors */\nexport function cosineSimilarity(a: Float32Array, b: Float32Array): number {\n if (a.length !== b.length) return 0\n let dotProduct = 0\n let normA = 0\n let normB = 0\n for (let i = 0; i < a.length; i++) {\n dotProduct += a[i]! * b[i]!\n normA += a[i]! * a[i]!\n normB += b[i]! * b[i]!\n }\n const denom = Math.sqrt(normA) * Math.sqrt(normB)\n return denom === 0 ? 0 : dotProduct / denom\n}\n","import type { LabelDefinition, ClassMapDefinition } from '../types/labels.js'\n\nexport const COCO_80_LABELS: readonly LabelDefinition[] = [\n { id: 'person', name: 'Person' },\n { id: 'bicycle', name: 'Bicycle' },\n { id: 'car', name: 'Car' },\n { id: 'motorcycle', name: 'Motorcycle' },\n { id: 'airplane', name: 'Airplane' },\n { id: 'bus', name: 'Bus' },\n { id: 'train', name: 'Train' },\n { id: 'truck', name: 'Truck' },\n { id: 'boat', name: 'Boat' },\n { id: 'traffic light', name: 'Traffic Light' },\n { id: 'fire hydrant', name: 'Fire Hydrant' },\n { id: 'stop sign', name: 'Stop Sign' },\n { id: 'parking meter', name: 'Parking Meter' },\n { id: 'bench', name: 'Bench' },\n { id: 'bird', name: 'Bird' },\n { id: 'cat', name: 'Cat' },\n { id: 'dog', name: 'Dog' },\n { id: 'horse', name: 'Horse' },\n { id: 'sheep', name: 'Sheep' },\n { id: 'cow', name: 'Cow' },\n { id: 'elephant', name: 'Elephant' },\n { id: 'bear', name: 'Bear' },\n { id: 'zebra', name: 'Zebra' },\n { id: 'giraffe', name: 'Giraffe' },\n { id: 'backpack', name: 'Backpack' },\n { id: 'umbrella', name: 'Umbrella' },\n { id: 'handbag', name: 'Handbag' },\n { id: 'tie', name: 'Tie' },\n { id: 'suitcase', name: 'Suitcase' },\n { id: 'frisbee', name: 'Frisbee' },\n { id: 'skis', name: 'Skis' },\n { id: 'snowboard', name: 'Snowboard' },\n { id: 'sports ball', name: 'Sports Ball' },\n { id: 'kite', name: 'Kite' },\n { id: 'baseball bat', name: 'Baseball Bat' },\n { id: 'baseball glove', name: 'Baseball Glove' },\n { id: 'skateboard', name: 'Skateboard' },\n { id: 'surfboard', name: 'Surfboard' },\n { id: 'tennis racket', name: 'Tennis Racket' },\n { id: 'bottle', name: 'Bottle' },\n { id: 'wine glass', name: 'Wine Glass' },\n { id: 'cup', name: 'Cup' },\n { id: 'fork', name: 'Fork' },\n { id: 'knife', name: 'Knife' },\n { id: 'spoon', name: 'Spoon' },\n { id: 'bowl', name: 'Bowl' },\n { id: 'banana', name: 'Banana' },\n { id: 'apple', name: 'Apple' },\n { id: 'sandwich', name: 'Sandwich' },\n { id: 'orange', name: 'Orange' },\n { id: 'broccoli', name: 'Broccoli' },\n { id: 'carrot', name: 'Carrot' },\n { id: 'hot dog', name: 'Hot Dog' },\n { id: 'pizza', name: 'Pizza' },\n { id: 'donut', name: 'Donut' },\n { id: 'cake', name: 'Cake' },\n { id: 'chair', name: 'Chair' },\n { id: 'couch', name: 'Couch' },\n { id: 'potted plant', name: 'Potted Plant' },\n { id: 'bed', name: 'Bed' },\n { id: 'dining table', name: 'Dining Table' },\n { id: 'toilet', name: 'Toilet' },\n { id: 'tv', name: 'TV' },\n { id: 'laptop', name: 'Laptop' },\n { id: 'mouse', name: 'Mouse' },\n { id: 'remote', name: 'Remote' },\n { id: 'keyboard', name: 'Keyboard' },\n { id: 'cell phone', name: 'Cell Phone' },\n { id: 'microwave', name: 'Microwave' },\n { id: 'oven', name: 'Oven' },\n { id: 'toaster', name: 'Toaster' },\n { id: 'sink', name: 'Sink' },\n { id: 'refrigerator', name: 'Refrigerator' },\n { id: 'book', name: 'Book' },\n { id: 'clock', name: 'Clock' },\n { id: 'vase', name: 'Vase' },\n { id: 'scissors', name: 'Scissors' },\n { id: 'teddy bear', name: 'Teddy Bear' },\n { id: 'hair drier', name: 'Hair Drier' },\n { id: 'toothbrush', name: 'Toothbrush' },\n] as const\n\nexport const MACRO_LABELS: readonly LabelDefinition[] = [\n { id: 'person', name: 'Person' },\n { id: 'vehicle', name: 'Vehicle' },\n { id: 'animal', name: 'Animal' },\n] as const\n\nexport const COCO_TO_MACRO: ClassMapDefinition = {\n mapping: {\n person: 'person',\n bicycle: 'vehicle',\n car: 'vehicle',\n motorcycle: 'vehicle',\n airplane: 'vehicle',\n bus: 'vehicle',\n train: 'vehicle',\n truck: 'vehicle',\n boat: 'vehicle',\n bird: 'animal',\n cat: 'animal',\n dog: 'animal',\n horse: 'animal',\n sheep: 'animal',\n cow: 'animal',\n elephant: 'animal',\n bear: 'animal',\n zebra: 'animal',\n giraffe: 'animal',\n },\n preserveOriginal: true,\n}\n","export enum DeviceType {\n Camera = 'camera',\n}\n\nexport interface DeviceTypeInfo {\n readonly type: DeviceType\n readonly label: string\n readonly icon: string // lucide icon name\n}\n\nexport const DEVICE_TYPE_INFO: Record<DeviceType, DeviceTypeInfo> = {\n [DeviceType.Camera]: { type: DeviceType.Camera, label: 'Camera', icon: 'camera' },\n}\n"],"mappings":"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","names":["DeviceType"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Addon i18n interface -- allows addons to provide translations
|
|
3
|
+
* for their UI labels, descriptions, and config schema fields.
|
|
4
|
+
*
|
|
5
|
+
* Addons implement IAddonTranslationProvider to supply translations
|
|
6
|
+
* either as a static map or via a dynamic lookup method.
|
|
7
|
+
*/
|
|
8
|
+
/** A flat key-value map of translation strings for a single locale */
|
|
9
|
+
export type TranslationMap = Readonly<Record<string, string>>;
|
|
10
|
+
/** A complete translations bundle keyed by locale code (e.g. 'en', 'it', 'de') */
|
|
11
|
+
export type TranslationBundle = Readonly<Record<string, TranslationMap>>;
|
|
12
|
+
/**
|
|
13
|
+
* Provider interface for addons that supply translations.
|
|
14
|
+
*
|
|
15
|
+
* Addons can provide translations in two ways:
|
|
16
|
+
* 1. A static bundle via `getTranslationBundle()` containing all locales
|
|
17
|
+
* 2. A per-locale lookup via `getTranslations(locale)` for lazy loading
|
|
18
|
+
*
|
|
19
|
+
* At least one method must be implemented. If both are present,
|
|
20
|
+
* `getTranslations()` takes precedence for the requested locale.
|
|
21
|
+
*/
|
|
22
|
+
export interface IAddonTranslationProvider {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
/**
|
|
25
|
+
* Return translations for a specific locale.
|
|
26
|
+
* Returns undefined if the locale is not supported.
|
|
27
|
+
*/
|
|
28
|
+
getTranslations?(locale: string): TranslationMap | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Return the full translation bundle containing all supported locales.
|
|
31
|
+
* Useful when the addon ships all translations statically.
|
|
32
|
+
*/
|
|
33
|
+
getTranslationBundle?(): TranslationBundle;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a translation key against a provider for the given locale.
|
|
37
|
+
* Falls back to 'en' if the requested locale is not available,
|
|
38
|
+
* then falls back to the key itself if no translation is found.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveTranslation(provider: IAddonTranslationProvider, locale: string, key: string): string;
|
|
41
|
+
//# sourceMappingURL=addon-i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-i18n.d.ts","sourceRoot":"","sources":["../../src/interfaces/addon-i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,sEAAsE;AACtE,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAE7D,kFAAkF;AAClF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;AAExE;;;;;;;;;GASG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAA;IAE5D;;;OAGG;IACH,oBAAoB,CAAC,IAAI,iBAAiB,CAAA;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,yBAAyB,EACnC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,MAAM,CA4BR"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { TokenScope } from './scoped-token.js';
|
|
2
|
+
export type RouteAccess = 'public' | 'authenticated' | 'admin';
|
|
3
|
+
/**
|
|
4
|
+
* Request object passed to addon route handlers.
|
|
5
|
+
*/
|
|
6
|
+
export interface AddonHttpRequest {
|
|
7
|
+
readonly params: Record<string, string>;
|
|
8
|
+
readonly query: Record<string, string>;
|
|
9
|
+
readonly body: unknown;
|
|
10
|
+
readonly headers: Record<string, string>;
|
|
11
|
+
/** Populated for 'authenticated' and 'admin' routes */
|
|
12
|
+
readonly user?: {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly username: string;
|
|
15
|
+
readonly role: string;
|
|
16
|
+
};
|
|
17
|
+
/** Populated when request uses a scoped token */
|
|
18
|
+
readonly scopedToken?: {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly userId: string;
|
|
21
|
+
readonly scopes: TokenScope[];
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Reply object for addon route handlers.
|
|
26
|
+
*/
|
|
27
|
+
export interface AddonHttpReply {
|
|
28
|
+
status(code: number): AddonHttpReply;
|
|
29
|
+
send(data: unknown): void;
|
|
30
|
+
redirect(url: string): void;
|
|
31
|
+
header(name: string, value: string): AddonHttpReply;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A single HTTP route registered by an addon.
|
|
35
|
+
*/
|
|
36
|
+
export interface IAddonHttpRoute {
|
|
37
|
+
readonly method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly access: RouteAccess;
|
|
40
|
+
readonly description?: string;
|
|
41
|
+
readonly handler: (request: AddonHttpRequest, reply: AddonHttpReply) => Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Provider interface for addons that expose HTTP endpoints.
|
|
45
|
+
*/
|
|
46
|
+
export interface IAddonRouteProvider {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
getRoutes(): IAddonHttpRoute[];
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=addon-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"addon-routes.d.ts","sourceRoot":"","sources":["../../src/interfaces/addon-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,eAAe,GAAG,OAAO,CAAA;AAE9D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,iDAAiD;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE;QACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;QACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAA;KAC9B,CAAA;CACF;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAAA;IACpC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAAA;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAA;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtF;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,SAAS,IAAI,eAAe,EAAE,CAAA;CAC/B"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import type { PipelineSlot } from '../types/pipeline.js';
|
|
2
|
+
import type { ConfigUISchema } from './config-ui.js';
|
|
3
|
+
import type { IAddonRouter } from './router.js';
|
|
4
|
+
import type { INetworkProvider } from './network.js';
|
|
5
|
+
import type { IScopedLogger } from './logging.js';
|
|
6
|
+
import type { IEventBus } from './event-bus.js';
|
|
7
|
+
import type { IStorageProvider, IStorageLocation, ISettingsBackend, IEmbeddingsBackend } from './storage.js';
|
|
8
|
+
import type { CapabilityDeclaration, CapabilityProviderMap } from './capability.js';
|
|
9
|
+
import type { IElementConfig } from './context.js';
|
|
10
|
+
import type { ITaskHandler } from './task-handler.js';
|
|
11
|
+
import type { SubProcessInfo, WorkerProcessStats } from './worker-protocol.js';
|
|
12
|
+
/** Storage interface for addon file operations */
|
|
13
|
+
export interface IAddonFileStorage {
|
|
14
|
+
readFile(path: string): Promise<Buffer>;
|
|
15
|
+
writeFile(path: string, data: Buffer): Promise<void>;
|
|
16
|
+
deleteFile(path: string): Promise<void>;
|
|
17
|
+
listFiles(prefix?: string): Promise<readonly string[]>;
|
|
18
|
+
exists(path: string): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/** Storage interface for addon structured data (DB) */
|
|
21
|
+
export interface IAddonStructuredStorage {
|
|
22
|
+
query(collection: string, filter?: Record<string, unknown>): Promise<readonly unknown[]>;
|
|
23
|
+
insert(collection: string, data: Record<string, unknown>): Promise<void>;
|
|
24
|
+
update(collection: string, id: string, data: Record<string, unknown>): Promise<void>;
|
|
25
|
+
delete(collection: string, id: string): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
/** Named file storage locations available to addons */
|
|
28
|
+
export type AddonFileLocationName = 'data' | 'media' | 'recordings' | 'models' | 'cache' | 'logs';
|
|
29
|
+
/** Named structured storage locations available to addons */
|
|
30
|
+
export type AddonStructuredLocationName = 'data' | 'events' | 'config';
|
|
31
|
+
/** Combined storage location name (union of file and structured) */
|
|
32
|
+
export type AddonStorageLocationName = AddonFileLocationName | AddonStructuredLocationName;
|
|
33
|
+
/** Storage access for addons -- replaces raw AddonLocationPaths */
|
|
34
|
+
export interface AddonStorageLocations {
|
|
35
|
+
/** Get file storage for a named location */
|
|
36
|
+
getFiles(location: AddonFileLocationName): IAddonFileStorage;
|
|
37
|
+
/** Get structured storage (DB) for a named location */
|
|
38
|
+
getStructured(location: AddonStructuredLocationName): IAddonStructuredStorage;
|
|
39
|
+
}
|
|
40
|
+
export type AddonCapability = 'storage' | 'backup' | 'log-destination' | 'device-exporter' | 'network-access' | 'turn-provider' | 'webrtc-provider' | 'remote-access' | 'recording-engine' | 'notification-output' | 'streaming-engine' | 'pipeline-consumer' | 'detection-engine' | 'object-detector' | 'motion-analyzer' | 'sub-detector' | 'face-detector' | 'plate-detector' | 'recognizer' | 'face-recognizer' | 'plate-recognizer' | 'audio-classifier' | 'device-provider' | 'stream-broker' | 'analysis-data-persistence' | 'analysis-pipeline';
|
|
41
|
+
export interface RequiredStep {
|
|
42
|
+
readonly slot: PipelineSlot;
|
|
43
|
+
readonly outputClasses: readonly string[];
|
|
44
|
+
readonly description: string;
|
|
45
|
+
}
|
|
46
|
+
export interface AddonManifest {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly name: string;
|
|
49
|
+
readonly version: string;
|
|
50
|
+
readonly description?: string;
|
|
51
|
+
/** Relative path to SVG icon asset within the addon package */
|
|
52
|
+
readonly icon?: string;
|
|
53
|
+
/** Brand hex color for UI display (e.g., "#3b82f6") */
|
|
54
|
+
readonly color?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Whether multiple instances of this provider can be created.
|
|
57
|
+
* 'unique' — only one instance allowed (e.g., RTSP, ONVIF)
|
|
58
|
+
* 'multiple' — user can create N instances (e.g., Frigate, Scrypted)
|
|
59
|
+
* Default: 'multiple'
|
|
60
|
+
*/
|
|
61
|
+
readonly instanceMode?: 'unique' | 'multiple';
|
|
62
|
+
/** Whether this addon is protected (required by the system, cannot be uninstalled) */
|
|
63
|
+
readonly protected?: boolean;
|
|
64
|
+
readonly packageName?: string;
|
|
65
|
+
readonly capabilities?: readonly (AddonCapability | {
|
|
66
|
+
name: string;
|
|
67
|
+
mode: string;
|
|
68
|
+
})[];
|
|
69
|
+
readonly requiredFeatures?: readonly string[];
|
|
70
|
+
readonly slot?: PipelineSlot;
|
|
71
|
+
readonly inputClasses?: readonly string[];
|
|
72
|
+
readonly outputClasses?: readonly string[];
|
|
73
|
+
readonly requiredSteps?: readonly RequiredStep[];
|
|
74
|
+
readonly supportsCustomModels?: boolean;
|
|
75
|
+
readonly mayRequirePython?: boolean;
|
|
76
|
+
readonly defaultConfig?: Readonly<Record<string, unknown>>;
|
|
77
|
+
/** Whether this addon performs active inference with models.
|
|
78
|
+
* Passive addons (e.g. motion-detection) set this to false
|
|
79
|
+
* and are excluded from the inference pipeline schema. Default: true. */
|
|
80
|
+
readonly passive?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Label output type — declares what kind of label this addon produces
|
|
83
|
+
* when used as a classifier/recognizer in the pipeline.
|
|
84
|
+
* Used to tag LabelData.origin so the UI can render labels appropriately.
|
|
85
|
+
*/
|
|
86
|
+
readonly labelOutputType?: import('../types/detection.js').LabelOrigin;
|
|
87
|
+
}
|
|
88
|
+
/** @deprecated Use IStorageProvider.resolve() instead of raw paths */
|
|
89
|
+
export interface AddonLocationPaths {
|
|
90
|
+
readonly data: string;
|
|
91
|
+
readonly media: string;
|
|
92
|
+
readonly recordings: string;
|
|
93
|
+
readonly models: string;
|
|
94
|
+
readonly logs: string;
|
|
95
|
+
readonly cache: string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Minimal model-management API exposed to addons via AddonContext.
|
|
99
|
+
*/
|
|
100
|
+
export interface IAddonModelManager {
|
|
101
|
+
/** Ensure a model is downloaded. Returns the local file path. */
|
|
102
|
+
ensure(modelId: string, format?: import('../types/models.js').ModelFormat): Promise<string>;
|
|
103
|
+
/** Ensure extra files for a model are downloaded. Returns paths. */
|
|
104
|
+
ensureExtraFiles(modelId: string): Promise<readonly string[]>;
|
|
105
|
+
/** Absolute path to the shared models directory. */
|
|
106
|
+
getModelsDir(): string;
|
|
107
|
+
/** Check if a model is already downloaded. */
|
|
108
|
+
isDownloaded(modelId: string, format?: import('../types/models.js').ModelFormat): boolean;
|
|
109
|
+
/** @deprecated Use ensure() instead. Legacy API kept for backward compatibility. */
|
|
110
|
+
downloadModel(id: string): Promise<string>;
|
|
111
|
+
}
|
|
112
|
+
/** Process management for addon sub-processes (ffmpeg, python, etc.) */
|
|
113
|
+
export interface IAddonProcessManager {
|
|
114
|
+
/** Spawn a child process managed by this addon's worker */
|
|
115
|
+
spawn(config: SubProcessConfig): Promise<IManagedSubProcess>;
|
|
116
|
+
/** List all sub-processes spawned by this addon */
|
|
117
|
+
listProcesses(): readonly SubProcessInfo[];
|
|
118
|
+
/** Get worker stats (this addon's worker process) */
|
|
119
|
+
getWorkerStats(): WorkerProcessStats;
|
|
120
|
+
}
|
|
121
|
+
export interface SubProcessConfig {
|
|
122
|
+
readonly name: string;
|
|
123
|
+
readonly command: string;
|
|
124
|
+
readonly args?: readonly string[];
|
|
125
|
+
readonly cwd?: string;
|
|
126
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
127
|
+
readonly autoRestart?: boolean;
|
|
128
|
+
readonly maxRestarts?: number;
|
|
129
|
+
}
|
|
130
|
+
export interface IManagedSubProcess {
|
|
131
|
+
readonly pid: number;
|
|
132
|
+
readonly name: string;
|
|
133
|
+
getStats(): WorkerProcessStats;
|
|
134
|
+
write(data: Buffer): void;
|
|
135
|
+
readonly stdout: AsyncIterable<Buffer>;
|
|
136
|
+
readonly stderr: AsyncIterable<Buffer>;
|
|
137
|
+
kill(signal?: NodeJS.Signals): void;
|
|
138
|
+
wait(): Promise<{
|
|
139
|
+
code: number | null;
|
|
140
|
+
signal: string | null;
|
|
141
|
+
}>;
|
|
142
|
+
onExit(handler: (code: number | null) => void): void;
|
|
143
|
+
onError(handler: (error: Error) => void): void;
|
|
144
|
+
}
|
|
145
|
+
/** Dependency manager — ensures binaries/tools are available for addons */
|
|
146
|
+
export interface IAddonDepsManager {
|
|
147
|
+
/** Ensure a named binary is available (check local -> PATH -> download) */
|
|
148
|
+
ensureBinary(opts: {
|
|
149
|
+
readonly name: string;
|
|
150
|
+
readonly downloadUrl: string;
|
|
151
|
+
readonly isArchive?: boolean;
|
|
152
|
+
readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz';
|
|
153
|
+
readonly archiveInnerPath?: string;
|
|
154
|
+
}): Promise<string>;
|
|
155
|
+
/** Ensure ffmpeg is available */
|
|
156
|
+
ensureFfmpeg(): Promise<string>;
|
|
157
|
+
/** Ensure Python is available, returns path or null if unavailable */
|
|
158
|
+
ensurePython(): Promise<string | null>;
|
|
159
|
+
/** Install Python packages in the managed Python environment */
|
|
160
|
+
installPythonPackages(packages: readonly string[]): Promise<void>;
|
|
161
|
+
/** Get the deps directory path */
|
|
162
|
+
getDepsDir(): string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* AddonContext -- injected into every addon at initialize().
|
|
166
|
+
*
|
|
167
|
+
* The context includes both the CamstackContext fields (id, logger, eventBus, storage, config)
|
|
168
|
+
* and addon-specific extras (addonConfig, models, locationPaths, router, network).
|
|
169
|
+
*/
|
|
170
|
+
/**
|
|
171
|
+
* AddonContext -- injected into every addon at initialize().
|
|
172
|
+
*
|
|
173
|
+
* The `api` field is typed as `AddonApi` — a generated interface that
|
|
174
|
+
* mirrors the server's tRPC router namespaces. This gives addons type-safe
|
|
175
|
+
* access to server procedures without depending on the server package.
|
|
176
|
+
*
|
|
177
|
+
* To regenerate after changing routers: npx tsx scripts/generate-api-types.ts
|
|
178
|
+
*/
|
|
179
|
+
export interface AddonContext {
|
|
180
|
+
/** Immutable progressive ID */
|
|
181
|
+
readonly id: string;
|
|
182
|
+
/** Pre-scoped logger */
|
|
183
|
+
readonly logger: IScopedLogger;
|
|
184
|
+
/** System event bus */
|
|
185
|
+
readonly eventBus: IEventBus;
|
|
186
|
+
/** Scoped storage location (legacy — use storageProvider instead) */
|
|
187
|
+
readonly storage: IStorageLocation;
|
|
188
|
+
/** Persisted config store */
|
|
189
|
+
readonly config: IElementConfig;
|
|
190
|
+
/** Bootstrap configuration from server settings (read-only) */
|
|
191
|
+
readonly addonConfig: Readonly<Record<string, unknown>>;
|
|
192
|
+
/** Model management -- download default models or retrieve cached paths. */
|
|
193
|
+
models?: IAddonModelManager;
|
|
194
|
+
/** @deprecated Use storageProvider.resolve() instead */
|
|
195
|
+
readonly locationPaths: AddonLocationPaths;
|
|
196
|
+
/** File storage provider — resolve paths, read/write files per location type */
|
|
197
|
+
readonly storageProvider?: IStorageProvider;
|
|
198
|
+
/** Settings backend — query/insert structured data (events, settings, metadata) */
|
|
199
|
+
readonly settingsBackend?: ISettingsBackend;
|
|
200
|
+
/** Embeddings backend — vector storage for similarity search */
|
|
201
|
+
readonly embeddingsBackend?: IEmbeddingsBackend;
|
|
202
|
+
/**
|
|
203
|
+
* Private data directory for this addon.
|
|
204
|
+
* Resolved via storageProvider.resolve('addons-data', '{addonId}/').
|
|
205
|
+
* The addon owns this directory exclusively.
|
|
206
|
+
*/
|
|
207
|
+
readonly dataDir: string;
|
|
208
|
+
/** HTTP router for registering addon routes */
|
|
209
|
+
readonly router?: IAddonRouter;
|
|
210
|
+
/** Network access provider */
|
|
211
|
+
readonly network?: INetworkProvider;
|
|
212
|
+
/**
|
|
213
|
+
* Register a task handler that can be dispatched by the hub.
|
|
214
|
+
* Only effective in agent mode — in hub mode, handlers are stored but not dispatched.
|
|
215
|
+
*/
|
|
216
|
+
registerTaskHandler?(handler: ITaskHandler): void;
|
|
217
|
+
/** Process management — spawn and monitor sub-processes */
|
|
218
|
+
readonly process?: IAddonProcessManager;
|
|
219
|
+
/** Dependency management — ensure binary/tool availability */
|
|
220
|
+
readonly deps?: IAddonDepsManager;
|
|
221
|
+
/**
|
|
222
|
+
* Full tRPC client — same API as the frontend.
|
|
223
|
+
* Transport is transparent: direct caller (in-process), WSS (worker), or WSS (remote agent).
|
|
224
|
+
* Use this for all server interactions: storage, events, devices, streaming, etc.
|
|
225
|
+
*/
|
|
226
|
+
readonly api?: import('../generated/addon-api.js').AddonApi;
|
|
227
|
+
}
|
|
228
|
+
export interface ICamstackAddon {
|
|
229
|
+
readonly id?: string;
|
|
230
|
+
readonly manifest: AddonManifest;
|
|
231
|
+
initialize(context: AddonContext): Promise<void>;
|
|
232
|
+
shutdown(): Promise<void>;
|
|
233
|
+
getConfigSchema?(): ConfigUISchema;
|
|
234
|
+
/**
|
|
235
|
+
* Return the provider instance for a declared capability.
|
|
236
|
+
* Called by CapabilityRegistry after initialize() succeeds.
|
|
237
|
+
* Returns null if this addon does not provide the requested capability.
|
|
238
|
+
*/
|
|
239
|
+
getCapabilityProvider?<K extends keyof CapabilityProviderMap>(name: K): CapabilityProviderMap[K] | null;
|
|
240
|
+
}
|
|
241
|
+
/** Declaration of a UI page provided by an addon */
|
|
242
|
+
export interface AddonPageDeclaration {
|
|
243
|
+
/** Unique page ID (scoped to addon) */
|
|
244
|
+
readonly id: string;
|
|
245
|
+
/** Display label for sidebar */
|
|
246
|
+
readonly label: string;
|
|
247
|
+
/** Lucide icon name for sidebar */
|
|
248
|
+
readonly icon: string;
|
|
249
|
+
/** Route path (e.g., '/benchmark') */
|
|
250
|
+
readonly path: string;
|
|
251
|
+
/** Relative path to JS bundle within addon package (default export = React component) */
|
|
252
|
+
readonly bundle: string;
|
|
253
|
+
/** @deprecated Web component element name — addon pages now export React components */
|
|
254
|
+
readonly element?: string;
|
|
255
|
+
}
|
|
256
|
+
/** Provider interface for addons that expose UI pages */
|
|
257
|
+
export interface IAddonPageProvider {
|
|
258
|
+
readonly id: string;
|
|
259
|
+
getPages(): readonly AddonPageDeclaration[];
|
|
260
|
+
}
|
|
261
|
+
/** Provider interface for the admin UI shell (singleton capability) */
|
|
262
|
+
export interface IAdminUI {
|
|
263
|
+
getStaticDir(): string;
|
|
264
|
+
getVersion(): string;
|
|
265
|
+
}
|
|
266
|
+
export interface AddonDeclaration {
|
|
267
|
+
readonly id: string;
|
|
268
|
+
readonly entry: string;
|
|
269
|
+
readonly slot: PipelineSlot;
|
|
270
|
+
/** Relative path to SVG icon asset within the addon package */
|
|
271
|
+
readonly icon?: string;
|
|
272
|
+
/** Brand hex color for UI display */
|
|
273
|
+
readonly color?: string;
|
|
274
|
+
/** Instance mode: 'unique' or 'multiple'. Default: 'multiple' */
|
|
275
|
+
readonly instanceMode?: 'unique' | 'multiple';
|
|
276
|
+
/** @deprecated Use inProcess instead. Legacy opt-in flag for forking. */
|
|
277
|
+
readonly forkable?: boolean;
|
|
278
|
+
/**
|
|
279
|
+
* Force this addon to stay in-process (no forking).
|
|
280
|
+
* Default: false — all non-infra addons are forked by default.
|
|
281
|
+
* Use CAMSTACK_FORCE_INPROCESS=true env var for emergency global fallback.
|
|
282
|
+
*/
|
|
283
|
+
readonly inProcess?: boolean;
|
|
284
|
+
/** Capabilities this addon provides. Declared in package.json camstack.addons[].capabilities */
|
|
285
|
+
readonly capabilities?: readonly CapabilityDeclaration[];
|
|
286
|
+
/** UI pages provided by this addon */
|
|
287
|
+
readonly pages?: readonly AddonPageDeclaration[];
|
|
288
|
+
}
|
|
289
|
+
export interface AddonPackageManifest {
|
|
290
|
+
/** Human-readable package name for UI display (e.g., "CamStack Vision") */
|
|
291
|
+
readonly displayName?: string;
|
|
292
|
+
readonly addons: readonly AddonDeclaration[];
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=addon.d.ts.map
|