@camera.ui/sdk 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/dist/camera/events.js +2 -0
  4. package/dist/camera/index.js +3 -1
  5. package/dist/external.js +7 -0
  6. package/dist/index.d.ts +7132 -4248
  7. package/dist/index.js +3 -11
  8. package/dist/internal/contract-validators.js +21 -0
  9. package/dist/internal/index.d.ts +915 -0
  10. package/dist/internal/index.js +9 -0
  11. package/dist/internal/sensor-triggers.js +2 -0
  12. package/dist/internal/shared-utils.js +86 -0
  13. package/dist/internal/streaming-internal.js +1 -0
  14. package/dist/manager/index.js +1 -1
  15. package/dist/observable/index.js +419 -0
  16. package/dist/plugin/api.js +21 -0
  17. package/dist/plugin/contract.js +101 -114
  18. package/dist/plugin/helper.js +277 -0
  19. package/dist/plugin/index.js +4 -1
  20. package/dist/plugin/interfaces.js +51 -1
  21. package/dist/plugin/notifier.js +23 -0
  22. package/dist/plugin/oauth.js +1 -0
  23. package/dist/sensor/audio.js +103 -81
  24. package/dist/sensor/base.js +350 -318
  25. package/dist/sensor/battery.js +73 -59
  26. package/dist/sensor/classifier.js +117 -0
  27. package/dist/sensor/clip.js +30 -0
  28. package/dist/sensor/contact.js +37 -18
  29. package/dist/sensor/detection.js +4 -0
  30. package/dist/sensor/doorbell.js +52 -38
  31. package/dist/sensor/face.js +71 -86
  32. package/dist/sensor/garage.js +121 -0
  33. package/dist/sensor/humidity.js +52 -0
  34. package/dist/sensor/index.js +17 -11
  35. package/dist/sensor/leak.js +52 -0
  36. package/dist/sensor/licensePlate.js +70 -79
  37. package/dist/sensor/light.js +82 -38
  38. package/dist/sensor/lock.js +99 -0
  39. package/dist/sensor/motion.js +85 -70
  40. package/dist/sensor/object.js +73 -94
  41. package/dist/sensor/occupancy.js +52 -0
  42. package/dist/sensor/ptz.js +114 -100
  43. package/dist/sensor/securitySystem.js +98 -0
  44. package/dist/sensor/siren.js +75 -43
  45. package/dist/sensor/smoke.js +52 -0
  46. package/dist/sensor/spec.js +1 -0
  47. package/dist/sensor/switch.js +72 -0
  48. package/dist/sensor/temperature.js +52 -0
  49. package/dist/storage/index.js +1 -2
  50. package/dist/types.js +1 -0
  51. package/docs/.vitepress/config.ts +77 -0
  52. package/docs/.vitepress/theme/index.ts +5 -0
  53. package/docs/.vitepress/theme/style.css +117 -0
  54. package/docs/index.md +16 -0
  55. package/docs/logo.png +0 -0
  56. package/docs/public/apple-touch-icon.png +0 -0
  57. package/docs/public/favicon-16.ico +0 -0
  58. package/docs/public/favicon.ico +0 -0
  59. package/docs/public/logo.svg +1 -0
  60. package/examples/README.md +7 -0
  61. package/examples/getting-started.md +535 -0
  62. package/package.json +36 -23
  63. package/scripts/build-example-docs.mjs +62 -0
  64. package/tsconfig.node.json +3 -2
  65. package/typedoc.json +42 -0
  66. package/dist/sensor/guards.js +0 -133
  67. package/dist/sensor/types.js +0 -46
  68. package/dist/service/base.js +0 -96
  69. package/dist/service/index.js +0 -3
  70. /package/dist/camera/{types.js → enums.js} +0 -0
  71. /package/dist/{manager/types.js → camera/frames.js} +0 -0
  72. /package/dist/{plugin/types.js → internal/camera-config-internal.js} +0 -0
  73. /package/dist/{service/services.js → internal/camera-enums.js} +0 -0
  74. /package/dist/{service/types.js → internal/camera-wire.js} +0 -0
  75. /package/dist/{storage/schema.js → internal/manager-rpc.js} +0 -0
  76. /package/dist/{storage/storages.js → internal/sensor-rpc.js} +0 -0
