@camstack/addon-export-alexa 1.1.22 → 1.1.24

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.
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  //#endregion
27
27
  let node_crypto = require("node:crypto");
28
28
  node_crypto = __toESM(node_crypto);
29
- //#region ../types/dist/event-category-CFZs3jI4.mjs
29
+ //#region ../types/dist/event-category-H4AVePnn.mjs
30
30
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
31
31
  EventCategory["SystemBoot"] = "system.boot";
32
32
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -176,6 +176,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
176
176
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
177
177
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
178
178
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
179
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
180
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
181
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
179
182
  EventCategory["DetectionEvent"] = "detection.event";
180
183
  EventCategory["SessionTrackNew"] = "session.track.new";
181
184
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -7385,6 +7388,24 @@ var RecordingRetentionSchema = object({
7385
7388
  maxSizeGb: number().min(0).optional()
7386
7389
  });
7387
7390
  /**
7391
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7392
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7393
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7394
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7395
+ *
7396
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7397
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7398
+ * preset changed over time renders every historical window at the dims it was
7399
+ * written with.
7400
+ */
7401
+ var ScrubThumbnailPresetSchema = _enum([
7402
+ "minimal",
7403
+ "low",
7404
+ "standard",
7405
+ "high",
7406
+ "max"
7407
+ ]);
7408
+ /**
7388
7409
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7389
7410
  *
7390
7411
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7421,7 +7442,14 @@ var RecordingConfigSchema = object({
7421
7442
  * derived into bands once via `migrateConfigToBands`.
7422
7443
  */
7423
7444
  bands: array(RecordingBandSchema).optional(),
7424
- retention: RecordingRetentionSchema.optional()
7445
+ retention: RecordingRetentionSchema.optional(),
7446
+ /**
7447
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7448
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7449
+ * windows only — existing sheets are immutable, and each window's index
7450
+ * carries its own tile dims so mixed-preset history renders correctly.
7451
+ */
7452
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7425
7453
  });
