@camstack/addon-provider-onvif 1.1.25 → 1.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/addon.js +202 -13
  2. package/dist/addon.mjs +202 -13
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
4
  //#endregion
5
- //#region ../types/dist/event-category-CFZs3jI4.mjs
5
+ //#region ../types/dist/event-category-H4AVePnn.mjs
6
6
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
7
7
  EventCategory["SystemBoot"] = "system.boot";
8
8
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -152,6 +152,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
152
152
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
153
153
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
154
154
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
155
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
156
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
157
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
155
158
  EventCategory["DetectionEvent"] = "detection.event";
156
159
  EventCategory["SessionTrackNew"] = "session.track.new";
157
160
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -7233,6 +7236,24 @@ var RecordingRetentionSchema = object({
7233
7236
  maxSizeGb: number().min(0).optional()
7234
7237
  });
7235
7238
  /**
7239
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7240
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7241
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7242
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7243
+ *
7244
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7245
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7246
+ * preset changed over time renders every historical window at the dims it was
7247
+ * written with.
7248
+ */
7249
+ var ScrubThumbnailPresetSchema = _enum([
7250
+ "minimal",
7251
+ "low",
7252
+ "standard",
7253
+ "high",
7254
+ "max"
7255
+ ]);
7256
+ /**
7236
7257
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7237
7258
  *
7238
7259
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7269,7 +7290,14 @@ var RecordingConfigSchema = object({
7269
7290
  * derived into bands once via `migrateConfigToBands`.
7270
7291
  */
7271
7292
  bands: array(RecordingBandSchema).optional(),
7272
- retention: RecordingRetentionSchema.optional()
7293
+ retention: RecordingRetentionSchema.optional(),
7294
+ /**
7295
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7296
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7297
+ * windows only — existing sheets are immutable, and each window's index
7298
+ * carries its own tile dims so mixed-preset history renders correctly.
7299
+ */
7300
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7273
7301
  });