@@ -0,0 +1,915 @@
1
+ import type { Disposable } from '@camera.ui/sdk';
2
+ /**
3
+ * Subscription handle returned by `subscribe()`.
4
+ *
5
+ * Call `dispose()` (or its alias `unsubscribe()`) to detach the listener
6
+ * and run any teardown logic registered by the producer. Disposing twice
7
+ * is a no-op.
8
+ */
9
+
10
+ /** Built-in detection label types recognized across the system. */
11
+ declare const DETECTION_LABELS: readonly ["motion", "person", "vehicle", "animal", "package", "audio"];
12
+ /** Union of the built-in detection label strings. */
13
+ type DetectionLabel = (typeof DETECTION_LABELS)[number];
14
+ /**
15
+ * Bounding box of a detection. All coordinates are normalized to 0–1
16
+ * (fraction of frame dimensions), so they are independent of resolution.
17
+ */
18
+ interface BoundingBox {
19
+ /** X coordinate of the top-left corner (0–1). */
20
+ x: number;
21
+ /** Y coordinate of the top-left corner (0–1). */
22
+ y: number;
23
+ /** Width as a fraction of frame width (0–1). */
24
+ width: number;
25
+ /** Height as a fraction of frame height (0–1). */
26
+ height: number;
27
+ }
28
+
29
+ /** Expected video input dimensions and pixel format for a detector model. */
30
+ interface VideoInputSpec {
31
+ /** Expected frame width in pixels. */
32
+ width: number;
33
+ /** Expected frame height in pixels. */
34
+ height: number;
35
+ /** Pixel format: `'rgb'` = 3 bytes/pixel, `'gray'` = 1 byte/pixel, `'nv12'` = YUV semi-planar. */
36
+ format: 'rgb' | 'nv12' | 'gray';
37
+ }
38
+ /**
39
+ * Model spec for detectors with fixed output labels (face, classifier, license plate).
40
+ * Declares the input shape the backend should produce and the trigger labels
41
+ * that should activate this detector.
42
+ */
43
+ interface ModelSpec {
44
+ /** Required input frame dimensions and pixel format. */
45
+ input: VideoInputSpec;
46
+ /** Labels emitted by an upstream object detector that activate this detector (e.g. `['person']` for face detection). */
47
+ triggerLabels: DetectionLabel[];
48
+ /** Embedding model identifier for face recognition. */
49
+ embeddingModel?: string;
50
+ }
51
+
52
+ /**
53
+ * Property names of an audio detection sensor.
54
+ *
55
+ * @internal
56
+ */
57
+ declare enum AudioProperty {
58
+ /** Whether an audio event is currently detected. */
59
+ Detected = "detected",
60
+ /** List of detected audio events (e.g. glass break, scream). */
61
+ Detections = "detections",
62
+ /** Current audio level in decibels. */
63
+ Decibels = "decibels",
64
+ /** Timestamp in milliseconds of the last detection trigger, set by the backend. */
65
+ LastTriggered = "lastTriggered"
66
+ }
67
+
68
+ /**
69
+ * Properties for battery info sensors
70
+ *
71
+ * @internal
72
+ */
73
+ declare enum BatteryProperty {
74
+ /** Battery level percentage (0–100) */
75
+ Level = "level",
76
+ /** Current charging state */
77
+ Charging = "charging",
78
+ /** Whether battery is critically low */
79
+ Low = "low"
80
+ }
81
+
82
+ /**
83
+ * Properties for contact sensors
84
+ *
85
+ * @internal
86
+ */
87
+ declare enum ContactProperty {
88
+ /** Whether the contact is open (true = open, false = closed) */
89
+ Detected = "detected"
90
+ }
91
+
92
+ /**
93
+ * Properties for doorbell triggers
94
+ *
95
+ * @internal
96
+ */
97
+ declare enum DoorbellProperty {
98
+ /** Whether the doorbell is currently ringing */
99
+ Ring = "ring"
100
+ }
101
+
102
+ /**
103
+ * Property names of a face detection sensor.
104
+ *
105
+ * @internal
106
+ */
107
+ declare enum FaceProperty {
108
+ /** Whether any face is currently detected. */
109
+ Detected = "detected",
110
+ /** List of detected faces with optional identity, embedding, and thumbnail. */
111
+ Detections = "detections"
112
+ }
113
+
114
+ /**
115
+ * Properties for garage controls
116
+ *
117
+ * @internal
118
+ */
119
+ declare enum GarageProperty {
120
+ /** The actual current state of the garage door */
121
+ CurrentState = "currentState",
122
+ /** The desired target state (set by user, transitions to currentState) */
123
+ TargetState = "targetState",
124
+ /** Whether an obstruction is detected */
125
+ ObstructionDetected = "obstructionDetected"
126
+ }
127
+
128
+ /**
129
+ * Properties for humidity sensors
130
+ *
131
+ * @internal
132
+ */
133
+ declare enum HumidityProperty {
134
+ /** Current relative humidity (0–100%) */
135
+ Current = "current"
136
+ }
137
+
138
+ /**
139
+ * Properties for leak sensors
140
+ *
141
+ * @internal
142
+ */
143
+ declare enum LeakProperty {
144
+ /** Whether a leak is detected */
145
+ Detected = "detected"
146
+ }
147
+
148
+ /**
149
+ * Property names of a license plate detection sensor.
150
+ *
151
+ * @internal
152
+ */
153
+ declare enum LicensePlateProperty {
154
+ /** Whether any license plate is currently detected. */
155
+ Detected = "detected",
156
+ /** List of detected plates with OCR text. */
157
+ Detections = "detections"
158
+ }
159
+
160
+ /**
161
+ * Properties for light controls
162
+ *
163
+ * @internal
164
+ */
165
+ declare enum LightProperty {
166
+ /** Whether the light is on */
167
+ On = "on",
168
+ /** Brightness level (0–100) */
169
+ Brightness = "brightness"
170
+ }
171
+
172
+ /**
173
+ * Properties for lock controls
174
+ *
175
+ * @internal
176
+ */
177
+ declare enum LockProperty {
178
+ /** The actual current state of the lock */
179
+ CurrentState = "currentState",
180
+ /** The desired target state (set by user, transitions to currentState) */
181
+ TargetState = "targetState"
182
+ }
183
+
184
+ /**
185
+ * Property names of a motion sensor.
186
+ *
187
+ * @internal
188
+ */
189
+ declare enum MotionProperty {
190
+ /** Whether motion is currently detected. */
191
+ Detected = "detected",
192
+ /** List of detection results with bounding boxes. */
193
+ Detections = "detections",
194
+ /** When true, detection updates are suppressed (set by the backend dwell logic). */
195
+ Blocked = "blocked",
196
+ /** Timestamp in milliseconds of the last detection trigger, set by the backend. */
197
+ LastTriggered = "lastTriggered"
198
+ }
199
+
200
+ /**
201
+ * Property names of an object detection sensor.
202
+ *
203
+ * @internal
204
+ */
205
+ declare enum ObjectProperty {
206
+ /** Whether any object is currently detected. */
207
+ Detected = "detected",
208
+ /** List of detected objects with labels and bounding boxes. */
209
+ Detections = "detections",
210
+ /** Unique labels of the current detections (auto-derived when reporting detections). */
211
+ Labels = "labels"
212
+ }
213
+
214
+ /**
215
+ * Properties for occupancy sensors
216
+ *
217
+ * @internal
218
+ */
219
+ declare enum OccupancyProperty {
220
+ /** Whether occupancy is detected (true = occupied) */
221
+ Detected = "detected"
222
+ }
223
+
224
+ /**
225
+ * Properties for PTZ controls
226
+ *
227
+ * @internal
228
+ */
229
+ declare enum PTZProperty {
230
+ /** Current pan/tilt/zoom position */
231
+ Position = "position",
232
+ /** Whether the camera is currently moving */
233
+ Moving = "moving",
234
+ /** List of available preset names */
235
+ Presets = "presets",
236
+ /** Current movement velocity (continuous move) */
237
+ Velocity = "velocity",
238
+ /** Target preset to move to */
239
+ TargetPreset = "targetPreset"
240
+ }
241
+
242
+ /**
243
+ * Properties for security system controls
244
+ *
245
+ * @internal
246
+ */
247
+ declare enum SecuritySystemProperty {
248
+ /** The actual current state of the security system */
249
+ CurrentState = "currentState",
250
+ /** The desired target state (set by user, transitions to currentState) */
251
+ TargetState = "targetState"
252
+ }
253
+
254
+ /**
255
+ * Properties for siren controls
256
+ *
257
+ * @internal
258
+ */
259
+ declare enum SirenProperty {
260
+ /** Whether the siren is currently active */
261
+ Active = "active",
262
+ /** Volume level (0–100) */
263
+ Volume = "volume"
264
+ }
265
+
266
+ /**
267
+ * Properties for smoke sensors
268
+ *
269
+ * @internal
270
+ */
271
+ declare enum SmokeProperty {
272
+ /** Whether smoke is detected */
273
+ Detected = "detected"
274
+ }
275
+
276
+ /**
277
+ * Properties for switch controls
278
+ *
279
+ * @internal
280
+ */
281
+ declare enum SwitchProperty {
282
+ /** Whether the switch is on */
283
+ On = "on"
284
+ }
285
+
286
+ /**
287
+ * Properties for temperature sensors
288
+ *
289
+ * @internal
290
+ */
291
+ declare enum TemperatureProperty {
292
+ /** Current temperature in degrees Celsius */
293
+ Current = "current"
294
+ }
295
+
296
+ /** Emitted when a sensor property value changes */
297
+ interface PropertyChangedEvent {
298
+ cameraId: string;
299
+ sensorId: string;
300
+ sensorType: SensorType;
301
+ /** The property enum value that changed */
302
+ property: SensorPropertyType;
303
+ value: unknown;
304
+ previousValue?: unknown;
305
+ timestamp: number;
306
+ }
307
+ /**
308
+ * Receives a partial-state delta (only properties that actually changed). One callback
309
+ * invocation per `_writeState` call — atomic from the receiver's perspective.
310
+ *
311
+ * @internal
312
+ */
313
+ type PropertyUpdateFn = (properties: Record<string, unknown>) => void;
314
+ /** Callback for detailed property change events */
315
+ type PropertyChangeListener = (event: PropertyChangedEvent) => void;
316
+ /**
317
+ * @internal
318
+ */
319
+ type CapabilityUpdateFn = (capabilities: string[]) => void;
320
+ /** JSON-serializable representation of a sensor for RPC transport */
321
+ interface SensorJSON {
322
+ id: string;
323
+ type: SensorType;
324
+ name: string;
325
+ displayName: string;
326
+ category: SensorCategory;
327
+ cameraId: string;
328
+ pluginId?: string;
329
+ properties: Record<string, unknown>;
330
+ capabilities?: string[];
331
+ /** True if this sensor needs video/audio frames from the backend pipeline */
332
+ requiresFrames?: boolean;
333
+ modelSpec?: ModelSpec;
334
+ }
335
+
336
+ /** Union of all sensor-specific property enums */
337
+ type SensorPropertyType = AudioProperty | BatteryProperty | ContactProperty | DoorbellProperty | FaceProperty | GarageProperty | HumidityProperty | LeakProperty | LicensePlateProperty | LightProperty | LockProperty | MotionProperty | ObjectProperty | OccupancyProperty | PTZProperty | SecuritySystemProperty | SirenProperty | SmokeProperty | SwitchProperty | TemperatureProperty;
338
+ /**
339
+ * Type of sensor. Each maps to a smart-home concept (HomeKit service).
340
+ * Plugins create sensors of these types and attach them to cameras.
341
+ */
342
+ declare enum SensorType {
343
+ /** Video-based motion detection */
344
+ Motion = "motion",
345
+ /** Object detection (person, vehicle, animal, etc.) */
346
+ Object = "object",
347
+ /** Audio event detection (glass break, scream, etc.) */
348
+ Audio = "audio",
349
+ /** Face detection and recognition */
350
+ Face = "face",
351
+ /** License plate detection and OCR */
352
+ LicensePlate = "licensePlate",
353
+ /** General-purpose image classifier */
354
+ Classifier = "classifier",
355
+ /** CLIP embedding generation for semantic search */
356
+ Clip = "clip",
357
+ /** Contact/open-close sensor (door, window) */
358
+ Contact = "contact",
359
+ /** Temperature sensor (°C) */
360
+ Temperature = "temperature",
361
+ /** Humidity sensor (0–100%) */
362
+ Humidity = "humidity",
363
+ /** Occupancy/presence sensor */
364
+ Occupancy = "occupancy",
365
+ /** Smoke detector */
366
+ Smoke = "smoke",
367
+ /** Water leak detector */
368
+ Leak = "leak",
369
+ /** Light on/off and brightness control */
370
+ Light = "light",
371
+ /** Siren on/off and volume control */
372
+ Siren = "siren",
373
+ /** Generic on/off switch */
374
+ Switch = "switch",
375
+ /** Lock/unlock control */
376
+ Lock = "lock",
377
+ /** Pan-tilt-zoom camera control */
378
+ PTZ = "ptz",
379
+ /** Security system arm/disarm control */
380
+ SecuritySystem = "securitySystem",
381
+ /** Garage door opener */
382
+ Garage = "garage",
383
+ /** Doorbell ring trigger */
384
+ Doorbell = "doorbell",
385
+ /** Battery level and charging state */
386
+ Battery = "battery"
387
+ }
388
+ /**
389
+ * Categorizes a sensor's role in the system.
390
+ * Determines how the backend treats the sensor (read-only vs. controllable).
391
+ */
392
+ declare enum SensorCategory {
393
+ /** Read-only detection sensor (motion, object, audio, etc.) */
394
+ Sensor = "sensor",
395
+ /** Controllable sensor with set methods (light, siren, PTZ, etc.) */
396
+ Control = "control",
397
+ /** Event trigger (doorbell ring) */
398
+ Trigger = "trigger",
399
+ /** Informational read-only state (battery level) */
400
+ Info = "info"
401
+ }
402
+
403
+ /**
404
+ * Python interpreter major.minor version a Python plugin requires. The host
405
+ * ensures a matching interpreter exists in its venv pool before launching
406
+ * the plugin; Node and Go plugins ignore this field.
407
+ */
408
+ type PythonVersion = '3.11' | '3.12';
409
+ /**
410
+ * Role a plugin plays in the system. The role decides which lifecycle hooks
411
+ * the host invokes and which contract validations apply (see helper.ts).
412
+ */
413
+ declare enum PluginRole {
414
+ /**
415
+ * Cloud-service integration that manages its own cameras end-to-end via a
416
+ * vendor account (e.g. a vendor SDK / cloud API). The hub owns camera
417
+ * creation, streaming and sensors; it cannot expose sensors for cameras
418
+ * owned by other plugins.
419
+ */
420
+ Hub = "hub",
421
+ /**
422
+ * Adds sensors to existing cameras without owning the camera itself.
423
+ * Typical use: a detection plugin that consumes another plugin's video
424
+ * frames and emits motion / object / face detections back into the system.
425
+ */
426
+ SensorProvider = "sensorProvider",
427
+ /**
428
+ * Manages cameras and their media streams (ONVIF, RTSP, generic IP, ...).
429
+ * The plugin is responsible for stream URLs, PTZ, snapshots, and the
430
+ * lifecycle hooks in BasePlugin. It does not produce sensors for foreign
431
+ * cameras.
432
+ */
433
+ CameraController = "cameraController",
434
+ /**
435
+ * Combined role: plugin both manages cameras and exposes sensors (its own
436
+ * cameras and, when consumes is set, also foreign cameras). Used by
437
+ * integrations that ship a complete camera + detection stack.
438
+ */
439
+ CameraAndSensorProvider = "cameraAndSensorProvider"
440
+ }
441
+ /**
442
+ * Capability flags a plugin advertises in its contract. The host uses these
443
+ * to decide which RPC handlers to wire up and which UI affordances to show.
444
+ */
445
+ declare enum PluginInterface {
446
+ /** Implements MotionDetectionInterface (video-based motion detection). */
447
+ MotionDetection = "MotionDetection",
448
+ /** Implements ObjectDetectionInterface (e.g. person, vehicle, animal). */
449
+ ObjectDetection = "ObjectDetection",
450
+ /** Implements AudioDetectionInterface (event/keyword audio detection). */
451
+ AudioDetection = "AudioDetection",
452
+ /**
453
+ * Implements FaceDetectionInterface (face localisation + embeddings). The
454
+ * NVR owns matching against enrolled faces; the plugin only emits
455
+ * detections + embeddings.
456
+ */
457
+ FaceDetection = "FaceDetection",
458
+ /** Implements LicensePlateDetectionInterface (plate localisation + OCR). */
459
+ LicensePlateDetection = "LicensePlateDetection",
460
+ /**
461
+ * Implements ClassifierDetectionInterface (generic image classification
462
+ * emitting attribute/label pairs).
463
+ */
464
+ ClassifierDetection = "ClassifierDetection",
465
+ /**
466
+ * Implements ClipDetectionInterface (CLIP image and text embeddings used
467
+ * for semantic search).
468
+ */
469
+ ClipDetection = "ClipDetection",
470
+ /**
471
+ * Implements DiscoveryProvider — plugin can scan the network for new
472
+ * cameras and adopt them. Only valid for camera-controlling roles.
473
+ */
474
+ DiscoveryProvider = "DiscoveryProvider",
475
+ /**
476
+ * Implements NVRInterface — persists events and recordings, and serves
477
+ * them back to the UI / mobile clients. Exactly one plugin per host
478
+ * fills this role at runtime.
479
+ */
480
+ NVR = "NVR",
481
+ /**
482
+ * Implements NotifierInterface (getDevices, sendNotification, ...). Lets
483
+ * the central NotificationManager dispatch notifications to this plugin
484
+ * regardless of role — see notifier.ts.
485
+ */
486
+ Notifier = "Notifier",
487
+ /**
488
+ * Implements the OAuthCapable base interface (getOAuthMetadata,
489
+ * getOAuthState, disconnect) plus at least one flow sub-interface below —
490
+ * see oauth.ts.
491
+ */
492
+ OAuthCapable = "OAuthCapable",
493
+ /** Implements OAuthDeviceFlowCapable (RFC 8628 Device Authorization Grant). */
494
+ OAuthDeviceFlow = "OAuthDeviceFlow",
495
+ /** Implements OAuthAuthCodeFlowCapable (Authorization Code Flow + PKCE). */
496
+ OAuthAuthCodeFlow = "OAuthAuthCodeFlow",
497
+ /** Implements OAuthClientCredentialsCapable (user-supplied client_id + client_secret). */
498
+ OAuthClientCredentials = "OAuthClientCredentials"
499
+ }
500
+ /**
501
+ * Permission a plugin requests so it can call a host-provided system feature.
502
+ * Each capability gates one outgoing SDK call — calls without the matching
503
+ * capability are rejected by the host.
504
+ */
505
+ declare enum PluginCapability {
506
+ /**
507
+ * Grants the plugin permission to call `api.notificationManager.publish`.
508
+ * Without this capability the host silently drops published notifications
509
+ * and logs an error.
510
+ */
511
+ PublishNotifications = "publishNotifications"
512
+ }
513
+ /**
514
+ * Manifest contract a plugin declares so the host knows what it does and
515
+ * what it needs at load time. Validated by helper.ts before the plugin is
516
+ * started.
517
+ */
518
+ interface PluginContract {
519
+ /**
520
+ * Stable, unique identifier for the plugin instance — used as the
521
+ * registry key, log prefix and the storage namespace.
522
+ */
523
+ name: string;
524
+ /** Role of the plugin (see {@link PluginRole}). */
525
+ role: PluginRole;
526
+ /**
527
+ * Sensor types the plugin produces. Empty for hubs and pure
528
+ * camera-controllers; required for sensor providers.
529
+ */
530
+ provides: SensorType[];
531
+ /**
532
+ * Sensor types the plugin reads from other plugins (e.g. a face plugin
533
+ * consumes camera video frames).
534
+ */
535
+ consumes: SensorType[];
536
+ /** Capability flags the plugin implements (see {@link PluginInterface}). */
537
+ interfaces: PluginInterface[];
538
+ /**
539
+ * Permissions the plugin requests to call host system features (see
540
+ * {@link PluginCapability}). The host enforces these — calls without a
541
+ * matching capability are rejected.
542
+ */
543
+ capabilities?: PluginCapability[];
544
+ /**
545
+ * Required Python interpreter version for Python plugins. Ignored by
546
+ * Node / Go plugins.
547
+ */
548
+ pythonVersion?: PythonVersion;
549
+ /**
550
+ * Extra package dependencies installed into the plugin's runtime (PyPI
551
+ * for Python plugins, npm for Node plugins).
552
+ */
553
+ dependencies?: string[];
554
+ }
555
+
556
+ /**
557
+ * Reports whether the plugin can be queried for camera discovery — it must
558
+ * both implement the DiscoveryProvider interface and have a camera-owning
559
+ * role.
560
+ *
561
+ * @param contract - Plugin contract to inspect.
562
+ *
563
+ * @returns `true` if the plugin is a usable discovery provider.
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * import { isDiscoveryProvider } from '@camera.ui/sdk/internal';
568
+ *
569
+ * if (isDiscoveryProvider(contract)) await runDiscovery(contract);
570
+ * ```
571
+ */
572
+ declare function isDiscoveryProvider(contract: PluginContract): boolean;
573
+
574
+ /**
575
+ * Camera stream resolution role.
576
+ * Used to identify different quality streams from the same camera.
577
+ */
578
+ type CameraRole = 'high-resolution' | 'mid-resolution' | 'low-resolution' | 'snapshot';
579
+ /**
580
+ * Detection event message type (lifecycle phase).
581
+ */
582
+ type DetectionEventType = 'start' | 'end' | 'update' | 'segment-start' | 'segment-update' | 'segment-end';
583
+ /**
584
+ * Event lifecycle state.
585
+ */
586
+ type DetectionEventState = 'active' | 'ended';
587
+ /**
588
+ * Event trigger type.
589
+ */
590
+ type EventTriggerType = 'motion' | 'audio' | 'contact' | 'doorbell' | 'switch' | 'light' | 'siren' | 'security_system' | 'line-crossing';
591
+
592
+ /**
593
+ * Camera input settings (user configuration).
594
+ */
595
+ interface CameraInputSettings {
596
+ /** Unique source ID */
597
+ readonly _id: string;
598
+ /** Source display name */
599
+ name: string;
600
+ /** Resolution role */
601
+ role: CameraRole;
602
+ /** Use this source for snapshots */
603
+ useForSnapshot: boolean;
604
+ /** Keep connection always active */
605
+ hotMode: boolean;
606
+ /** Preload stream on startup */
607
+ preload: boolean;
608
+ /** Enable stream prebuffering */
609
+ prebuffer: boolean;
610
+ /** User-provided stream URLs */
611
+ urls: string[];
612
+ /** Child source ID (for snapshot fallback) */
613
+ childSourceId?: string;
614
+ }
615
+ /**
616
+ * Camera configuration subset for partial updates.
617
+ */
618
+ type CameraConfigPartial = Partial<BaseCameraConfig> & {
619
+ sources?: Partial<CameraConfigInputSettings>[];
620
+ };
621
+
622
+ /**
623
+ * WebRTC ICE server configuration.
624
+ */
625
+ interface IceServer {
626
+ /** STUN/TURN server URLs */
627
+ urls: string[];
628
+ /** Authentication username */
629
+ username?: string;
630
+ /** Authentication credential */
631
+ credential?: string;
632
+ }
633
+ /**
634
+ * Subscription management interface for sessions.
635
+ */
636
+ interface Subscribed {
637
+ /** Add subscriptions to be cleaned up on unsubscribe */
638
+ addSubscriptions(...subscriptions: Disposable[]): void;
639
+ /** Add additional subscriptions (separate cleanup) */
640
+ addAdditionalSubscriptions(...subscriptions: Disposable[]): void;
641
+ /** Unsubscribe all main subscriptions */
642
+ unsubscribe(): void;
643
+ /** Unsubscribe additional subscriptions only */
644
+ unsubscribeAdditional(): void;
645
+ }
646
+
647
+ /**
648
+ * Camera input settings for config.
649
+ */
650
+ interface CameraConfigInputSettings extends Omit<CameraInputSettings, '_id' | 'urls'> {
651
+ urls?: string[];
652
+ }
653
+ /**
654
+ * Base camera configuration (shared fields).
655
+ */
656
+ interface BaseCameraConfig {
657
+ /** Camera display name */
658
+ name: string;
659
+ /** Native device ID from plugin */
660
+ nativeId?: string;
661
+ /** Whether camera streams from cloud */
662
+ isCloud?: boolean;
663
+ /** Disable this camera */
664
+ disabled?: boolean;
665
+ /** Camera hardware information */
666
+ info?: Partial<CameraInformation>;
667
+ }
668
+ /**
669
+ * Camera hardware/firmware information.
670
+ */
671
+ interface CameraInformation {
672
+ /** Camera model name */
673
+ model?: string;
674
+ /** Manufacturer name */
675
+ manufacturer?: string;
676
+ /** Hardware version/revision */
677
+ hardware?: string;
678
+ /** Device serial number */
679
+ serialNumber?: string;
680
+ /** Current firmware version */
681
+ firmwareVersion?: string;
682
+ /** Manufacturer support URL */
683
+ supportUrl?: string;
684
+ }
685
+
686
+ /** AI-generated event description. */
687
+ interface EventDescription {
688
+ /** Brief title of what occurred */
689
+ title: string;
690
+ /** Chronological narrative of the scene */
691
+ description: string;
692
+ /** Two-sentence notification-friendly summary */
693
+ summary: string;
694
+ /** Threat level: 0 = normal, 1 = suspicious, 2 = threat */
695
+ threatLevel: number;
696
+ }
697
+ /**
698
+ * Event trigger (motion, audio, sensor, or line-crossing).
699
+ */
700
+ interface EventTrigger {
701
+ /** Trigger type */
702
+ type: EventTriggerType;
703
+ /** Audio label (e.g. "doorbell", "glass_break") */
704
+ label?: string;
705
+ /** Best confidence score */
706
+ score?: number;
707
+ /** First detection time (Unix ms) */
708
+ firstSeen: number;
709
+ /** Last detection time (Unix ms) */
710
+ lastSeen: number;
711
+ /** Name of the crossed line (only for line-crossing triggers) */
712
+ lineName?: string;
713
+ /** Crossing direction (only for line-crossing triggers) */
714
+ crossingDirection?: 'a-to-b' | 'b-to-a';
715
+ /** Track ID of the object that crossed (only for line-crossing triggers) */
716
+ trackId?: number;
717
+ }
718
+ /**
719
+ * Aggregated object detection within a segment.
720
+ */
721
+ interface EventDetection {
722
+ /** Detection label (e.g. "person", "car") */
723
+ label: string;
724
+ /** Best confidence score */
725
+ score: number;
726
+ /** Maximum simultaneous count in a single frame */
727
+ maxCount: number;
728
+ /** Bounding box of the highest-confidence detection (normalized 0–1) */
729
+ box?: BoundingBox;
730
+ /** Best-selected JPEG thumbnail crop. Only present on 'end' events. */
731
+ thumbnail?: Uint8Array;
732
+ /** Object tracker ID (links this detection across frames) */
733
+ trackId?: number;
734
+ /** Whether the object was moving (true) or stationary (false) */
735
+ moving?: boolean;
736
+ }
737
+ /**
738
+ * Unified attribute within a segment (face identity, license plate, classifier result).
739
+ */
740
+ interface EventAttribute {
741
+ /** Attribute type ('face', 'license_plate', or classifier-specific like 'bird') */
742
+ type: string;
743
+ /** Identity name, plate text, or classification label */
744
+ label: string;
745
+ /** Detection confidence (0-1) */
746
+ confidence?: number;
747
+ /** Best-selected JPEG thumbnail crop. Only present on 'end' events. */
748
+ thumbnail?: Uint8Array;
749
+ /** Face embedding vector for unknown face persistence. Only present for face attributes. */
750
+ embedding?: number[];
751
+ /** Embedding model identifier. Only present for face attributes with embedding. */
752
+ embeddingModel?: string;
753
+ /** CLIP embedding vector for semantic search. Only present for clip attributes. */
754
+ clipEmbedding?: number[];
755
+ /** CLIP embedding model identifier. Only present for clip attributes with embedding. */
756
+ clipEmbeddingModel?: string;
757
+ /** Parent object's tracker ID (links this attribute to its parent detection) */
758
+ parentTrackId?: number;
759
+ }
760
+ /**
761
+ * A contiguous object detection phase within an event.
762
+ */
763
+ interface EventSegment {
764
+ /** Segment start time (Unix ms) */
765
+ firstSeen: number;
766
+ /** Segment end time (Unix ms) */
767
+ lastSeen: number;
768
+ /** Best-selected JPEG scene thumbnail for this segment. Only present on 'end' events. */
769
+ thumbnail?: Uint8Array;
770
+ /** Object detections in this segment */
771
+ detections: EventDetection[];
772
+ /** Unified attributes (faces, plates, classifications) */
773
+ attributes: EventAttribute[];
774
+ /** Names of detection zones any detection in this segment overlapped (deduplicated) */
775
+ zones?: string[];
776
+ /** AI-generated description for this segment */
777
+ description?: EventDescription;
778
+ }
779
+ /**
780
+ * Aggregated detection event with lifecycle (start → update → end).
781
+ * Groups individual sensor detections into structured events.
782
+ */
783
+ interface DetectionEvent {
784
+ /** Unique event ID */
785
+ id: string;
786
+ /** Camera that produced this event */
787
+ cameraId: string;
788
+ /** Event lifecycle state */
789
+ state: DetectionEventState;
790
+ /** Event start time (Unix ms) */
791
+ startTime: number;
792
+ /** Event end time (Unix ms, only when ended) */
793
+ endTime?: number;
794
+ /** Last activity timestamp (Unix ms) */
795
+ lastUpdate: number;
796
+ /** Detection types present in this event (for filtering) */
797
+ types: string[];
798
+ /** Event triggers (motion/audio) */
799
+ triggers: EventTrigger[];
800
+ /**
801
+ * Detection segments (object detection phases).
802
+ * For segment-* messages: contains only the current segment.
803
+ * For start/end messages: empty.
804
+ */
805
+ segments: EventSegment[];
806
+ /** Index of the segment in segments[0] for segment-* messages. */
807
+ segmentIndex?: number;
808
+ /**
809
+ * Expected event end time (Unix ms) — the latest dwell expiry across all
810
+ * currently-active triggers. Monotonically non-decreasing during the event
811
+ * lifetime. Updated on each `update` / `segment-*` message.
812
+ */
813
+ expectedEndTime?: number;
814
+ /**
815
+ * Full-frame downscaled JPEG captured at event start. Inline only on the
816
+ * first message that delivers it (`start` or the first `update`); the NVR
817
+ * plugin persists it and clients fetch it on demand via getEventThumbnails.
818
+ */
819
+ thumbnail?: Buffer;
820
+ }
821
+
822
+ /**
823
+ * Discovered camera from a discovery provider.
824
+ *
825
+ * Represents a camera found during network scanning or cloud lookup that
826
+ * can be adopted into the system. Push these via
827
+ * `deviceManager.pushDiscoveredCameras` so the user can pick them in the
828
+ * UI without waiting for the next discovery poll.
829
+ */
830
+ interface DiscoveredCamera {
831
+ /** Unique, stable identifier for this discovered camera (used for deduplication). */
832
+ id: string;
833
+ /** Display name shown in the UI adoption list. */
834
+ name: string;
835
+ /** Camera manufacturer label (optional). */
836
+ manufacturer?: string;
837
+ /** Camera model label (optional). */
838
+ model?: string;
839
+ }
840
+
841
+ /**
842
+ * Connection status for discovered cameras.
843
+ */
844
+ type ConnectionStatus = 'idle' | 'connecting' | 'connected' | 'error';
845
+ /**
846
+ * Discovered camera with provider and connection state.
847
+ *
848
+ * Extended version of `DiscoveredCamera` used by the UI to render the
849
+ * adoption list — adds the provider plugin name and a live connection
850
+ * status so users see whether the camera is currently reachable.
851
+ */
852
+ interface DiscoveredCameraWithState extends DiscoveredCamera {
853
+ /** Name of the provider plugin that discovered this camera. */
854
+ provider: string;
855
+ /** Current connection status reported by the provider. */
856
+ connectionStatus: ConnectionStatus;
857
+ /** Last error message when `connectionStatus` is `'error'`. */
858
+ errorMessage?: string;
859
+ }
860
+
861
+ /**
862
+ * Deep equality check for arbitrary values.
863
+ *
864
+ * Recursively compares primitives, arrays, and plain objects. Object
865
+ * comparison ignores property declaration order (only key/value pairs
866
+ * matter). Set `ignoreOrder` to `true` to compare arrays as multisets,
867
+ * i.e. ignoring element order.
868
+ *
869
+ * Typically used for property-change detection on sensors: a property
870
+ * update is only emitted when the new value is not deeply equal to the
871
+ * previous value, which avoids redundant events for unchanged data.
872
+ *
873
+ * @param first - First value to compare.
874
+ *
875
+ * @param second - Second value to compare.
876
+ *
877
+ * @param ignoreOrder - If `true`, arrays are compared ignoring element order.
878
+ *
879
+ * @returns `true` if the values are deeply equal.
880
+ *
881
+ * @example
882
+ * ```ts
883
+ * import { isEqual } from '@camera.ui/sdk/internal';
884
+ *
885
+ * isEqual({ a: 1, b: 2 }, { b: 2, a: 1 }); // true
886
+ * isEqual([1, 2, 3], [3, 2, 1], true); // true (ignoreOrder)
887
+ * ```
888
+ */
889
+ declare function isEqual(first: unknown, second: unknown, ignoreOrder?: boolean): boolean;
890
+
891
+ /**
892
+ * Detection event message published via NATS.
893
+ */
894
+ interface DetectionEventMessage {
895
+ /** Event lifecycle type */
896
+ type: DetectionEventType;
897
+ /** Full event data */
898
+ data: DetectionEvent;
899
+ }
900
+
901
+ /** Sensor trigger types — the subset of trigger types that originate from configurable sensors (excludes motion/audio). */
902
+ declare const SENSOR_TRIGGER_TYPES: readonly ["contact", "doorbell", "switch", "light", "siren", "security_system"];
903
+ type SensorTriggerType = (typeof SENSOR_TRIGGER_TYPES)[number];
904
+
905
+ /**
906
+ * Frame type identifier for frame workers.
907
+ */
908
+ type FrameType = 'stream' | 'motion';
909
+ /**
910
+ * Frame worker decoder implementation.
911
+ */
912
+ type CameraFrameWorkerDecoder = 'wasm' | 'rust';
913
+
914
+ export { SENSOR_TRIGGER_TYPES, isDiscoveryProvider, isEqual };
915
+ export type { CameraConfigPartial, CameraFrameWorkerDecoder, CameraInputSettings, CapabilityUpdateFn, ConnectionStatus, DetectionEventMessage, DiscoveredCameraWithState, FrameType, IceServer, PropertyChangeListener, PropertyChangedEvent, PropertyUpdateFn, SensorJSON, SensorTriggerType, Subscribed };