7426
7454
  /**
7427
7455
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -10034,7 +10062,7 @@ object({
10034
10062
  deviceId: number(),
10035
10063
  timestamp: number()
10036
10064
  });
10037
- DeviceType.Button;
10065
+ DeviceType.Button, DeviceType.Camera;
10038
10066
  /**
10039
10067
  * Enum-state sensor — a string value picked from a finite option set.
10040
10068
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14469,6 +14497,14 @@ var ConfigEntrySchema = object({
14469
14497
  value: unknown(),
14470
14498
  description: string().optional()
14471
14499
  });
14500
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14501
+ /** One resolved linked device — the compact projection consumers need. */
14502
+ var LinkedDeviceSchema = object({
14503
+ deviceId: number(),
14504
+ name: string(),
14505
+ location: string().nullable(),
14506
+ features: array(string())
14507
+ });
14472
14508
  var SavedDeviceRowSchema = object({
14473
14509
  /** Numeric id reserved at allocateDeviceId time. */
14474
14510
  id: number(),
@@ -14690,7 +14726,10 @@ method(object({
14690
14726
  }), _void(), {
14691
14727
  kind: "mutation",
14692
14728
  auth: "admin"
14693
- }), 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({
14729
+ }), 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({
14730
+ mode: DeviceLinkModeSchema,
14731
+ devices: array(LinkedDeviceSchema)
14732
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14694
14733
  deviceId: number(),
14695
14734
  values: record(string(), unknown())
14696
14735
  }), object({ success: literal(true) }), {
@@ -15965,6 +16004,61 @@ var EventKindSchema = _enum([
15965
16004
  "object",
15966
16005
  "audio"
15967
16006
  ]);
16007
+ /**
16008
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
16009
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
16010
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
16011
+ */
16012
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
16013
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
16014
+ var EventKindIconSchema = _enum([
16015
+ "motion",
16016
+ "audio",
16017
+ "person",
16018
+ "vehicle",
16019
+ "animal",
16020
+ "door",
16021
+ "pir",
16022
+ "smoke",
16023
+ "water",
16024
+ "button",
16025
+ "generic"
16026
+ ]);
16027
+ var EventKindCategorySchema = _enum([
16028
+ "motion",
16029
+ "audio",
16030
+ "detection",
16031
+ "sensor",
16032
+ "custom"
16033
+ ]);
16034
+ var EventKindDescriptorSchema = object({
16035
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16036
+ kind: string(),
16037
+ label: string(),
16038
+ /** Hex color for timeline/legend rendering. */
16039
+ color: string(),
16040
+ icon: EventKindIconSchema,
16041
+ category: EventKindCategorySchema,
16042
+ /** Which cap + device contributes this kind. For built-ins the camera
16043
+ * itself; for sensor kinds the LINKED source device. */
16044
+ source: object({
16045
+ capName: string(),
16046
+ deviceId: number()
16047
+ })
16048
+ });
16049
+ var SensorEventSchema = object({
16050
+ id: string(),
16051
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16052
+ * yields N rows, one per camera). */
16053
+ deviceId: number(),
16054
+ /** The linked sensor device whose state changed. */
16055
+ sourceDeviceId: number(),
16056
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16057
+ kind: string(),
16058
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16059
+ value: record(string(), unknown()).nullable(),
16060
+ timestamp: number()
16061
+ });
15968
16062
  var TrackPositionSchema = object({
15969
16063
  x: number(),
15970
16064
  y: number(),
@@ -15978,6 +16072,30 @@ var TrackSnapshotSchema = object({
15978
16072
  mediaKey: string()
15979
16073
  });
15980
16074
  /**
16075
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16076
+ * divided by the track's detection-frame dims), computed at persist time.
16077
+ * Absent when the frame dims were unknown when the track was persisted
16078
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16079
+ */
16080
+ var TrackEnvelopeSchema = object({
16081
+ minX: number(),
16082
+ minY: number(),
16083
+ maxX: number(),
16084
+ maxY: number()
16085
+ });
16086
+ /**
16087
+ * Row projection for track list queries. `full` (default) returns the
16088
+ * complete Track including the frame-rate `positions[]` history and the
16089
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16090
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16091
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16092
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16093
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16094
+ * `getTrack`. Mirrors the event-store `projection` convention
16095
+ * (`getObjectEvents` et al.).
16096
+ */
16097
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16098
+ /**
15981
16099
  * One audio-classification label heard on the track's camera while the
15982
16100
  * track was alive, aggregated per label. An "episode" is one persisted
15983
16101
  * audio event (the confident-classification path: score ≥ the device's
@@ -16028,7 +16146,11 @@ var TrackSchema = object({
16028
16146
  /** Audio-classification labels heard on the camera during the track's
16029
16147
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16030
16148
  * Absent on legacy rows / tracks with no confident audio. */
16031
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16149
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16150
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16151
+ * Populated from the persisted envelope columns on historical reads;
16152
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16153
+ envelope: TrackEnvelopeSchema.optional()
16032
16154
  });
16033
16155
  var BaseEventFields = {
16034
16156
  id: string(),
@@ -16138,11 +16260,13 @@ var MediaFileSchema = object({
16138
16260
  sizeBytes: number(),
16139
16261
  timestamp: number()
16140
16262
  });
16263
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16264
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16141
16265
  var DeviceEventQueryInput = object({
16142
16266
  deviceId: number(),
16143
16267
  since: number().optional(),
16144
16268
  until: number().optional(),
16145
- limit: number().int().min(1).max(5e3).default(1e3),
16269
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16146
16270
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16147
16271
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16148
16272
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16150,6 +16274,27 @@ var DeviceEventQueryInput = object({
16150
16274
  projection: _enum(["full", "slim"]).optional()
16151
16275
  });
16152
16276
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16277
+ var RecentTracksQueryInput = object({
16278
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16279
+ deviceIds: array(number()),
16280
+ /** Window lower bound on `lastSeen` (inclusive). */
16281
+ since: number().optional(),
16282
+ /** Window upper bound on `lastSeen` (inclusive). */
16283
+ until: number().optional(),
16284
+ /** Page size. Default 200, max 1000. */
16285
+ limit: number().int().min(1).max(1e3).default(200),
16286
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16287
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16288
+ cursor: string().optional(),
16289
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16290
+ projection: TrackProjectionSchema.optional()
16291
+ });
16292
+ var RecentTracksPageSchema = object({
16293
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16294
+ tracks: array(TrackSchema).readonly(),
16295
+ /** Cursor for the next page, or null when this page is the last. */
16296
+ nextCursor: string().nullable()
16297
+ });
16153
16298
  var KeyEventQueryInput = object({
16154
16299
  deviceId: number(),
16155
16300
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16232,11 +16377,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16232
16377
  deviceId: number(),
16233
16378
  since: number().optional(),
16234
16379
  until: number().optional(),
16235
- limit: number().optional()
16236
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16237
- kind: "mutation",
16238
- auth: "admin"
16239
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16380
+ limit: number().optional(),
16381
+ /** Spatial filter only tracks whose trajectory intersects the zone
16382
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16383
+ * envelope columns, then precisely tested per position. Tracks with
16384
+ * an unknown envelope (no frame dims at persist time) always match. */
16385
+ zone: TrackZoneFilterSchema.optional(),
16386
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16387
+ * compatible — omitting the field keeps today's exact behaviour). */
16388
+ projection: TrackProjectionSchema.optional()
16389
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16390
+ kind: "mutation",
16391
+ auth: "admin"
16392
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16393
+ deviceId: number(),
16394
+ since: number().optional(),
16395
+ until: number().optional(),
16396
+ kinds: array(string()).optional(),
16397
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16398
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16240
16399
  deviceId: number(),
16241
16400
  since: number(),
16242
16401
  until: number(),
@@ -19437,7 +19596,12 @@ var RecordingStorageUsageSchema = object({
19437
19596
  /**
19438
19597
  * Result of locating footage at a wall-clock instant for one device/profile.
19439
19598
  * `segment` carries the covering segment's window; `gap` reports the forward
19440
- * nearest covered edge (`null` past the end of footage / when none exists).
19599
+ * nearest covered edge (`null` past the end of footage / when none exists)
19600
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19601
+ * footage behind the epoch; `null` when none — optional so older providers
19602
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19603
+ * small inter-segment cracks (durMs under-covers the span to the next
19604
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19441
19605
  */
19442
19606
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19443
19607
  kind: literal("segment"),
@@ -19446,7 +19610,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19446
19610
  bytes: number()
19447
19611
  }), object({
19448
19612
  kind: literal("gap"),
19449
- nearestEdgeMs: number().nullable()
19613
+ nearestEdgeMs: number().nullable(),
19614
+ prevEndMs: number().nullable().optional()
19450
19615
  })]);
19451
19616
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19452
19617
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -21015,6 +21180,12 @@ Object.freeze({
21015
21180
  addonId: null,
21016
21181
  access: "view"
21017
21182
  },
21183
+ "deviceManager.getLinkedDevices": {
21184
+ capName: "device-manager",
21185
+ capScope: "system",
21186
+ addonId: null,
21187
+ access: "view"
21188
+ },
21018
21189
  "deviceManager.getRoleDisplayDefaults": {
21019
21190
  capName: "device-manager",
21020
21191
  capScope: "system",
@@ -22569,6 +22740,12 @@ Object.freeze({
22569
22740
  addonId: null,
22570
22741
  access: "view"
22571
22742
  },
22743
+ "pipelineAnalytics.getSensorEvents": {
22744
+ capName: "pipeline-analytics",
22745
+ capScope: "device",
22746
+ addonId: null,
22747
+ access: "view"
22748
+ },
22572
22749
  "pipelineAnalytics.getTrack": {
22573
22750
  capName: "pipeline-analytics",
22574
22751
  capScope: "device",
@@ -22581,6 +22758,18 @@ Object.freeze({
22581
22758
  addonId: null,
22582
22759
  access: "view"
22583
22760
  },
22761
+ "pipelineAnalytics.listEventKinds": {
22762
+ capName: "pipeline-analytics",
22763
+ capScope: "device",
22764
+ addonId: null,
22765
+ access: "view"
22766
+ },
22767
+ "pipelineAnalytics.listRecentTracks": {
22768
+ capName: "pipeline-analytics",
22769
+ capScope: "device",
22770
+ addonId: null,
22771
+ access: "view"
22772
+ },
22584
22773
  "pipelineAnalytics.listTracks": {
22585
22774
  capName: "pipeline-analytics",
22586
22775
  capScope: "device",
@@ -1,6 +1,6 @@
1
1
  import * as crypto$1 from "node:crypto";
2
2
  import { createHash } from "node:crypto";
3
- //#region ../types/dist/event-category-CFZs3jI4.mjs
3
+ //#region ../types/dist/event-category-H4AVePnn.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -150,6 +150,9 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
150
150
  EventCategory["RecordingSegmentWritten"] = "recording.segment.written";
151
151
  EventCategory["RecordingPolicyFallback"] = "recording.policy.fallback";
152
152
  EventCategory["RecordingRetentionCompleted"] = "recording.retention.completed";
153
+ /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
154
+ * thumb is a scrub gap the recorder's keyframe backfill covers. */
155
+ EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
153
156
  EventCategory["DetectionEvent"] = "detection.event";
154
157
  EventCategory["SessionTrackNew"] = "session.track.new";
155
158
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -7359,6 +7362,24 @@ var RecordingRetentionSchema = object({
7359
7362
  maxSizeGb: number().min(0).optional()
7360
7363
  });
7361
7364
  /**
7365
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7366
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7367
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7368
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7369
+ *
7370
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7371
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7372
+ * preset changed over time renders every historical window at the dims it was
7373
+ * written with.
7374
+ */
7375
+ var ScrubThumbnailPresetSchema = _enum([
7376
+ "minimal",
7377
+ "low",
7378
+ "standard",
7379
+ "high",
7380
+ "max"
7381
+ ]);
7382
+ /**
7362
7383
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7363
7384
  *
7364
7385
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7395,7 +7416,14 @@ var RecordingConfigSchema = object({
7395
7416
  * derived into bands once via `migrateConfigToBands`.
7396
7417
  */
7397
7418
  bands: array(RecordingBandSchema).optional(),
7398
- retention: RecordingRetentionSchema.optional()
7419
+ retention: RecordingRetentionSchema.optional(),
7420
+ /**
7421
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7422
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7423
+ * windows only — existing sheets are immutable, and each window's index
7424
+ * carries its own tile dims so mixed-preset history renders correctly.
7425
+ */
7426
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7399
7427
  });
7400
7428
  /**
7401
7429
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -10008,7 +10036,7 @@ object({
10008
10036
  deviceId: number(),
10009
10037
  timestamp: number()
10010
10038
  });
10011
- DeviceType.Button;
10039
+ DeviceType.Button, DeviceType.Camera;
10012
10040
  /**
10013
10041
  * Enum-state sensor — a string value picked from a finite option set.
10014
10042
  * Drives HA `sensor` entries with `state_class: enum` (HVAC action
@@ -14443,6 +14471,14 @@ var ConfigEntrySchema = object({
14443
14471
  value: unknown(),
14444
14472
  description: string().optional()
14445
14473
  });
14474
+ var DeviceLinkModeSchema = _enum(["auto", "manual"]);
14475
+ /** One resolved linked device — the compact projection consumers need. */
14476
+ var LinkedDeviceSchema = object({
14477
+ deviceId: number(),
14478
+ name: string(),
14479
+ location: string().nullable(),
14480
+ features: array(string())
14481
+ });
14446
14482
  var SavedDeviceRowSchema = object({
14447
14483
  /** Numeric id reserved at allocateDeviceId time. */
14448
14484
  id: number(),
@@ -14664,7 +14700,10 @@ method(object({
14664
14700
  }), _void(), {
14665
14701
  kind: "mutation",
14666
14702
  auth: "admin"
14667
- }), 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({
14703
+ }), 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({
14704
+ mode: DeviceLinkModeSchema,
14705
+ devices: array(LinkedDeviceSchema)
14706
+ })), method(object({ deviceId: number() }), array(StreamSourceEntrySchema$1)), method(object({ deviceId: number() }), array(ConfigEntrySchema)), method(object({ deviceId: number() }), ConfigUISchemaOutput), method(object({
14668
14707
  deviceId: number(),
14669
14708
  values: record(string(), unknown())
14670
14709
  }), object({ success: literal(true) }), {
@@ -15939,6 +15978,61 @@ var EventKindSchema = _enum([
15939
15978
  "object",
15940
15979
  "audio"
15941
15980
  ]);
15981
+ /**
15982
+ * Spatial filter for `listTracks` — the rect + polygon variants of the shared
15983
+ * MaskShape vocabulary (see `mask-shape.ts`). Coordinates are NORMALIZED 0..1
15984
+ * of the camera frame (top-left origin), matching the drawing-plane editor.
15985
+ */
15986
+ var TrackZoneFilterSchema = discriminatedUnion("kind", [MaskRectShapeSchema, MaskPolygonShapeSchema]);
15987
+ /** Closed icon vocabulary so clients render a known glyph per kind. */
15988
+ var EventKindIconSchema = _enum([
15989
+ "motion",
15990
+ "audio",
15991
+ "person",
15992
+ "vehicle",
15993
+ "animal",
15994
+ "door",
15995
+ "pir",
15996
+ "smoke",
15997
+ "water",
15998
+ "button",
15999
+ "generic"
16000
+ ]);
16001
+ var EventKindCategorySchema = _enum([
16002
+ "motion",
16003
+ "audio",
16004
+ "detection",
16005
+ "sensor",
16006
+ "custom"
16007
+ ]);
16008
+ var EventKindDescriptorSchema = object({
16009
+ /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
16010
+ kind: string(),
16011
+ label: string(),
16012
+ /** Hex color for timeline/legend rendering. */
16013
+ color: string(),
16014
+ icon: EventKindIconSchema,
16015
+ category: EventKindCategorySchema,
16016
+ /** Which cap + device contributes this kind. For built-ins the camera
16017
+ * itself; for sensor kinds the LINKED source device. */
16018
+ source: object({
16019
+ capName: string(),
16020
+ deviceId: number()
16021
+ })
16022
+ });
16023
+ var SensorEventSchema = object({
16024
+ id: string(),
16025
+ /** The CAMERA the event is attributed to (a sensor linked to N cameras
16026
+ * yields N rows, one per camera). */
16027
+ deviceId: number(),
16028
+ /** The linked sensor device whose state changed. */
16029
+ sourceDeviceId: number(),
16030
+ /** Event kind id — matches an `EventKindDescriptor.kind`. */
16031
+ kind: string(),
16032
+ /** Snapshot of the sensor cap's runtime-state slice at the change. */
16033
+ value: record(string(), unknown()).nullable(),
16034
+ timestamp: number()
16035
+ });
15942
16036
  var TrackPositionSchema = object({
15943
16037
  x: number(),
15944
16038
  y: number(),
@@ -15952,6 +16046,30 @@ var TrackSnapshotSchema = object({
15952
16046
  mediaKey: string()
15953
16047
  });
15954
16048
  /**
16049
+ * Normalized 0..1 trajectory envelope (min/max over every position bbox,
16050
+ * divided by the track's detection-frame dims), computed at persist time.
16051
+ * Absent when the frame dims were unknown when the track was persisted
16052
+ * (legacy rows / dims-less sources) and on active (in-RAM) tracks.
16053
+ */
16054
+ var TrackEnvelopeSchema = object({
16055
+ minX: number(),
16056
+ minY: number(),
16057
+ maxX: number(),
16058
+ maxY: number()
16059
+ });
16060
+ /**
16061
+ * Row projection for track list queries. `full` (default) returns the
16062
+ * complete Track including the frame-rate `positions[]` history and the
16063
+ * `snapshots[]` references — megabytes across a page of tracks. `slim`
16064
+ * keeps every scalar the list surfaces actually render (ids, class(es),
16065
+ * label / audioLabels / importance enrichment, firstSeen/lastSeen, state,
16066
+ * zonesVisited, bestEventId, envelope) and returns `positions` /
16067
+ * `snapshots` as EMPTY arrays — detail views re-fetch the full row via
16068
+ * `getTrack`. Mirrors the event-store `projection` convention
16069
+ * (`getObjectEvents` et al.).
16070
+ */
16071
+ var TrackProjectionSchema = _enum(["full", "slim"]);
16072
+ /**
15955
16073
  * One audio-classification label heard on the track's camera while the
15956
16074
  * track was alive, aggregated per label. An "episode" is one persisted
15957
16075
  * audio event (the confident-classification path: score ≥ the device's
@@ -16002,7 +16120,11 @@ var TrackSchema = object({
16002
16120
  /** Audio-classification labels heard on the camera during the track's
16003
16121
  * life (score ≥ device `classificationMinScore`), aggregated per label.
16004
16122
  * Absent on legacy rows / tracks with no confident audio. */
16005
- audioLabels: array(TrackAudioLabelSchema).readonly().optional()
16123
+ audioLabels: array(TrackAudioLabelSchema).readonly().optional(),
16124
+ /** Normalized 0..1 trajectory envelope (see {@link TrackEnvelopeSchema}).
16125
+ * Populated from the persisted envelope columns on historical reads;
16126
+ * absent on legacy rows, dims-less tracks and active (in-RAM) tracks. */
16127
+ envelope: TrackEnvelopeSchema.optional()
16006
16128
  });
16007
16129
  var BaseEventFields = {
16008
16130
  id: string(),
@@ -16112,11 +16234,13 @@ var MediaFileSchema = object({
16112
16234
  sizeBytes: number(),
16113
16235
  timestamp: number()
16114
16236
  });
16237
+ var DEFAULT_EVENT_QUERY_LIMIT = 1e3;
16238
+ var MAX_EVENT_QUERY_LIMIT = 5e3;
16115
16239
  var DeviceEventQueryInput = object({
16116
16240
  deviceId: number(),
16117
16241
  since: number().optional(),
16118
16242
  until: number().optional(),
16119
- limit: number().int().min(1).max(5e3).default(1e3),
16243
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT),
16120
16244
  /** `slim` drops heavy JSON fields (regions/bbox/zones) and carries an
16121
16245
  * optional `mediaUrl` (populated by B5). `full` (default) keeps today's
16122
16246
  * exact behaviour. Callers may omit this field — the store defaults to
@@ -16124,6 +16248,27 @@ var DeviceEventQueryInput = object({
16124
16248
  projection: _enum(["full", "slim"]).optional()
16125
16249
  });
16126
16250
  var ObjectEventQueryInput = DeviceEventQueryInput.extend({ classFilter: string().optional() });
16251
+ var RecentTracksQueryInput = object({
16252
+ /** Devices to merge. An empty array yields `{ tracks: [], nextCursor: null }`. */
16253
+ deviceIds: array(number()),
16254
+ /** Window lower bound on `lastSeen` (inclusive). */
16255
+ since: number().optional(),
16256
+ /** Window upper bound on `lastSeen` (inclusive). */
16257
+ until: number().optional(),
16258
+ /** Page size. Default 200, max 1000. */
16259
+ limit: number().int().min(1).max(1e3).default(200),
16260
+ /** Opaque continuation cursor from a previous page's `nextCursor`.
16261
+ * Encodes the (lastSeen, trackId) sort position — treat as opaque. */
16262
+ cursor: string().optional(),
16263
+ /** See {@link TrackProjectionSchema}. Default `full`. */
16264
+ projection: TrackProjectionSchema.optional()
16265
+ });
16266
+ var RecentTracksPageSchema = object({
16267
+ /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
16268
+ tracks: array(TrackSchema).readonly(),
16269
+ /** Cursor for the next page, or null when this page is the last. */
16270
+ nextCursor: string().nullable()
16271
+ });
16127
16272
  var KeyEventQueryInput = object({
16128
16273
  deviceId: number(),
16129
16274
  /** Window lower bound (track firstSeen ≥ since). */
@@ -16206,11 +16351,25 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16206
16351
  deviceId: number(),
16207
16352
  since: number().optional(),
16208
16353
  until: number().optional(),
16209
- limit: number().optional()
16210
- }), array(TrackSchema).readonly()), method(object({ deviceId: number() }), _void(), {
16211
- kind: "mutation",
16212
- auth: "admin"
16213
- }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16354
+ limit: number().optional(),
16355
+ /** Spatial filter only tracks whose trajectory intersects the zone
16356
+ * (normalized 0..1 rect or polygon). SQL-prefiltered on the persisted
16357
+ * envelope columns, then precisely tested per position. Tracks with
16358
+ * an unknown envelope (no frame dims at persist time) always match. */
16359
+ zone: TrackZoneFilterSchema.optional(),
16360
+ /** See {@link TrackProjectionSchema}. Default `full` (backward
16361
+ * compatible — omitting the field keeps today's exact behaviour). */
16362
+ projection: TrackProjectionSchema.optional()
16363
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(object({ deviceId: number() }), _void(), {
16364
+ kind: "mutation",
16365
+ auth: "admin"
16366
+ }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({
16367
+ deviceId: number(),
16368
+ since: number().optional(),
16369
+ until: number().optional(),
16370
+ kinds: array(string()).optional(),
16371
+ limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
16372
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
16214
16373
  deviceId: number(),
16215
16374
  since: number(),
16216
16375
  until: number(),
@@ -19411,7 +19570,12 @@ var RecordingStorageUsageSchema = object({
19411
19570
  /**
19412
19571
  * Result of locating footage at a wall-clock instant for one device/profile.
19413
19572
  * `segment` carries the covering segment's window; `gap` reports the forward
19414
- * nearest covered edge (`null` past the end of footage / when none exists).
19573
+ * nearest covered edge (`null` past the end of footage / when none exists)
19574
+ * and the backward covered edge `prevEndMs` (exclusive end of the nearest
19575
+ * footage behind the epoch; `null` when none — optional so older providers
19576
+ * that omit it stay valid). `prevEndMs` lets a backward frame-step hop the
19577
+ * small inter-segment cracks (durMs under-covers the span to the next
19578
+ * startMs by ~11-17 ms) instead of no-opping at a segment head.
19415
19579
  */
19416
19580
  var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19417
19581
  kind: literal("segment"),
@@ -19420,7 +19584,8 @@ var LocateSegmentResultSchema = discriminatedUnion("kind", [object({
19420
19584
  bytes: number()
19421
19585
  }), object({
19422
19586
  kind: literal("gap"),
19423
- nearestEdgeMs: number().nullable()
19587
+ nearestEdgeMs: number().nullable(),
19588
+ prevEndMs: number().nullable().optional()
19424
19589
  })]);
19425
19590
  /** Raw bytes of one finalized footage segment (read off disk on the recording node). */
19426
19591
  var ReadSegmentBytesResultSchema = object({ data: _instanceof(Uint8Array) });
@@ -20989,6 +21154,12 @@ Object.freeze({
20989
21154
  addonId: null,
20990
21155
  access: "view"
20991
21156
  },
21157
+ "deviceManager.getLinkedDevices": {
21158
+ capName: "device-manager",
21159
+ capScope: "system",
21160
+ addonId: null,
21161
+ access: "view"
21162
+ },
20992
21163
  "deviceManager.getRoleDisplayDefaults": {
20993
21164
  capName: "device-manager",
20994
21165
  capScope: "system",
@@ -22543,6 +22714,12 @@ Object.freeze({
22543
22714
  addonId: null,
22544
22715
  access: "view"
22545
22716
  },
22717
+ "pipelineAnalytics.getSensorEvents": {
22718
+ capName: "pipeline-analytics",
22719
+ capScope: "device",
22720
+ addonId: null,
22721
+ access: "view"
22722
+ },
22546
22723
  "pipelineAnalytics.getTrack": {
22547
22724
  capName: "pipeline-analytics",
22548
22725
  capScope: "device",
@@ -22555,6 +22732,18 @@ Object.freeze({
22555
22732
  addonId: null,
22556
22733
  access: "view"
22557
22734
  },
22735
+ "pipelineAnalytics.listEventKinds": {
22736
+ capName: "pipeline-analytics",
22737
+ capScope: "device",
22738
+ addonId: null,
22739
+ access: "view"
22740
+ },
22741
+ "pipelineAnalytics.listRecentTracks": {
22742
+ capName: "pipeline-analytics",
22743
+ capScope: "device",
22744
+ addonId: null,
22745
+ access: "view"
22746
+ },
22558
22747
  "pipelineAnalytics.listTracks": {
22559
22748
  capName: "pipeline-analytics",
22560
22749
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-alexa",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
5
5
  "keywords": [
6
6
  "camstack",