@camstack/addon-advanced-notifier 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
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  let node_crypto = require("node:crypto");
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";
@@ -7222,6 +7225,24 @@ var RecordingRetentionSchema = object({
7222
7225
  maxSizeGb: number().min(0).optional()
7223
7226
  });
7224
7227
  /**
7228
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7229
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7230
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7231
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7232
+ *
7233
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7234
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7235
+ * preset changed over time renders every historical window at the dims it was
7236
+ * written with.
7237
+ */
7238
+ var ScrubThumbnailPresetSchema = _enum([
7239
+ "minimal",
7240
+ "low",
7241
+ "standard",
7242
+ "high",
7243
+ "max"
7244
+ ]);
7245
+ /**
7225
7246
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7226
7247
  *
7227
7248
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7258,7 +7279,14 @@ var RecordingConfigSchema = object({
7258
7279
  * derived into bands once via `migrateConfigToBands`.
7259
7280
  */
7260
7281
  bands: array(RecordingBandSchema).optional(),
7261
- retention: RecordingRetentionSchema.optional()
7282
+ retention: RecordingRetentionSchema.optional(),
7283
+ /**
7284
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7285
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7286
+ * windows only — existing sheets are immutable, and each window's index
7287
+ * carries its own tile dims so mixed-preset history renders correctly.
7288
+ */
7289
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7262
7290
  });
