@camstack/addon-notifiers 1.1.25 → 1.1.26

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 +176 -12
  2. package/dist/addon.mjs +176 -12
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  let node_zlib = require("node:zlib");
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";
@@ -10127,7 +10130,7 @@ object({
10127
10130
  deviceId: number(),
10128
10131
  timestamp: number()
10129
10132
  });
10130
- DeviceType.Button;
10133
+ DeviceType.Button, DeviceType.Camera;
10131
10134
  /**
10132
10135
  * Enum-state sensor — a string value picked from a finite option set.
10133
10136
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14516,6 +14519,14 @@ var ConfigEntrySchema = object({
14516
14519
  value: unknown(),
14517
14520
  description: string().optional()
14518
14521
  });
14522
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14523
+ /** One resolved linked device — the compact projection consumers need. */
14524
+ var LinkedDeviceSchema = object({
14525
+ deviceId: number(),
14526
+ name: string(),
14527
+ location: string().nullable(),
14528
+ features: array(string())
14529
+ });
14519
14530
  var SavedDeviceRowSchema = object({
14520
14531
  /** Numeric id reserved at allocateDeviceId time. */
14521
14532
  id: number(),
@@ -14737,7 +14748,10 @@ method(object({
14737
14748
  }), _void(), {
14738
14749
  kind: "mutation",
14739
14750
  auth: "admin"
14740
- }), 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({
14751
+ }), 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({
14752
+ mode: DeviceLinkModeSchema,
14753
+ devices: array(LinkedDeviceSchema)
14754
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14741
14755
  deviceId: number(),
14742
14756
  values: record(string(), unknown())
14743
14757
  }), object({ success: literal(true) }), {
@@ -16020,6 +16034,61 @@ var EventKindSchema = _enum([
16020
16034
  "object",
16021
16035
  "audio"
16022
16036
  ]);
16037
+ /**
16038
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
16039
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
16040
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
16041
+ */
16042
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
16043
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
16044
+ var EventKindIconSchema = _enum([
16045
+ "motion",
16046
+ "audio",
16047
+ "person",
16048
+ "vehicle",
16049
+ "animal",
16050
+ "door",
16051
+ "pir",
16052
+ "smoke",
16053
+ "water",
16054
+ "button",
16055
+ "generic"
16056
+ ]);
16057
+ var EventKindCategorySchema = _enum([
16058
+ "motion",
16059
+ "audio",
16060
+ "detection",
16061
+ "sensor",
16062
+ "custom"
16063
+ ]);
16064
+ var EventKindDescriptorSchema = object({
16065
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16066
+ kind: string(),
16067
+ label: string(),
16068
+ /** Hex color for timeline/legend rendering. */
16069
+ color: string(),
16070
+ icon: EventKindIconSchema,
16071
+ category: EventKindCategorySchema,
16072
+ /** Which cap + device contributes this kind. For built-ins the camera
16073
+ * itself; for sensor kinds the LINKED source device. */
16074
+ source: object({
16075
+ capName: string(),
16076
+ deviceId: number()
16077
+ })
16078
+ });
16079
+ var SensorEventSchema = object({
16080
+ id: string(),
16081
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16082
+ * yields N rows, one per camera). */
16083
+ deviceId: number(),
16084
+ /** The linked sensor device whose state changed. */
16085
+ sourceDeviceId: number(),
16086
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16087
+ kind: string(),
16088
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16089
+ value: record(string(), unknown()).nullable(),
16090
+ timestamp: number()
16091
+ });
16023
16092
  var TrackPositionSchema = object({
16024
16093
  x: number(),
16025
16094
  y: number(),
@@ -16033,6 +16102,30 @@ var TrackSnapshotSchema = object({
16033
16102
  mediaKey: string()
16034
16103
  });
16035
16104
  /**
16105
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16106
+ * divided by the track's detection-frame dims), computed at persist time.
16107
+ * Absent when the frame dims were unknown when the track was persisted
16108
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16109
+ */
16110
+ var TrackEnvelopeSchema = object({
16111
+ minX: number(),
16112
+ minY: number(),
16113
+ maxX: number(),
16114
+ maxY: number()
16115
+ });
16116
+ /**
16117
+ * Row projection for track list queries. `full` (default) returns the
16118
+ * complete Track including the frame-rate `positions[]` history and the
16119
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16120
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16121
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16122
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16123
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16124
+ * `getTrack`. Mirrors the event-store `projection` convention
16125
+ * (`getObjectEvents` et al.).
16126
+ */
16127
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16128
+ /**
16036
16129
  * One audio-classification label heard on the track's camera while the
16037
16130
  * track was alive, aggregated per label. An "episode" is one persisted
16038
16131
  * audio event (the confident-classification path: score ≥ the device's
@@ -16083,7 +16176,11 @@ var TrackSchema = object({
16083
16176
  /** Audio-classification labels heard on the camera during the track's
16084
16177
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16085
16178
  * Absent on legacy rows / tracks with no confident audio. */
16086
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16179
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16180
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16181
+ * Populated from the persisted envelope columns on historical reads;
16182
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16183
+ envelope: TrackEnvelopeSchema.optional()
16087
16184
  });
16088
16185
  var BaseEventFields = {
16089
16186
  id: string(),
@@ -16193,11 +16290,13 @@ var MediaFileSchema = object({
16193
16290
  sizeBytes: number(),
16194
16291
  timestamp: number()
16195
16292
  });
16293
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16294
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16196
16295
  var DeviceEventQueryInput = object({
16197
16296
  deviceId: number(),
16198
16297
  since: number().optional(),
16199
16298
  until: number().optional(),
16200
- limit: number().int().min(1).max(5e3).default(1e3),
16299
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16201
16300
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16202
16301
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16203
16302
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16205,6 +16304,27 @@ var DeviceEventQueryInput = object({
16205
16304
  projection: _enum(["full", "slim"]).optional()
16206
16305
  });
16207
16306
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16307
+ var RecentTracksQueryInput = object({
16308
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16309
+ deviceIds: array(number()),
16310
+ /** Window lower bound on `lastSeen` (inclusive). */
16311
+ since: number().optional(),
16312
+ /** Window upper bound on `lastSeen` (inclusive). */
16313
+ until: number().optional(),
16314
+ /** Page size. Default 200, max 1000. */
16315
+ limit: number().int().min(1).max(1e3).default(200),
16316
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16317
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16318
+ cursor: string().optional(),
16319
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16320
+ projection: TrackProjectionSchema.optional()
16321
+ });
16322
+ var RecentTracksPageSchema = object({
16323
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16324
+ tracks: array(TrackSchema).readonly(),
16325
+ /** Cursor for the next page, or null when this page is the last. */
16326
+ nextCursor: string().nullable()
16327
+ });
16208
16328
  var KeyEventQueryInput = object({
16209
16329
  deviceId: number(),
16210
16330
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16287,11 +16407,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16287
16407
  deviceId: number(),
16288
16408
  since: number().optional(),
16289
16409
  until: number().optional(),
16290
- limit: number().optional()
16291
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16292
- kind: "mutation",
16293
- auth: "admin"
16294
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16410
+ limit: number().optional(),
16411
+ /** Spatial filter only tracks whose trajectory intersects the zone
16412
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16413
+ * envelope columns, then precisely tested per position. Tracks with
16414
+ * an unknown envelope (no frame dims at persist time) always match. */
16415
+ zone: TrackZoneFilterSchema.optional(),
16416
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16417
+ * compatible — omitting the field keeps today's exact behaviour). */
16418
+ projection: TrackProjectionSchema.optional()
16419
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16420
+ kind: "mutation",
16421
+ auth: "admin"
16422
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16423
+ deviceId: number(),
16424
+ since: number().optional(),
16425
+ until: number().optional(),
16426
+ kinds: array(string()).optional(),
16427
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16428
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16295
16429
  deviceId: number(),
16296
16430
  since: number(),
16297
16431
  until: number(),
@@ -19492,7 +19626,12 @@ var RecordingStorageUsageSchema = object({
19492
19626
  /**
19493
19627
  * Result of locating footage at a wall-clock instant for one device/profile.
19494
19628
  * `segment` carries the covering segment's window; `gap` reports the forward
19495
- * nearest covered edge (`null` past the end of footage / when none exists).
19629
+ * nearest covered edge (`null` past the end of footage / when none exists)
19630
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19631
+ * footage behind the epoch; `null` when none — optional so older providers
19632
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19633
+ * small inter-segment cracks (durMs under-covers the span to the next
19634
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19496
19635
  */
19497
19636
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19498
19637
  kind: literal("segment"),
@@ -19501,7 +19640,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19501
19640
  bytes: number()
19502
19641
  }), object({
19503
19642
  kind: literal("gap"),
19504
- nearestEdgeMs: number().nullable()
19643
+ nearestEdgeMs: number().nullable(),
19644
+ prevEndMs: number().nullable().optional()
19505
19645
  })]);
19506
19646
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19507
19647
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -21070,6 +21210,12 @@ Object.freeze({
21070
21210
  addonId: null,
21071
21211
  access: "view"
21072
21212
  },
21213
+ "deviceManager.getLinkedDevices": {
21214
+ capName: "device-manager",
21215
+ capScope: "system",
21216
+ addonId: null,
21217
+ access: "view"
21218
+ },
21073
21219
  "deviceManager.getRoleDisplayDefaults": {
21074
21220
  capName: "device-manager",
21075
21221
  capScope: "system",
@@ -22624,6 +22770,12 @@ Object.freeze({
22624
22770
  addonId: null,
22625
22771
  access: "view"
22626
22772
  },
22773
+ "pipelineAnalytics.getSensorEvents": {
22774
+ capName: "pipeline-analytics",
22775
+ capScope: "device",
22776
+ addonId: null,
22777
+ access: "view"
22778
+ },
22627
22779
  "pipelineAnalytics.getTrack": {
22628
22780
  capName: "pipeline-analytics",
22629
22781
  capScope: "device",
@@ -22636,6 +22788,18 @@ Object.freeze({
22636
22788
  addonId: null,
22637
22789
  access: "view"
22638
22790
  },
22791
+ "pipelineAnalytics.listEventKinds": {
22792
+ capName: "pipeline-analytics",
22793
+ capScope: "device",
22794
+ addonId: null,
22795
+ access: "view"
22796
+ },
22797
+ "pipelineAnalytics.listRecentTracks": {
22798
+ capName: "pipeline-analytics",
22799
+ capScope: "device",
22800
+ addonId: null,
22801
+ access: "view"
22802
+ },
22639
22803
  "pipelineAnalytics.listTracks": {
22640
22804
  capName: "pipeline-analytics",
22641
22805
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
2
- //#region ../types/dist/event-category-CFZs3jI4.mjs
2
+ //#region ../types/dist/event-category-H4AVePnn.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -149,6 +149,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
149
149
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
150
150
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
151
151
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
152
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
153
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
154
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
152
155
  EventCategory["DetectionEvent"] = "detection.event";
153
156
  EventCategory["SessionTrackNew"] = "session.track.new";
154
157
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -10123,7 +10126,7 @@ object({
10123
10126
  deviceId: number(),
10124
10127
  timestamp: number()
10125
10128
  });
10126
- DeviceType.Button;
10129
+ DeviceType.Button, DeviceType.Camera;
10127
10130
  /**
10128
10131
  * Enum-state sensor — a string value picked from a finite option set.
10129
10132
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14512,6 +14515,14 @@ var ConfigEntrySchema = object({
14512
14515
  value: unknown(),
14513
14516
  description: string().optional()
14514
14517
  });
14518
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14519
+ /** One resolved linked device — the compact projection consumers need. */
14520
+ var LinkedDeviceSchema = object({
14521
+ deviceId: number(),
14522
+ name: string(),
14523
+ location: string().nullable(),
14524
+ features: array(string())
14525
+ });
14515
14526
  var SavedDeviceRowSchema = object({
14516
14527
  /** Numeric id reserved at allocateDeviceId time. */
14517
14528
  id: number(),
@@ -14733,7 +14744,10 @@ method(object({
14733
14744
  }), _void(), {
14734
14745
  kind: "mutation",
14735
14746
  auth: "admin"
14736
- }), 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({
14747
+ }), 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({
14748
+ mode: DeviceLinkModeSchema,
14749
+ devices: array(LinkedDeviceSchema)
14750
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14737
14751
  deviceId: number(),
14738
14752
  values: record(string(), unknown())
14739
14753
  }), object({ success: literal(true) }), {
@@ -16016,6 +16030,61 @@ var EventKindSchema = _enum([
16016
16030
  "object",
16017
16031
  "audio"
16018
16032
  ]);
16033
+ /**
16034
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
16035
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
16036
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
16037
+ */
16038
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
16039
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
16040
+ var EventKindIconSchema = _enum([
16041
+ "motion",
16042
+ "audio",
16043
+ "person",
16044
+ "vehicle",
16045
+ "animal",
16046
+ "door",
16047
+ "pir",
16048
+ "smoke",
16049
+ "water",
16050
+ "button",
16051
+ "generic"
16052
+ ]);
16053
+ var EventKindCategorySchema = _enum([
16054
+ "motion",
16055
+ "audio",
16056
+ "detection",
16057
+ "sensor",
16058
+ "custom"
16059
+ ]);
16060
+ var EventKindDescriptorSchema = object({
16061
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16062
+ kind: string(),
16063
+ label: string(),
16064
+ /** Hex color for timeline/legend rendering. */
16065
+ color: string(),
16066
+ icon: EventKindIconSchema,
16067
+ category: EventKindCategorySchema,
16068
+ /** Which cap + device contributes this kind. For built-ins the camera
16069
+ * itself; for sensor kinds the LINKED source device. */
16070
+ source: object({
16071
+ capName: string(),
16072
+ deviceId: number()
16073
+ })
16074
+ });
16075
+ var SensorEventSchema = object({
16076
+ id: string(),
16077
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16078
+ * yields N rows, one per camera). */
16079
+ deviceId: number(),
16080
+ /** The linked sensor device whose state changed. */
16081
+ sourceDeviceId: number(),
16082
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16083
+ kind: string(),
16084
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16085
+ value: record(string(), unknown()).nullable(),
16086
+ timestamp: number()
16087
+ });
16019
16088
  var TrackPositionSchema = object({
16020
16089
  x: number(),
16021
16090
  y: number(),
@@ -16029,6 +16098,30 @@ var TrackSnapshotSchema = object({
16029
16098
  mediaKey: string()
16030
16099
  });
16031
16100
  /**
16101
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16102
+ * divided by the track's detection-frame dims), computed at persist time.
16103
+ * Absent when the frame dims were unknown when the track was persisted
16104
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16105
+ */
16106
+ var TrackEnvelopeSchema = object({
16107
+ minX: number(),
16108
+ minY: number(),
16109
+ maxX: number(),
16110
+ maxY: number()
16111
+ });
16112
+ /**
16113
+ * Row projection for track list queries. `full` (default) returns the
16114
+ * complete Track including the frame-rate `positions[]` history and the
16115
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16116
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16117
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16118
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16119
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16120
+ * `getTrack`. Mirrors the event-store `projection` convention
16121
+ * (`getObjectEvents` et al.).
16122
+ */
16123
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16124
+ /**
16032
16125
  * One audio-classification label heard on the track's camera while the
16033
16126
  * track was alive, aggregated per label. An "episode" is one persisted
16034
16127
  * audio event (the confident-classification path: score ≥ the device's
@@ -16079,7 +16172,11 @@ var TrackSchema = object({
16079
16172
  /** Audio-classification labels heard on the camera during the track's
16080
16173
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16081
16174
  * Absent on legacy rows / tracks with no confident audio. */
16082
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16175
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16176
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16177
+ * Populated from the persisted envelope columns on historical reads;
16178
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16179
+ envelope: TrackEnvelopeSchema.optional()
16083
16180
  });
16084
16181
  var BaseEventFields = {
16085
16182
  id: string(),
@@ -16189,11 +16286,13 @@ var MediaFileSchema = object({
16189
16286
  sizeBytes: number(),
16190
16287
  timestamp: number()
16191
16288
  });
16289
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16290
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16192
16291
  var DeviceEventQueryInput = object({
16193
16292
  deviceId: number(),
16194
16293
  since: number().optional(),
16195
16294
  until: number().optional(),
16196
- limit: number().int().min(1).max(5e3).default(1e3),
16295
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16197
16296
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16198
16297
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16199
16298
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16201,6 +16300,27 @@ var DeviceEventQueryInput = object({
16201
16300
  projection: _enum(["full", "slim"]).optional()
16202
16301
  });
16203
16302
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16303
+ var RecentTracksQueryInput = object({
16304
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16305
+ deviceIds: array(number()),
16306
+ /** Window lower bound on `lastSeen` (inclusive). */
16307
+ since: number().optional(),
16308
+ /** Window upper bound on `lastSeen` (inclusive). */
16309
+ until: number().optional(),
16310
+ /** Page size. Default 200, max 1000. */
16311
+ limit: number().int().min(1).max(1e3).default(200),
16312
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16313
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16314
+ cursor: string().optional(),
16315
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16316
+ projection: TrackProjectionSchema.optional()
16317
+ });
16318
+ var RecentTracksPageSchema = object({
16319
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16320
+ tracks: array(TrackSchema).readonly(),
16321
+ /** Cursor for the next page, or null when this page is the last. */
16322
+ nextCursor: string().nullable()
16323
+ });
16204
16324
  var KeyEventQueryInput = object({
16205
16325
  deviceId: number(),
16206
16326
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16283,11 +16403,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16283
16403
  deviceId: number(),
16284
16404
  since: number().optional(),
16285
16405
  until: number().optional(),
16286
- limit: number().optional()
16287
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16288
- kind: "mutation",
16289
- auth: "admin"
16290
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16406
+ limit: number().optional(),
16407
+ /** Spatial filter only tracks whose trajectory intersects the zone
16408
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16409
+ * envelope columns, then precisely tested per position. Tracks with
16410
+ * an unknown envelope (no frame dims at persist time) always match. */
16411
+ zone: TrackZoneFilterSchema.optional(),
16412
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16413
+ * compatible — omitting the field keeps today's exact behaviour). */
16414
+ projection: TrackProjectionSchema.optional()
16415
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16416
+ kind: "mutation",
16417
+ auth: "admin"
16418
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16419
+ deviceId: number(),
16420
+ since: number().optional(),
16421
+ until: number().optional(),
16422
+ kinds: array(string()).optional(),
16423
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16424
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16291
16425
  deviceId: number(),
16292
16426
  since: number(),
16293
16427
  until: number(),
@@ -19488,7 +19622,12 @@ var RecordingStorageUsageSchema = object({
19488
19622
  /**
19489
19623
  * Result of locating footage at a wall-clock instant for one device/profile.
19490
19624
  * `segment` carries the covering segment's window; `gap` reports the forward
19491
- * nearest covered edge (`null` past the end of footage / when none exists).
19625
+ * nearest covered edge (`null` past the end of footage / when none exists)
19626
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19627
+ * footage behind the epoch; `null` when none — optional so older providers
19628
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19629
+ * small inter-segment cracks (durMs under-covers the span to the next
19630
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19492
19631
  */
19493
19632
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19494
19633
  kind: literal("segment"),
@@ -19497,7 +19636,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19497
19636
  bytes: number()
19498
19637
  }), object({
19499
19638
  kind: literal("gap"),
19500
- nearestEdgeMs: number().nullable()
19639
+ nearestEdgeMs: number().nullable(),
19640
+ prevEndMs: number().nullable().optional()
19501
19641
  })]);
19502
19642
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19503
19643
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -21066,6 +21206,12 @@ Object.freeze({
21066
21206
  addonId: null,
21067
21207
  access: "view"
21068
21208
  },
21209
+ "deviceManager.getLinkedDevices": {
21210
+ capName: "device-manager",
21211
+ capScope: "system",
21212
+ addonId: null,
21213
+ access: "view"
21214
+ },
21069
21215
  "deviceManager.getRoleDisplayDefaults": {
21070
21216
  capName: "device-manager",
21071
21217
  capScope: "system",
@@ -22620,6 +22766,12 @@ Object.freeze({
22620
22766
  addonId: null,
22621
22767
  access: "view"
22622
22768
  },
22769
+ "pipelineAnalytics.getSensorEvents": {
22770
+ capName: "pipeline-analytics",
22771
+ capScope: "device",
22772
+ addonId: null,
22773
+ access: "view"
22774
+ },
22623
22775
  "pipelineAnalytics.getTrack": {
22624
22776
  capName: "pipeline-analytics",
22625
22777
  capScope: "device",
@@ -22632,6 +22784,18 @@ Object.freeze({
22632
22784
  addonId: null,
22633
22785
  access: "view"
22634
22786
  },
22787
+ "pipelineAnalytics.listEventKinds": {
22788
+ capName: "pipeline-analytics",
22789
+ capScope: "device",
22790
+ addonId: null,
22791
+ access: "view"
22792
+ },
22793
+ "pipelineAnalytics.listRecentTracks": {
22794
+ capName: "pipeline-analytics",
22795
+ capScope: "device",
22796
+ addonId: null,
22797
+ access: "view"
22798
+ },
22635
22799
  "pipelineAnalytics.listTracks": {
22636
22800
  capName: "pipeline-analytics",
22637
22801
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-notifiers",
3
- "version": "1.1.25",
3
+ "version": "1.1.26",
4
4
  "description": "System notifiers addon for CamStack — a `notification-output` collection provider hosting per-kind notifier adapters (ntfy, pushover, gotify, telegram, discord, webhook, zentik).",
5
5
  "keywords": [
6
6
  "camstack",