7274
7302
  /**
7275
7303
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -9998,7 +10026,7 @@ object({
9998
10026
  deviceId: number(),
9999
10027
  timestamp: number()
10000
10028
  });
10001
- DeviceType.Button;
10029
+ DeviceType.Button, DeviceType.Camera;
10002
10030
  /**
10003
10031
  * Enum-state sensor — a string value picked from a finite option set.
10004
10032
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14662,6 +14690,14 @@ var ConfigEntrySchema = object({
14662
14690
  value: unknown(),
14663
14691
  description: string().optional()
14664
14692
  });
14693
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14694
+ /** One resolved linked device — the compact projection consumers need. */
14695
+ var LinkedDeviceSchema = object({
14696
+ deviceId: number(),
14697
+ name: string(),
14698
+ location: string().nullable(),
14699
+ features: array(string())
14700
+ });
14665
14701
  var SavedDeviceRowSchema = object({
14666
14702
  /** Numeric id reserved at allocateDeviceId time. */
14667
14703
  id: number(),
@@ -14883,7 +14919,10 @@ method(object({
14883
14919
  }), _void(), {
14884
14920
  kind: "mutation",
14885
14921
  auth: "admin"
14886
- }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14922
+ }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
14923
+ mode: DeviceLinkModeSchema,
14924
+ devices: array(LinkedDeviceSchema)
14925
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14887
14926
  deviceId: number(),
14888
14927
  values: record(string(), unknown())
14889
14928
  }), object({ success: literal(true) }), {
@@ -16152,6 +16191,61 @@ var EventKindSchema = _enum([
16152
16191
  "object",
16153
16192
  "audio"
16154
16193
  ]);
16194
+ /**
16195
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
16196
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
16197
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
16198
+ */
16199
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
16200
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
16201
+ var EventKindIconSchema = _enum([
16202
+ "motion",
16203
+ "audio",
16204
+ "person",
16205
+ "vehicle",
16206
+ "animal",
16207
+ "door",
16208
+ "pir",
16209
+ "smoke",
16210
+ "water",
16211
+ "button",
16212
+ "generic"
16213
+ ]);
16214
+ var EventKindCategorySchema = _enum([
16215
+ "motion",
16216
+ "audio",
16217
+ "detection",
16218
+ "sensor",
16219
+ "custom"
16220
+ ]);
16221
+ var EventKindDescriptorSchema = object({
16222
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16223
+ kind: string(),
16224
+ label: string(),
16225
+ /** Hex color for timeline/legend rendering. */
16226
+ color: string(),
16227
+ icon: EventKindIconSchema,
16228
+ category: EventKindCategorySchema,
16229
+ /** Which cap + device contributes this kind. For built-ins the camera
16230
+ * itself; for sensor kinds the LINKED source device. */
16231
+ source: object({
16232
+ capName: string(),
16233
+ deviceId: number()
16234
+ })
16235
+ });
16236
+ var SensorEventSchema = object({
16237
+ id: string(),
16238
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16239
+ * yields N rows, one per camera). */
16240
+ deviceId: number(),
16241
+ /** The linked sensor device whose state changed. */
16242
+ sourceDeviceId: number(),
16243
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16244
+ kind: string(),
16245
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16246
+ value: record(string(), unknown()).nullable(),
16247
+ timestamp: number()
16248
+ });
16155
16249
  var TrackPositionSchema = object({
16156
16250
  x: number(),
16157
16251
  y: number(),
@@ -16165,6 +16259,30 @@ var TrackSnapshotSchema = object({
16165
16259
  mediaKey: string()
16166
16260
  });
16167
16261
  /**
16262
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16263
+ * divided by the track's detection-frame dims), computed at persist time.
16264
+ * Absent when the frame dims were unknown when the track was persisted
16265
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16266
+ */
16267
+ var TrackEnvelopeSchema = object({
16268
+ minX: number(),
16269
+ minY: number(),
16270
+ maxX: number(),
16271
+ maxY: number()
16272
+ });
16273
+ /**
16274
+ * Row projection for track list queries. `full` (default) returns the
16275
+ * complete Track including the frame-rate `positions[]` history and the
16276
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16277
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16278
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16279
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16280
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16281
+ * `getTrack`. Mirrors the event-store `projection` convention
16282
+ * (`getObjectEvents` et al.).
16283
+ */
16284
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16285
+ /**
16168
16286
  * One audio-classification label heard on the track's camera while the
16169
16287
  * track was alive, aggregated per label. An "episode" is one persisted
16170
16288
  * audio event (the confident-classification path: score ≥ the device's
@@ -16215,7 +16333,11 @@ var TrackSchema = object({
16215
16333
  /** Audio-classification labels heard on the camera during the track's
16216
16334
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16217
16335
  * Absent on legacy rows / tracks with no confident audio. */
16218
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16336
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16337
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16338
+ * Populated from the persisted envelope columns on historical reads;
16339
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16340
+ envelope: TrackEnvelopeSchema.optional()
16219
16341
  });