7263
7291
  /**
7264
7292
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -9831,7 +9859,7 @@ object({
9831
9859
  deviceId: number(),
9832
9860
  timestamp: number()
9833
9861
  });
9834
- DeviceType.Button;
9862
+ DeviceType.Button, DeviceType.Camera;
9835
9863
  /**
9836
9864
  * Enum-state sensor — a string value picked from a finite option set.
9837
9865
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14213,6 +14241,14 @@ var ConfigEntrySchema = object({
14213
14241
  value: unknown(),
14214
14242
  description: string().optional()
14215
14243
  });
14244
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14245
+ /** One resolved linked device — the compact projection consumers need. */
14246
+ var LinkedDeviceSchema = object({
14247
+ deviceId: number(),
14248
+ name: string(),
14249
+ location: string().nullable(),
14250
+ features: array(string())
14251
+ });
14216
14252
  var SavedDeviceRowSchema = object({
14217
14253
  /** Numeric id reserved at allocateDeviceId time. */
14218
14254
  id: number(),
@@ -14434,7 +14470,10 @@ method(object({
14434
14470
  }), _void(), {
14435
14471
  kind: "mutation",
14436
14472
  auth: "admin"
14437
- }), 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({
14473
+ }), 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({
14474
+ mode: DeviceLinkModeSchema,
14475
+ devices: array(LinkedDeviceSchema)
14476
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14438
14477
  deviceId: number(),
14439
14478
  values: record(string(), unknown())
14440
14479
  }), object({ success: literal(true) }), {
@@ -15717,6 +15756,61 @@ var EventKindSchema = _enum([
15717
15756
  "object",
15718
15757
  "audio"
15719
15758
  ]);
15759
+ /**
15760
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
15761
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
15762
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
15763
+ */
15764
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
15765
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
15766
+ var EventKindIconSchema = _enum([
15767
+ "motion",
15768
+ "audio",
15769
+ "person",
15770
+ "vehicle",
15771
+ "animal",
15772
+ "door",
15773
+ "pir",
15774
+ "smoke",
15775
+ "water",
15776
+ "button",
15777
+ "generic"
15778
+ ]);
15779
+ var EventKindCategorySchema = _enum([
15780
+ "motion",
15781
+ "audio",
15782
+ "detection",
15783
+ "sensor",
15784
+ "custom"
15785
+ ]);
15786
+ var EventKindDescriptorSchema = object({
15787
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
15788
+ kind: string(),
15789
+ label: string(),
15790
+ /** Hex color for timeline/legend rendering. */
15791
+ color: string(),
15792
+ icon: EventKindIconSchema,
15793
+ category: EventKindCategorySchema,
15794
+ /** Which cap + device contributes this kind. For built-ins the camera
15795
+ * itself; for sensor kinds the LINKED source device. */
15796
+ source: object({
15797
+ capName: string(),
15798
+ deviceId: number()
15799
+ })
15800
+ });
15801
+ var SensorEventSchema = object({
15802
+ id: string(),
15803
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
15804
+ * yields N rows, one per camera). */
15805
+ deviceId: number(),
15806
+ /** The linked sensor device whose state changed. */
15807
+ sourceDeviceId: number(),
15808
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
15809
+ kind: string(),
15810
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
15811
+ value: record(string(), unknown()).nullable(),
15812
+ timestamp: number()
15813
+ });
15720
15814
  var TrackPositionSchema = object({
15721
15815
  x: number(),
15722
15816
  y: number(),
@@ -15730,6 +15824,30 @@ var TrackSnapshotSchema = object({
15730
15824
  mediaKey: string()
15731
15825
  });
15732
15826
  /**
15827
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
15828
+ * divided by the track's detection-frame dims), computed at persist time.
15829
+ * Absent when the frame dims were unknown when the track was persisted
15830
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
15831
+ */
15832
+ var TrackEnvelopeSchema = object({
15833
+ minX: number(),
15834
+ minY: number(),
15835
+ maxX: number(),
15836
+ maxY: number()
15837
+ });
15838
+ /**
15839
+ * Row projection for track list queries. `full` (default) returns the
15840
+ * complete Track including the frame-rate `positions[]` history and the
15841
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
15842
+ * keeps every scalar the list surfaces actually render (ids, class(es),
15843
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
15844
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
15845
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
15846
+ * `getTrack`. Mirrors the event-store `projection` convention
15847
+ * (`getObjectEvents` et al.).
15848
+ */
15849
+ var TrackProjectionSchema = _enum(["full", "slim"]);
15850
+ /**
15733
15851
  * One audio-classification label heard on the track's camera while the
15734
15852
  * track was alive, aggregated per label. An "episode" is one persisted
15735
15853
  * audio event (the confident-classification path: score ≥ the device's
@@ -15780,7 +15898,11 @@ var TrackSchema = object({
15780
15898
  /** Audio-classification labels heard on the camera during the track's
15781
15899
  * life (score ≥ device `classificationMinScore`), aggregated per label.
15782
15900
  * Absent on legacy rows / tracks with no confident audio. */
15783
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
15901
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
15902
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
15903
+ * Populated from the persisted envelope columns on historical reads;
15904
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
15905
+ envelope: TrackEnvelopeSchema.optional()
15784
15906
  });
15785
15907
  var BaseEventFields = {
15786
15908
  id: string(),
@@ -15890,11 +16012,13 @@ var MediaFileSchema = object({
15890
16012
  sizeBytes: number(),
15891
16013
  timestamp: number()
15892
16014
  });
16015
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16016
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
15893
16017
  var DeviceEventQueryInput = object({
15894
16018
  deviceId: number(),
15895
16019
  since: number().optional(),
15896
16020
  until: number().optional(),
15897
- limit: number().int().min(1).max(5e3).default(1e3),
16021
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
15898
16022
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
15899
16023
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
15900
16024
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -15902,6 +16026,27 @@ var DeviceEventQueryInput = object({
15902
16026
  projection: _enum(["full", "slim"]).optional()
15903
16027
  });
15904
16028
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16029
+ var RecentTracksQueryInput = object({
16030
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16031
+ deviceIds: array(number()),
16032
+ /** Window lower bound on `lastSeen` (inclusive). */
16033
+ since: number().optional(),
16034
+ /** Window upper bound on `lastSeen` (inclusive). */
16035
+ until: number().optional(),
16036
+ /** Page size. Default 200, max 1000. */
16037
+ limit: number().int().min(1).max(1e3).default(200),
16038
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16039
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16040
+ cursor: string().optional(),
16041
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16042
+ projection: TrackProjectionSchema.optional()
16043
+ });
16044
+ var RecentTracksPageSchema = object({
16045
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16046
+ tracks: array(TrackSchema).readonly(),
16047
+ /** Cursor for the next page, or null when this page is the last. */
16048
+ nextCursor: string().nullable()
16049
+ });
15905
16050
  var KeyEventQueryInput = object({
15906
16051
  deviceId: number(),
15907
16052
  /** Window lower bound (track firstSeen ≥ since). */
@@ -15984,11 +16129,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15984
16129
  deviceId: number(),
15985
16130
  since: number().optional(),
15986
16131
  until: number().optional(),
15987
- limit: number().optional()
15988
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
15989
- kind: "mutation",
15990
- auth: "admin"
15991
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16132
+ limit: number().optional(),
16133
+ /** Spatial filter only tracks whose trajectory intersects the zone
16134
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16135
+ * envelope columns, then precisely tested per position. Tracks with
16136
+ * an unknown envelope (no frame dims at persist time) always match. */
16137
+ zone: TrackZoneFilterSchema.optional(),
16138
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16139
+ * compatible — omitting the field keeps today's exact behaviour). */
16140
+ projection: TrackProjectionSchema.optional()
16141
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16142
+ kind: "mutation",
16143
+ auth: "admin"
16144
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16145
+ deviceId: number(),
16146
+ since: number().optional(),
16147
+ until: number().optional(),
16148
+ kinds: array(string()).optional(),
16149
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16150
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
15992
16151
  deviceId: number(),
15993
16152
  since: number(),
15994
16153
  until: number(),
@@ -19189,7 +19348,12 @@ var RecordingStorageUsageSchema = object({
19189
19348
  /**
19190
19349
  * Result of locating footage at a wall-clock instant for one device/profile.
19191
19350
  * `segment` carries the covering segment's window; `gap` reports the forward
19192
- * nearest covered edge (`null` past the end of footage / when none exists).
19351
+ * nearest covered edge (`null` past the end of footage / when none exists)
19352
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19353
+ * footage behind the epoch; `null` when none — optional so older providers
19354
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19355
+ * small inter-segment cracks (durMs under-covers the span to the next
19356
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19193
19357
  */
19194
19358
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19195
19359
  kind: literal("segment"),
@@ -19198,7 +19362,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19198
19362
  bytes: number()
19199
19363
  }), object({
19200
19364
  kind: literal("gap"),
19201
- nearestEdgeMs: number().nullable()
19365
+ nearestEdgeMs: number().nullable(),
19366
+ prevEndMs: number().nullable().optional()
19202
19367
  })]);
19203
19368
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19204
19369
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -20767,6 +20932,12 @@ Object.freeze({
20767
20932
  addonId: null,
20768
20933
  access: "view"
20769
20934
  },
20935
+ "deviceManager.getLinkedDevices": {
20936
+ capName: "device-manager",
20937
+ capScope: "system",
20938
+ addonId: null,
20939
+ access: "view"
20940
+ },
20770
20941
  "deviceManager.getRoleDisplayDefaults": {
20771
20942
  capName: "device-manager",
20772
20943
  capScope: "system",
@@ -22321,6 +22492,12 @@ Object.freeze({
22321
22492
  addonId: null,
22322
22493
  access: "view"
22323
22494
  },
22495
+ "pipelineAnalytics.getSensorEvents": {
22496
+ capName: "pipeline-analytics",
22497
+ capScope: "device",
22498
+ addonId: null,
22499
+ access: "view"
22500
+ },
22324
22501
  "pipelineAnalytics.getTrack": {
22325
22502
  capName: "pipeline-analytics",
22326
22503
  capScope: "device",
@@ -22333,6 +22510,18 @@ Object.freeze({
22333
22510
  addonId: null,
22334
22511
  access: "view"
22335
22512
  },
22513
+ "pipelineAnalytics.listEventKinds": {
22514
+ capName: "pipeline-analytics",
22515
+ capScope: "device",
22516
+ addonId: null,
22517
+ access: "view"
22518
+ },
22519
+ "pipelineAnalytics.listRecentTracks": {
22520
+ capName: "pipeline-analytics",
22521
+ capScope: "device",
22522
+ addonId: null,
22523
+ access: "view"
22524
+ },
22336
22525
  "pipelineAnalytics.listTracks": {
22337
22526
  capName: "pipeline-analytics",
22338
22527
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
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";
@@ -7218,6 +7221,24 @@ var RecordingRetentionSchema = object({
7218
7221
  maxSizeGb: number().min(0).optional()
7219
7222
  });
7220
7223
  /**
7224
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7225
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7226
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7227
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7228
+ *
7229
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7230
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7231
+ * preset changed over time renders every historical window at the dims it was
7232
+ * written with.
7233
+ */
7234
+ var ScrubThumbnailPresetSchema = _enum([
7235
+ "minimal",
7236
+ "low",
7237
+ "standard",
7238
+ "high",
7239
+ "max"
7240
+ ]);
7241
+ /**
7221
7242
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7222
7243
  *
7223
7244
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7254,7 +7275,14 @@ var RecordingConfigSchema = object({
7254
7275
  * derived into bands once via `migrateConfigToBands`.
7255
7276
  */
7256
7277
  bands: array(RecordingBandSchema).optional(),
7257
- retention: RecordingRetentionSchema.optional()
7278
+ retention: RecordingRetentionSchema.optional(),
7279
+ /**
7280
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7281
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7282
+ * windows only — existing sheets are immutable, and each window's index
7283
+ * carries its own tile dims so mixed-preset history renders correctly.
7284
+ */
7285
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7258
7286
  });
7259
7287
  /**
7260
7288
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -9827,7 +9855,7 @@ object({
9827
9855
  deviceId: number(),
9828
9856
  timestamp: number()
9829
9857
  });
9830
- DeviceType.Button;
9858
+ DeviceType.Button, DeviceType.Camera;
9831
9859
  /**
9832
9860
  * Enum-state sensor — a string value picked from a finite option set.
9833
9861
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14209,6 +14237,14 @@ var ConfigEntrySchema = object({
14209
14237
  value: unknown(),
14210
14238
  description: string().optional()
14211
14239
  });
14240
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14241
+ /** One resolved linked device — the compact projection consumers need. */
14242
+ var LinkedDeviceSchema = object({
14243
+ deviceId: number(),
14244
+ name: string(),
14245
+ location: string().nullable(),
14246
+ features: array(string())
14247
+ });
14212
14248
  var SavedDeviceRowSchema = object({
14213
14249
  /** Numeric id reserved at allocateDeviceId time. */
14214
14250
  id: number(),
@@ -14430,7 +14466,10 @@ method(object({
14430
14466
  }), _void(), {
14431
14467
  kind: "mutation",
14432
14468
  auth: "admin"
14433
- }), 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({
14469
+ }), 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({
14470
+ mode: DeviceLinkModeSchema,
14471
+ devices: array(LinkedDeviceSchema)
14472
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14434
14473
  deviceId: number(),
14435
14474
  values: record(string(), unknown())
14436
14475
  }), object({ success: literal(true) }), {
@@ -15713,6 +15752,61 @@ var EventKindSchema = _enum([
15713
15752
  "object",
15714
15753
  "audio"
15715
15754
  ]);
15755
+ /**
15756
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
15757
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
15758
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
15759
+ */
15760
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
15761
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
15762
+ var EventKindIconSchema = _enum([
15763
+ "motion",
15764
+ "audio",
15765
+ "person",
15766
+ "vehicle",
15767
+ "animal",
15768
+ "door",
15769
+ "pir",
15770
+ "smoke",
15771
+ "water",
15772
+ "button",
15773
+ "generic"
15774
+ ]);
15775
+ var EventKindCategorySchema = _enum([
15776
+ "motion",
15777
+ "audio",
15778
+ "detection",
15779
+ "sensor",
15780
+ "custom"
15781
+ ]);
15782
+ var EventKindDescriptorSchema = object({
15783
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
15784
+ kind: string(),
15785
+ label: string(),
15786
+ /** Hex color for timeline/legend rendering. */
15787
+ color: string(),
15788
+ icon: EventKindIconSchema,
15789
+ category: EventKindCategorySchema,
15790
+ /** Which cap + device contributes this kind. For built-ins the camera
15791
+ * itself; for sensor kinds the LINKED source device. */
15792
+ source: object({
15793
+ capName: string(),
15794
+ deviceId: number()
15795
+ })
15796
+ });
15797
+ var SensorEventSchema = object({
15798
+ id: string(),
15799
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
15800
+ * yields N rows, one per camera). */
15801
+ deviceId: number(),
15802
+ /** The linked sensor device whose state changed. */
15803
+ sourceDeviceId: number(),
15804
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
15805
+ kind: string(),
15806
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
15807
+ value: record(string(), unknown()).nullable(),
15808
+ timestamp: number()
15809
+ });
15716
15810
  var TrackPositionSchema = object({
15717
15811
  x: number(),
15718
15812
  y: number(),
@@ -15726,6 +15820,30 @@ var TrackSnapshotSchema = object({
15726
15820
  mediaKey: string()
15727
15821
  });
15728
15822
  /**
15823
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
15824
+ * divided by the track's detection-frame dims), computed at persist time.
15825
+ * Absent when the frame dims were unknown when the track was persisted
15826
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
15827
+ */
15828
+ var TrackEnvelopeSchema = object({
15829
+ minX: number(),
15830
+ minY: number(),
15831
+ maxX: number(),
15832
+ maxY: number()
15833
+ });
15834
+ /**
15835
+ * Row projection for track list queries. `full` (default) returns the
15836
+ * complete Track including the frame-rate `positions[]` history and the
15837
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
15838
+ * keeps every scalar the list surfaces actually render (ids, class(es),
15839
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
15840
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
15841
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
15842
+ * `getTrack`. Mirrors the event-store `projection` convention
15843
+ * (`getObjectEvents` et al.).
15844
+ */
15845
+ var TrackProjectionSchema = _enum(["full", "slim"]);
15846
+ /**
15729
15847
  * One audio-classification label heard on the track's camera while the
15730
15848
  * track was alive, aggregated per label. An "episode" is one persisted
15731
15849
  * audio event (the confident-classification path: score ≥ the device's
@@ -15776,7 +15894,11 @@ var TrackSchema = object({
15776
15894
  /** Audio-classification labels heard on the camera during the track's
15777
15895
  * life (score ≥ device `classificationMinScore`), aggregated per label.
15778
15896
  * Absent on legacy rows / tracks with no confident audio. */
15779
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
15897
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
15898
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
15899
+ * Populated from the persisted envelope columns on historical reads;
15900
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
15901
+ envelope: TrackEnvelopeSchema.optional()
15780
15902
  });
15781
15903
  var BaseEventFields = {
15782
15904
  id: string(),
@@ -15886,11 +16008,13 @@ var MediaFileSchema = object({
15886
16008
  sizeBytes: number(),
15887
16009
  timestamp: number()
15888
16010
  });
16011
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16012
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
15889
16013
  var DeviceEventQueryInput = object({
15890
16014
  deviceId: number(),
15891
16015
  since: number().optional(),
15892
16016
  until: number().optional(),
15893
- limit: number().int().min(1).max(5e3).default(1e3),
16017
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
15894
16018
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
15895
16019
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
15896
16020
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -15898,6 +16022,27 @@ var DeviceEventQueryInput = object({
15898
16022
  projection: _enum(["full", "slim"]).optional()
15899
16023
  });
15900
16024
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16025
+ var RecentTracksQueryInput = object({
16026
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16027
+ deviceIds: array(number()),
16028
+ /** Window lower bound on `lastSeen` (inclusive). */
16029
+ since: number().optional(),
16030
+ /** Window upper bound on `lastSeen` (inclusive). */
16031
+ until: number().optional(),
16032
+ /** Page size. Default 200, max 1000. */
16033
+ limit: number().int().min(1).max(1e3).default(200),
16034
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16035
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16036
+ cursor: string().optional(),
16037
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16038
+ projection: TrackProjectionSchema.optional()
16039
+ });
16040
+ var RecentTracksPageSchema = object({
16041
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16042
+ tracks: array(TrackSchema).readonly(),
16043
+ /** Cursor for the next page, or null when this page is the last. */
16044
+ nextCursor: string().nullable()
16045
+ });
15901
16046
  var KeyEventQueryInput = object({
15902
16047
  deviceId: number(),
15903
16048
  /** Window lower bound (track firstSeen ≥ since). */
@@ -15980,11 +16125,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
15980
16125
  deviceId: number(),
15981
16126
  since: number().optional(),
15982
16127
  until: number().optional(),
15983
- limit: number().optional()
15984
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
15985
- kind: "mutation",
15986
- auth: "admin"
15987
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16128
+ limit: number().optional(),
16129
+ /** Spatial filter only tracks whose trajectory intersects the zone
16130
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16131
+ * envelope columns, then precisely tested per position. Tracks with
16132
+ * an unknown envelope (no frame dims at persist time) always match. */
16133
+ zone: TrackZoneFilterSchema.optional(),
16134
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16135
+ * compatible — omitting the field keeps today's exact behaviour). */
16136
+ projection: TrackProjectionSchema.optional()
16137
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16138
+ kind: "mutation",
16139
+ auth: "admin"
16140
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16141
+ deviceId: number(),
16142
+ since: number().optional(),
16143
+ until: number().optional(),
16144
+ kinds: array(string()).optional(),
16145
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16146
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
15988
16147
  deviceId: number(),
15989
16148
  since: number(),
15990
16149
  until: number(),
@@ -19185,7 +19344,12 @@ var RecordingStorageUsageSchema = object({
19185
19344
  /**
19186
19345
  * Result of locating footage at a wall-clock instant for one device/profile.
19187
19346
  * `segment` carries the covering segment's window; `gap` reports the forward
19188
- * nearest covered edge (`null` past the end of footage / when none exists).
19347
+ * nearest covered edge (`null` past the end of footage / when none exists)
19348
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19349
+ * footage behind the epoch; `null` when none — optional so older providers
19350
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19351
+ * small inter-segment cracks (durMs under-covers the span to the next
19352
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19189
19353
  */
19190
19354
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19191
19355
  kind: literal("segment"),
@@ -19194,7 +19358,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19194
19358
  bytes: number()
19195
19359
  }), object({
19196
19360
  kind: literal("gap"),
19197
- nearestEdgeMs: number().nullable()
19361
+ nearestEdgeMs: number().nullable(),
19362
+ prevEndMs: number().nullable().optional()
19198
19363
  })]);
19199
19364
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19200
19365
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -20763,6 +20928,12 @@ Object.freeze({
20763
20928
  addonId: null,
20764
20929
  access: "view"
20765
20930
  },
20931
+ "deviceManager.getLinkedDevices": {
20932
+ capName: "device-manager",
20933
+ capScope: "system",
20934
+ addonId: null,
20935
+ access: "view"
20936
+ },
20766
20937
  "deviceManager.getRoleDisplayDefaults": {
20767
20938
  capName: "device-manager",
20768
20939
  capScope: "system",
@@ -22317,6 +22488,12 @@ Object.freeze({
22317
22488
  addonId: null,
22318
22489
  access: "view"
22319
22490
  },
22491
+ "pipelineAnalytics.getSensorEvents": {
22492
+ capName: "pipeline-analytics",
22493
+ capScope: "device",
22494
+ addonId: null,
22495
+ access: "view"
22496
+ },
22320
22497
  "pipelineAnalytics.getTrack": {
22321
22498
  capName: "pipeline-analytics",
22322
22499
  capScope: "device",
@@ -22329,6 +22506,18 @@ Object.freeze({
22329
22506
  addonId: null,
22330
22507
  access: "view"
22331
22508
  },
22509
+ "pipelineAnalytics.listEventKinds": {
22510
+ capName: "pipeline-analytics",
22511
+ capScope: "device",
22512
+ addonId: null,
22513
+ access: "view"
22514
+ },
22515
+ "pipelineAnalytics.listRecentTracks": {
22516
+ capName: "pipeline-analytics",
22517
+ capScope: "device",
22518
+ addonId: null,
22519
+ access: "view"
22520
+ },
22332
22521
  "pipelineAnalytics.listTracks": {
22333
22522
  capName: "pipeline-analytics",
22334
22523
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-advanced-notifier",
3
- "version": "1.1.25",
3
+ "version": "1.1.27",
4
4
  "description": "Rules-based notification engine for CamStack",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",