16220
16342
  var BaseEventFields = {
16221
16343
  id: string(),
@@ -16325,11 +16447,13 @@ var MediaFileSchema = object({
16325
16447
  sizeBytes: number(),
16326
16448
  timestamp: number()
16327
16449
  });
16450
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16451
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16328
16452
  var DeviceEventQueryInput = object({
16329
16453
  deviceId: number(),
16330
16454
  since: number().optional(),
16331
16455
  until: number().optional(),
16332
- limit: number().int().min(1).max(5e3).default(1e3),
16456
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16333
16457
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16334
16458
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16335
16459
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16337,6 +16461,27 @@ var DeviceEventQueryInput = object({
16337
16461
  projection: _enum(["full", "slim"]).optional()
16338
16462
  });
16339
16463
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16464
+ var RecentTracksQueryInput = object({
16465
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16466
+ deviceIds: array(number()),
16467
+ /** Window lower bound on `lastSeen` (inclusive). */
16468
+ since: number().optional(),
16469
+ /** Window upper bound on `lastSeen` (inclusive). */
16470
+ until: number().optional(),
16471
+ /** Page size. Default 200, max 1000. */
16472
+ limit: number().int().min(1).max(1e3).default(200),
16473
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16474
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16475
+ cursor: string().optional(),
16476
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16477
+ projection: TrackProjectionSchema.optional()
16478
+ });
16479
+ var RecentTracksPageSchema = object({
16480
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16481
+ tracks: array(TrackSchema).readonly(),
16482
+ /** Cursor for the next page, or null when this page is the last. */
16483
+ nextCursor: string().nullable()
16484
+ });
16340
16485
  var KeyEventQueryInput = object({
16341
16486
  deviceId: number(),
16342
16487
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16419,11 +16564,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16419
16564
  deviceId: number(),
16420
16565
  since: number().optional(),
16421
16566
  until: number().optional(),
16422
- limit: number().optional()
16423
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16424
- kind: "mutation",
16425
- auth: "admin"
16426
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16567
+ limit: number().optional(),
16568
+ /** Spatial filter only tracks whose trajectory intersects the zone
16569
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16570
+ * envelope columns, then precisely tested per position. Tracks with
16571
+ * an unknown envelope (no frame dims at persist time) always match. */
16572
+ zone: TrackZoneFilterSchema.optional(),
16573
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16574
+ * compatible — omitting the field keeps today's exact behaviour). */
16575
+ projection: TrackProjectionSchema.optional()
16576
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16577
+ kind: "mutation",
16578
+ auth: "admin"
16579
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16580
+ deviceId: number(),
16581
+ since: number().optional(),
16582
+ until: number().optional(),
16583
+ kinds: array(string()).optional(),
16584
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16585
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16427
16586
  deviceId: number(),
16428
16587
  since: number(),
16429
16588
  until: number(),
@@ -19717,7 +19876,12 @@ var RecordingStorageUsageSchema = object({
19717
19876
  /**
19718
19877
  * Result of locating footage at a wall-clock instant for one device/profile.
19719
19878
  * `segment` carries the covering segment's window; `gap` reports the forward
19720
- * nearest covered edge (`null` past the end of footage / when none exists).
19879
+ * nearest covered edge (`null` past the end of footage / when none exists)
19880
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19881
+ * footage behind the epoch; `null` when none — optional so older providers
19882
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19883
+ * small inter-segment cracks (durMs under-covers the span to the next
19884
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19721
19885
  */
19722
19886
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19723
19887
  kind: literal("segment"),
@@ -19726,7 +19890,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19726
19890
  bytes: number()
19727
19891
  }), object({
19728
19892
  kind: literal("gap"),
19729
- nearestEdgeMs: number().nullable()
19893
+ nearestEdgeMs: number().nullable(),
19894
+ prevEndMs: number().nullable().optional()
19730
19895
  })]);
19731
19896
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19732
19897
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -21295,6 +21460,12 @@ Object.freeze({
21295
21460
  addonId: null,
21296
21461
  access: "view"
21297
21462
  },
21463
+ "deviceManager.getLinkedDevices": {
21464
+ capName: "device-manager",
21465
+ capScope: "system",
21466
+ addonId: null,
21467
+ access: "view"
21468
+ },
21298
21469
  "deviceManager.getRoleDisplayDefaults": {
21299
21470
  capName: "device-manager",
21300
21471
  capScope: "system",
@@ -22849,6 +23020,12 @@ Object.freeze({
22849
23020
  addonId: null,
22850
23021
  access: "view"
22851
23022
  },
23023
+ "pipelineAnalytics.getSensorEvents": {
23024
+ capName: "pipeline-analytics",
23025
+ capScope: "device",
23026
+ addonId: null,
23027
+ access: "view"
23028
+ },
22852
23029
  "pipelineAnalytics.getTrack": {
22853
23030
  capName: "pipeline-analytics",
22854
23031
  capScope: "device",
@@ -22861,6 +23038,18 @@ Object.freeze({
22861
23038
  addonId: null,
22862
23039
  access: "view"
22863
23040
  },
23041
+ "pipelineAnalytics.listEventKinds": {
23042
+ capName: "pipeline-analytics",
23043
+ capScope: "device",
23044
+ addonId: null,
23045
+ access: "view"
23046
+ },
23047
+ "pipelineAnalytics.listRecentTracks": {
23048
+ capName: "pipeline-analytics",
23049
+ capScope: "device",
23050
+ addonId: null,
23051
+ access: "view"
23052
+ },
22864
23053
  "pipelineAnalytics.listTracks": {
22865
23054
  capName: "pipeline-analytics",
22866
23055
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
3
3
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
4
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  //#endregion
6
- //#region ../types/dist/event-category-CFZs3jI4.mjs
6
+ //#region ../types/dist/event-category-H4AVePnn.mjs
7
7
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
8
8
  EventCategory["SystemBoot"] = "system.boot";
9
9
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -153,6 +153,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
153
153
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
154
154
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
155
155
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
156
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
157
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
158
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
156
159
  EventCategory["DetectionEvent"] = "detection.event";
157
160
  EventCategory["SessionTrackNew"] = "session.track.new";
158
161
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -7234,6 +7237,24 @@ var RecordingRetentionSchema = object({
7234
7237
  maxSizeGb: number().min(0).optional()
7235
7238
  });
7236
7239
  /**
7240
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7241
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7242
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7243
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7244
+ *
7245
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7246
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7247
+ * preset changed over time renders every historical window at the dims it was
7248
+ * written with.
7249
+ */
7250
+ var ScrubThumbnailPresetSchema = _enum([
7251
+ "minimal",
7252
+ "low",
7253
+ "standard",
7254
+ "high",
7255
+ "max"
7256
+ ]);
7257
+ /**
7237
7258
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7238
7259
  *
7239
7260
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7270,7 +7291,14 @@ var RecordingConfigSchema = object({
7270
7291
  * derived into bands once via `migrateConfigToBands`.
7271
7292
  */
7272
7293
  bands: array(RecordingBandSchema).optional(),
7273
- retention: RecordingRetentionSchema.optional()
7294
+ retention: RecordingRetentionSchema.optional(),
7295
+ /**
7296
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7297
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7298
+ * windows only — existing sheets are immutable, and each window's index
7299
+ * carries its own tile dims so mixed-preset history renders correctly.
7300
+ */
7301
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7274
7302
  });
7275
7303
  /**
7276
7304
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -9999,7 +10027,7 @@ object({
9999
10027
  deviceId: number(),
10000
10028
  timestamp: number()
10001
10029
  });
10002
- DeviceType.Button;
10030
+ DeviceType.Button, DeviceType.Camera;
10003
10031
  /**
10004
10032
  * Enum-state sensor — a string value picked from a finite option set.
10005
10033
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14663,6 +14691,14 @@ var ConfigEntrySchema = object({
14663
14691
  value: unknown(),
14664
14692
  description: string().optional()
14665
14693
  });
14694
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14695
+ /** One resolved linked device — the compact projection consumers need. */
14696
+ var LinkedDeviceSchema = object({
14697
+ deviceId: number(),
14698
+ name: string(),
14699
+ location: string().nullable(),
14700
+ features: array(string())
14701
+ });
14666
14702
  var SavedDeviceRowSchema = object({
14667
14703
  /** Numeric id reserved at allocateDeviceId time. */
14668
14704
  id: number(),
@@ -14884,7 +14920,10 @@ method(object({
14884
14920
  }), _void(), {
14885
14921
  kind: "mutation",
14886
14922
  auth: "admin"
14887
- }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14923
+ }), method(object({ addonId: string() }), array(SavedDeviceRowSchema)), method(object({ addonId: string().optional() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), DeviceInfoSchema.nullable()), method(object({ parentDeviceId: number() }), array(DeviceInfoSchema)), method(object({ deviceId: number() }), object({
14924
+ mode: DeviceLinkModeSchema,
14925
+ devices: array(LinkedDeviceSchema)
14926
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14888
14927
  deviceId: number(),
14889
14928
  values: record(string(), unknown())
14890
14929
  }), object({ success: literal(true) }), {
@@ -16153,6 +16192,61 @@ var EventKindSchema = _enum([
16153
16192
  "object",
16154
16193
  "audio"
16155
16194
  ]);
16195
+ /**
16196
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
16197
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
16198
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
16199
+ */
16200
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
16201
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
16202
+ var EventKindIconSchema = _enum([
16203
+ "motion",
16204
+ "audio",
16205
+ "person",
16206
+ "vehicle",
16207
+ "animal",
16208
+ "door",
16209
+ "pir",
16210
+ "smoke",
16211
+ "water",
16212
+ "button",
16213
+ "generic"
16214
+ ]);
16215
+ var EventKindCategorySchema = _enum([
16216
+ "motion",
16217
+ "audio",
16218
+ "detection",
16219
+ "sensor",
16220
+ "custom"
16221
+ ]);
16222
+ var EventKindDescriptorSchema = object({
16223
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16224
+ kind: string(),
16225
+ label: string(),
16226
+ /** Hex color for timeline/legend rendering. */
16227
+ color: string(),
16228
+ icon: EventKindIconSchema,
16229
+ category: EventKindCategorySchema,
16230
+ /** Which cap + device contributes this kind. For built-ins the camera
16231
+ * itself; for sensor kinds the LINKED source device. */
16232
+ source: object({
16233
+ capName: string(),
16234
+ deviceId: number()
16235
+ })
16236
+ });
16237
+ var SensorEventSchema = object({
16238
+ id: string(),
16239
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16240
+ * yields N rows, one per camera). */
16241
+ deviceId: number(),
16242
+ /** The linked sensor device whose state changed. */
16243
+ sourceDeviceId: number(),
16244
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16245
+ kind: string(),
16246
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16247
+ value: record(string(), unknown()).nullable(),
16248
+ timestamp: number()
16249
+ });
16156
16250
  var TrackPositionSchema = object({
16157
16251
  x: number(),
16158
16252
  y: number(),
@@ -16166,6 +16260,30 @@ var TrackSnapshotSchema = object({
16166
16260
  mediaKey: string()
16167
16261
  });
16168
16262
  /**
16263
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16264
+ * divided by the track's detection-frame dims), computed at persist time.
16265
+ * Absent when the frame dims were unknown when the track was persisted
16266
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16267
+ */
16268
+ var TrackEnvelopeSchema = object({
16269
+ minX: number(),
16270
+ minY: number(),
16271
+ maxX: number(),
16272
+ maxY: number()
16273
+ });
16274
+ /**
16275
+ * Row projection for track list queries. `full` (default) returns the
16276
+ * complete Track including the frame-rate `positions[]` history and the
16277
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16278
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16279
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16280
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16281
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16282
+ * `getTrack`. Mirrors the event-store `projection` convention
16283
+ * (`getObjectEvents` et al.).
16284
+ */
16285
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16286
+ /**
16169
16287
  * One audio-classification label heard on the track's camera while the
16170
16288
  * track was alive, aggregated per label. An "episode" is one persisted
16171
16289
  * audio event (the confident-classification path: score ≥ the device's
@@ -16216,7 +16334,11 @@ var TrackSchema = object({
16216
16334
  /** Audio-classification labels heard on the camera during the track's
16217
16335
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16218
16336
  * Absent on legacy rows / tracks with no confident audio. */
16219
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16337
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16338
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16339
+ * Populated from the persisted envelope columns on historical reads;
16340
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16341
+ envelope: TrackEnvelopeSchema.optional()
16220
16342
  });
16221
16343
  var BaseEventFields = {
16222
16344
  id: string(),
@@ -16326,11 +16448,13 @@ var MediaFileSchema = object({
16326
16448
  sizeBytes: number(),
16327
16449
  timestamp: number()
16328
16450
  });
16451
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16452
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16329
16453
  var DeviceEventQueryInput = object({
16330
16454
  deviceId: number(),
16331
16455
  since: number().optional(),
16332
16456
  until: number().optional(),
16333
- limit: number().int().min(1).max(5e3).default(1e3),
16457
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16334
16458
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16335
16459
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16336
16460
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16338,6 +16462,27 @@ var DeviceEventQueryInput = object({
16338
16462
  projection: _enum(["full", "slim"]).optional()
16339
16463
  });
16340
16464
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16465
+ var RecentTracksQueryInput = object({
16466
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16467
+ deviceIds: array(number()),
16468
+ /** Window lower bound on `lastSeen` (inclusive). */
16469
+ since: number().optional(),
16470
+ /** Window upper bound on `lastSeen` (inclusive). */
16471
+ until: number().optional(),
16472
+ /** Page size. Default 200, max 1000. */
16473
+ limit: number().int().min(1).max(1e3).default(200),
16474
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16475
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16476
+ cursor: string().optional(),
16477
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16478
+ projection: TrackProjectionSchema.optional()
16479
+ });
16480
+ var RecentTracksPageSchema = object({
16481
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16482
+ tracks: array(TrackSchema).readonly(),
16483
+ /** Cursor for the next page, or null when this page is the last. */
16484
+ nextCursor: string().nullable()
16485
+ });
16341
16486
  var KeyEventQueryInput = object({
16342
16487
  deviceId: number(),
16343
16488
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16420,11 +16565,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16420
16565
  deviceId: number(),
16421
16566
  since: number().optional(),
16422
16567
  until: number().optional(),
16423
- limit: number().optional()
16424
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16425
- kind: "mutation",
16426
- auth: "admin"
16427
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16568
+ limit: number().optional(),
16569
+ /** Spatial filter only tracks whose trajectory intersects the zone
16570
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16571
+ * envelope columns, then precisely tested per position. Tracks with
16572
+ * an unknown envelope (no frame dims at persist time) always match. */
16573
+ zone: TrackZoneFilterSchema.optional(),
16574
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16575
+ * compatible — omitting the field keeps today's exact behaviour). */
16576
+ projection: TrackProjectionSchema.optional()
16577
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16578
+ kind: "mutation",
16579
+ auth: "admin"
16580
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16581
+ deviceId: number(),
16582
+ since: number().optional(),
16583
+ until: number().optional(),
16584
+ kinds: array(string()).optional(),
16585
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16586
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16428
16587
  deviceId: number(),
16429
16588
  since: number(),
16430
16589
  until: number(),
@@ -19718,7 +19877,12 @@ var RecordingStorageUsageSchema = object({
19718
19877
  /**
19719
19878
  * Result of locating footage at a wall-clock instant for one device/profile.
19720
19879
  * `segment` carries the covering segment's window; `gap` reports the forward
19721
- * nearest covered edge (`null` past the end of footage / when none exists).
19880
+ * nearest covered edge (`null` past the end of footage / when none exists)
19881
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19882
+ * footage behind the epoch; `null` when none — optional so older providers
19883
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19884
+ * small inter-segment cracks (durMs under-covers the span to the next
19885
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19722
19886
  */
19723
19887
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19724
19888
  kind: literal("segment"),
@@ -19727,7 +19891,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19727
19891
  bytes: number()
19728
19892
  }), object({
19729
19893
  kind: literal("gap"),
19730
- nearestEdgeMs: number().nullable()
19894
+ nearestEdgeMs: number().nullable(),
19895
+ prevEndMs: number().nullable().optional()
19731
19896
  })]);
19732
19897
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19733
19898
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -21296,6 +21461,12 @@ Object.freeze({
21296
21461
  addonId: null,
21297
21462
  access: "view"
21298
21463
  },
21464
+ "deviceManager.getLinkedDevices": {
21465
+ capName: "device-manager",
21466
+ capScope: "system",
21467
+ addonId: null,
21468
+ access: "view"
21469
+ },
21299
21470
  "deviceManager.getRoleDisplayDefaults": {
21300
21471
  capName: "device-manager",
21301
21472
  capScope: "system",
@@ -22850,6 +23021,12 @@ Object.freeze({
22850
23021
  addonId: null,
22851
23022
  access: "view"
22852
23023
  },
23024
+ "pipelineAnalytics.getSensorEvents": {
23025
+ capName: "pipeline-analytics",
23026
+ capScope: "device",
23027
+ addonId: null,
23028
+ access: "view"
23029
+ },
22853
23030
  "pipelineAnalytics.getTrack": {
22854
23031
  capName: "pipeline-analytics",
22855
23032
  capScope: "device",
@@ -22862,6 +23039,18 @@ Object.freeze({
22862
23039
  addonId: null,
22863
23040
  access: "view"
22864
23041
  },
23042
+ "pipelineAnalytics.listEventKinds": {
23043
+ capName: "pipeline-analytics",
23044
+ capScope: "device",
23045
+ addonId: null,
23046
+ access: "view"
23047
+ },
23048
+ "pipelineAnalytics.listRecentTracks": {
23049
+ capName: "pipeline-analytics",
23050
+ capScope: "device",
23051
+ addonId: null,
23052
+ access: "view"
23053
+ },
22865
23054
  "pipelineAnalytics.listTracks": {
22866
23055
  capName: "pipeline-analytics",
22867
23056
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-onvif",
3
- "version": "1.1.25",
3
+ "version": "1.1.27",
4
4
  "description": "ONVIF camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",