@camstack/addon-export-alexa 1.1.24 → 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.
@@ -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-H4AVePnn.mjs
29
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
30
30
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
31
31
  EventCategory["SystemBoot"] = "system.boot";
32
32
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -179,6 +179,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
179
179
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
180
180
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
181
181
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
182
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
183
+ * progress bar the client reconciles via `recordingExport.getExport`. */
184
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
185
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
186
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
182
187
  EventCategory["DetectionEvent"] = "detection.event";
183
188
  EventCategory["SessionTrackNew"] = "session.track.new";
184
189
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -468,6 +473,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
468
473
  */
469
474
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
470
475
  /**
476
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
477
+ * a package zone — a newly-appeared stationary object of a package class
478
+ * that cleared the class / zone / dwell / size gates. Payload:
479
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
480
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
481
+ * Telemetry (D8): the durable record is the `package-events` store row;
482
+ * this bus topic drives notifier rules + live UI. See
483
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
484
+ */
485
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
486
+ /**
487
+ * Fired by `addon-post-analysis` when a previously-delivered package
488
+ * leaves its zone (the stationary entry departed — moved or swept).
489
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
490
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
491
+ * Telemetry (D8). See package-zones-design §5.2.
492
+ */
493
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
494
+ /**
471
495
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
472
496
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
473
497
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5206,6 +5230,25 @@ function _instanceof(cls, params = {}) {
5206
5230
  };
5207
5231
  return inst;
5208
5232
  }
5233
+ //#endregion
5234
+ //#region ../../node_modules/zod/v4/classic/compat.js
5235
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5236
+ var ZodIssueCode = {
5237
+ invalid_type: "invalid_type",
5238
+ too_big: "too_big",
5239
+ too_small: "too_small",
5240
+ invalid_format: "invalid_format",
5241
+ not_multiple_of: "not_multiple_of",
5242
+ unrecognized_keys: "unrecognized_keys",
5243
+ invalid_union: "invalid_union",
5244
+ invalid_key: "invalid_key",
5245
+ invalid_element: "invalid_element",
5246
+ invalid_value: "invalid_value",
5247
+ custom: "custom"
5248
+ };
5249
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5250
+ var ZodFirstPartyTypeKind;
5251
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5209
5252
  Object.fromEntries([
5210
5253
  {
5211
5254
  id: "overview",
@@ -7452,6 +7495,62 @@ var RecordingConfigSchema = object({
7452
7495
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7453
7496
  });
7454
7497
  /**
7498
+ * Ops-log — the durable, append-only operations audit shared by the
7499
+ * recordings and events management surfaces.
7500
+ *
7501
+ * ONE row shape is reused for both domains so a single "Activity" view can
7502
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7503
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7504
+ * management operation, WHY it ran (reason), and its measurable effect
7505
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7506
+ * never fail the operation it records.
7507
+ */
7508
+ /** Which management domain the operation belongs to. */
7509
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7510
+ /** The kind of management operation performed. */
7511
+ var OpsLogOpSchema = _enum([
7512
+ "prune",
7513
+ "manual-delete",
7514
+ "rescan",
7515
+ "retention-run"
7516
+ ]);
7517
+ /** Why the operation ran. */
7518
+ var OpsLogReasonSchema = _enum([
7519
+ "retention",
7520
+ "quota",
7521
+ "manual",
7522
+ "operator"
7523
+ ]);
7524
+ /** One audit row, shared verbatim by both domains. */
7525
+ var OpsLogEntrySchema = object({
7526
+ /** Unique row id. */
7527
+ id: string(),
7528
+ /** Epoch ms the operation completed. */
7529
+ at: number(),
7530
+ domain: OpsLogDomainSchema,
7531
+ op: OpsLogOpSchema,
7532
+ reason: OpsLogReasonSchema,
7533
+ /** The camera the op targeted; null for a cluster/global op. */
7534
+ deviceId: number().nullable(),
7535
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7536
+ nodeId: string(),
7537
+ /** Buckets / rows deleted (op-specific unit). */
7538
+ itemsAffected: number(),
7539
+ /** Bytes reclaimed by the op (0 when not measurable). */
7540
+ bytesReclaimed: number(),
7541
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7542
+ detail: string().nullable(),
7543
+ /** Who/what triggered the op. */
7544
+ actor: string()
7545
+ });
7546
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7547
+ var OpsLogQueryInputSchema = object({
7548
+ /** Restrict to a single camera; omit for every row. */
7549
+ deviceId: number().optional(),
7550
+ /** Max rows returned, newest-first. */
7551
+ limit: number().int().min(1).max(1e3).optional()
7552
+ });
7553
+ /**
7455
7554
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7456
7555
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7457
7556
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12755,7 +12854,11 @@ array(ZoneRuleSchema).readonly();
12755
12854
  * Extend the enum here when a new gating consumer comes online (audio
12756
12855
  * gating, alert filtering, …) — no other surface needs to change.
12757
12856
  */
12758
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12857
+ var ZoneRuleStageEnum = _enum([
12858
+ "motion",
12859
+ "detection",
12860
+ "package"
12861
+ ]);
12759
12862
  DeviceType.Camera, method(object({
12760
12863
  deviceId: number(),
12761
12864
  stage: ZoneRuleStageEnum
@@ -12768,7 +12871,8 @@ DeviceType.Camera, method(object({
12768
12871
  auth: "admin"
12769
12872
  }), object({
12770
12873
  motion: array(ZoneRuleSchema).readonly(),
12771
- detection: array(ZoneRuleSchema).readonly()
12874
+ detection: array(ZoneRuleSchema).readonly(),
12875
+ package: array(ZoneRuleSchema).readonly()
12772
12876
  });
12773
12877
  var ProviderStatusSchema = object({
12774
12878
  connected: boolean(),
@@ -16022,6 +16126,7 @@ var EventKindIconSchema = _enum([
16022
16126
  "smoke",
16023
16127
  "water",
16024
16128
  "button",
16129
+ "package",
16025
16130
  "generic"
16026
16131
  ]);
16027
16132
  var EventKindCategorySchema = _enum([
@@ -16029,7 +16134,8 @@ var EventKindCategorySchema = _enum([
16029
16134
  "audio",
16030
16135
  "detection",
16031
16136
  "sensor",
16032
- "custom"
16137
+ "custom",
16138
+ "package"
16033
16139
  ]);
16034
16140
  var EventKindDescriptorSchema = object({
16035
16141
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16370,6 +16476,26 @@ var TrackCascadeCountsSchema = object({
16370
16476
  /** Per-track CLIP search vectors removed (best-effort). */
16371
16477
  embeddings: number().int()
16372
16478
  });
16479
+ /** Event-store footprint for one camera. */
16480
+ var EventStoreDeviceFootprintSchema = object({
16481
+ deviceId: number(),
16482
+ /** Persisted event rows (motion + object + audio) for the camera. */
16483
+ rows: number().int(),
16484
+ /** Event-owned media bytes on disk for the camera. */
16485
+ bytes: number().int()
16486
+ });
16487
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16488
+ var EventStoreFootprintSchema = object({
16489
+ totalRows: number().int(),
16490
+ totalBytes: number().int(),
16491
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16492
+ });
16493
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16494
+ var EventPruneCountsSchema = object({
16495
+ motion: number().int(),
16496
+ object: number().int(),
16497
+ audio: number().int()
16498
+ });
16373
16499
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16374
16500
  deviceId: number(),
16375
16501
  trackId: string()
@@ -16433,6 +16559,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16433
16559
  }), {
16434
16560
  kind: "mutation",
16435
16561
  auth: "admin"
16562
+ }), method(object({}), EventStoreFootprintSchema, {
16563
+ kind: "query",
16564
+ auth: "admin"
16565
+ }), method(object({
16566
+ olderThanMs: number(),
16567
+ reason: OpsLogReasonSchema.optional()
16568
+ }), EventPruneCountsSchema, {
16569
+ kind: "mutation",
16570
+ auth: "admin"
16571
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16572
+ kind: "mutation",
16573
+ auth: "admin"
16574
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16575
+ kind: "query",
16576
+ auth: "admin"
16436
16577
  }), method(object({
16437
16578
  eventId: string(),
16438
16579
  kind: MediaFileKindEnum.optional()
@@ -19666,13 +19807,131 @@ method(object({
19666
19807
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19667
19808
  kind: "mutation",
19668
19809
  auth: "admin"
19669
- }), method(object({ deviceId: number() }), object({
19810
+ }), method(object({
19811
+ deviceId: number(),
19812
+ reason: OpsLogReasonSchema.optional()
19813
+ }), object({
19670
19814
  floorMs: number().nullable(),
19671
19815
  deletedBuckets: number().int(),
19672
19816
  reclaimedBytes: number().int()
19673
19817
  }), {
19674
19818
  kind: "mutation",
19675
19819
  auth: "admin"
19820
+ }), method(object({
19821
+ deviceId: number(),
19822
+ fromMs: number().optional(),
19823
+ toMs: number().optional()
19824
+ }), object({
19825
+ deletedBuckets: number().int(),
19826
+ reclaimedBytes: number().int()
19827
+ }), {
19828
+ kind: "mutation",
19829
+ auth: "admin"
19830
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19831
+ kind: "query",
19832
+ auth: "admin"
19833
+ });
19834
+ /**
19835
+ * `recordingExport` cap — render a footage time range into a single downloadable
19836
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19837
+ * bounded lifetime with a durable history, auto-expiry, and optional
19838
+ * delete-after-download.
19839
+ *
19840
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19841
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19842
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19843
+ * input and dispatch to that single provider; the render runs on the node that
19844
+ * owns the footage (no cross-node segment transfer). Download rides the
19845
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19846
+ * SQLite); history rows survive file deletion for audit.
19847
+ */
19848
+ /** Playback-speed multiplier for the render (1 = realtime). */
19849
+ var ExportSpeedSchema = number().min(.25).max(32);
19850
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19851
+ var ExportTimelapseSchema = object({
19852
+ everyMs: number().int().positive(),
19853
+ outputFps: number().int().min(1).max(60).optional()
19854
+ });
19855
+ /**
19856
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19857
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19858
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19859
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19860
+ */
19861
+ var ExportOptionsSchema = object({
19862
+ speed: ExportSpeedSchema.optional(),
19863
+ timelapse: ExportTimelapseSchema.optional(),
19864
+ includeAudio: boolean(),
19865
+ maxLifeMs: number().int().positive(),
19866
+ deleteAfterDownload: boolean(),
19867
+ title: string().max(200).optional()
19868
+ }).superRefine((v, ctx) => {
19869
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19870
+ code: ZodIssueCode.custom,
19871
+ message: "speed and timelapse are mutually exclusive",
19872
+ path: ["timelapse"]
19873
+ });
19874
+ });
19875
+ var ExportStateSchema = _enum([
19876
+ "queued",
19877
+ "rendering",
19878
+ "ready",
19879
+ "failed",
19880
+ "expired",
19881
+ "deleted"
19882
+ ]);
19883
+ /** One export job / history row. */
19884
+ var ExportRecordSchema = object({
19885
+ id: string(),
19886
+ deviceId: number(),
19887
+ profile: string(),
19888
+ fromMs: number(),
19889
+ toMs: number(),
19890
+ options: ExportOptionsSchema,
19891
+ state: ExportStateSchema,
19892
+ /** 0–100 while rendering; null otherwise. */
19893
+ progressPct: number().nullable(),
19894
+ /** File size once ready; null before. */
19895
+ fileBytes: number().nullable(),
19896
+ expiresAt: number(),
19897
+ deleteAfterDownload: boolean(),
19898
+ /** Epoch of the first complete download; null until then. */
19899
+ downloadedAt: number().nullable(),
19900
+ createdAt: number(),
19901
+ /** User id/name that requested the export. */
19902
+ createdBy: string(),
19903
+ /** Failure reason when state is 'failed'; null otherwise. */
19904
+ error: string().nullable()
19905
+ });
19906
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19907
+ var ExportDownloadSchema = object({
19908
+ url: string(),
19909
+ endpoints: array(string())
19910
+ });
19911
+ method(object({
19912
+ deviceId: number(),
19913
+ profile: string(),
19914
+ fromMs: number(),
19915
+ toMs: number(),
19916
+ options: ExportOptionsSchema
19917
+ }), ExportRecordSchema, {
19918
+ kind: "mutation",
19919
+ auth: "protected"
19920
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19921
+ kind: "query",
19922
+ auth: "protected"
19923
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19924
+ kind: "query",
19925
+ auth: "protected"
19926
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19927
+ kind: "mutation",
19928
+ auth: "protected"
19929
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19930
+ kind: "mutation",
19931
+ auth: "protected"
19932
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19933
+ kind: "query",
19934
+ auth: "protected"
19676
19935
  });
19677
19936
  /**
19678
19937
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22692,6 +22951,12 @@ Object.freeze({
22692
22951
  addonId: null,
22693
22952
  access: "delete"
22694
22953
  },
22954
+ "pipelineAnalytics.deleteDeviceEvents": {
22955
+ capName: "pipeline-analytics",
22956
+ capScope: "device",
22957
+ addonId: null,
22958
+ access: "delete"
22959
+ },
22695
22960
  "pipelineAnalytics.deleteTracks": {
22696
22961
  capName: "pipeline-analytics",
22697
22962
  capScope: "device",
@@ -22722,6 +22987,12 @@ Object.freeze({
22722
22987
  addonId: null,
22723
22988
  access: "view"
22724
22989
  },
22990
+ "pipelineAnalytics.getEventStoreFootprint": {
22991
+ capName: "pipeline-analytics",
22992
+ capScope: "device",
22993
+ addonId: null,
22994
+ access: "view"
22995
+ },
22725
22996
  "pipelineAnalytics.getKeyEvents": {
22726
22997
  capName: "pipeline-analytics",
22727
22998
  capScope: "device",
@@ -22764,6 +23035,12 @@ Object.freeze({
22764
23035
  addonId: null,
22765
23036
  access: "view"
22766
23037
  },
23038
+ "pipelineAnalytics.listOpsLog": {
23039
+ capName: "pipeline-analytics",
23040
+ capScope: "device",
23041
+ addonId: null,
23042
+ access: "view"
23043
+ },
22767
23044
  "pipelineAnalytics.listRecentTracks": {
22768
23045
  capName: "pipeline-analytics",
22769
23046
  capScope: "device",
@@ -22776,6 +23053,12 @@ Object.freeze({
22776
23053
  addonId: null,
22777
23054
  access: "view"
22778
23055
  },
23056
+ "pipelineAnalytics.pruneEvents": {
23057
+ capName: "pipeline-analytics",
23058
+ capScope: "device",
23059
+ addonId: null,
23060
+ access: "create"
23061
+ },
22779
23062
  "pipelineAnalytics.pruneEventsBefore": {
22780
23063
  capName: "pipeline-analytics",
22781
23064
  capScope: "device",
@@ -23538,6 +23821,12 @@ Object.freeze({
23538
23821
  addonId: null,
23539
23822
  access: "create"
23540
23823
  },
23824
+ "recording.deleteFootprint": {
23825
+ capName: "recording",
23826
+ capScope: "system",
23827
+ addonId: null,
23828
+ access: "delete"
23829
+ },
23541
23830
  "recording.getAvailability": {
23542
23831
  capName: "recording",
23543
23832
  capScope: "system",
@@ -23568,6 +23857,12 @@ Object.freeze({
23568
23857
  addonId: null,
23569
23858
  access: "view"
23570
23859
  },
23860
+ "recording.listOpsLog": {
23861
+ capName: "recording",
23862
+ capScope: "system",
23863
+ addonId: null,
23864
+ access: "view"
23865
+ },
23571
23866
  "recording.locateSegment": {
23572
23867
  capName: "recording",
23573
23868
  capScope: "system",
@@ -23598,6 +23893,42 @@ Object.freeze({
23598
23893
  addonId: null,
23599
23894
  access: "create"
23600
23895
  },
23896
+ "recordingExport.cancelExport": {
23897
+ capName: "recordingExport",
23898
+ capScope: "system",
23899
+ addonId: null,
23900
+ access: "create"
23901
+ },
23902
+ "recordingExport.createExport": {
23903
+ capName: "recordingExport",
23904
+ capScope: "system",
23905
+ addonId: null,
23906
+ access: "create"
23907
+ },
23908
+ "recordingExport.deleteExport": {
23909
+ capName: "recordingExport",
23910
+ capScope: "system",
23911
+ addonId: null,
23912
+ access: "delete"
23913
+ },
23914
+ "recordingExport.getDownloadUrl": {
23915
+ capName: "recordingExport",
23916
+ capScope: "system",
23917
+ addonId: null,
23918
+ access: "view"
23919
+ },
23920
+ "recordingExport.getExport": {
23921
+ capName: "recordingExport",
23922
+ capScope: "system",
23923
+ addonId: null,
23924
+ access: "view"
23925
+ },
23926
+ "recordingExport.listExports": {
23927
+ capName: "recordingExport",
23928
+ capScope: "system",
23929
+ addonId: null,
23930
+ access: "view"
23931
+ },
23601
23932
  "sceneMonitor.captureReference": {
23602
23933
  capName: "scene-monitor",
23603
23934
  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-H4AVePnn.mjs
3
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -153,6 +153,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
153
153
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
154
154
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
155
155
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
156
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
157
+ * progress bar the client reconciles via `recordingExport.getExport`. */
158
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
159
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
160
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
156
161
  EventCategory["DetectionEvent"] = "detection.event";
157
162
  EventCategory["SessionTrackNew"] = "session.track.new";
158
163
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -442,6 +447,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
442
447
  */
443
448
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
444
449
  /**
450
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
451
+ * a package zone — a newly-appeared stationary object of a package class
452
+ * that cleared the class / zone / dwell / size gates. Payload:
453
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
454
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
455
+ * Telemetry (D8): the durable record is the `package-events` store row;
456
+ * this bus topic drives notifier rules + live UI. See
457
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
458
+ */
459
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
460
+ /**
461
+ * Fired by `addon-post-analysis` when a previously-delivered package
462
+ * leaves its zone (the stationary entry departed — moved or swept).
463
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
464
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
465
+ * Telemetry (D8). See package-zones-design §5.2.
466
+ */
467
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
468
+ /**
445
469
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
446
470
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
447
471
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5180,6 +5204,25 @@ function _instanceof(cls, params = {}) {
5180
5204
  };
5181
5205
  return inst;
5182
5206
  }
5207
+ //#endregion
5208
+ //#region ../../node_modules/zod/v4/classic/compat.js
5209
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5210
+ var ZodIssueCode = {
5211
+ invalid_type: "invalid_type",
5212
+ too_big: "too_big",
5213
+ too_small: "too_small",
5214
+ invalid_format: "invalid_format",
5215
+ not_multiple_of: "not_multiple_of",
5216
+ unrecognized_keys: "unrecognized_keys",
5217
+ invalid_union: "invalid_union",
5218
+ invalid_key: "invalid_key",
5219
+ invalid_element: "invalid_element",
5220
+ invalid_value: "invalid_value",
5221
+ custom: "custom"
5222
+ };
5223
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5224
+ var ZodFirstPartyTypeKind;
5225
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5183
5226
  Object.fromEntries([
5184
5227
  {
5185
5228
  id: "overview",
@@ -7426,6 +7469,62 @@ var RecordingConfigSchema = object({
7426
7469
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7427
7470
  });
7428
7471
  /**
7472
+ * Ops-log — the durable, append-only operations audit shared by the
7473
+ * recordings and events management surfaces.
7474
+ *
7475
+ * ONE row shape is reused for both domains so a single "Activity" view can
7476
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7477
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7478
+ * management operation, WHY it ran (reason), and its measurable effect
7479
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7480
+ * never fail the operation it records.
7481
+ */
7482
+ /** Which management domain the operation belongs to. */
7483
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7484
+ /** The kind of management operation performed. */
7485
+ var OpsLogOpSchema = _enum([
7486
+ "prune",
7487
+ "manual-delete",
7488
+ "rescan",
7489
+ "retention-run"
7490
+ ]);
7491
+ /** Why the operation ran. */
7492
+ var OpsLogReasonSchema = _enum([
7493
+ "retention",
7494
+ "quota",
7495
+ "manual",
7496
+ "operator"
7497
+ ]);
7498
+ /** One audit row, shared verbatim by both domains. */
7499
+ var OpsLogEntrySchema = object({
7500
+ /** Unique row id. */
7501
+ id: string(),
7502
+ /** Epoch ms the operation completed. */
7503
+ at: number(),
7504
+ domain: OpsLogDomainSchema,
7505
+ op: OpsLogOpSchema,
7506
+ reason: OpsLogReasonSchema,
7507
+ /** The camera the op targeted; null for a cluster/global op. */
7508
+ deviceId: number().nullable(),
7509
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7510
+ nodeId: string(),
7511
+ /** Buckets / rows deleted (op-specific unit). */
7512
+ itemsAffected: number(),
7513
+ /** Bytes reclaimed by the op (0 when not measurable). */
7514
+ bytesReclaimed: number(),
7515
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7516
+ detail: string().nullable(),
7517
+ /** Who/what triggered the op. */
7518
+ actor: string()
7519
+ });
7520
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7521
+ var OpsLogQueryInputSchema = object({
7522
+ /** Restrict to a single camera; omit for every row. */
7523
+ deviceId: number().optional(),
7524
+ /** Max rows returned, newest-first. */
7525
+ limit: number().int().min(1).max(1e3).optional()
7526
+ });
7527
+ /**
7429
7528
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7430
7529
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7431
7530
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12729,7 +12828,11 @@ array(ZoneRuleSchema).readonly();
12729
12828
  * Extend the enum here when a new gating consumer comes online (audio
12730
12829
  * gating, alert filtering, …) — no other surface needs to change.
12731
12830
  */
12732
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12831
+ var ZoneRuleStageEnum = _enum([
12832
+ "motion",
12833
+ "detection",
12834
+ "package"
12835
+ ]);
12733
12836
  DeviceType.Camera, method(object({
12734
12837
  deviceId: number(),
12735
12838
  stage: ZoneRuleStageEnum
@@ -12742,7 +12845,8 @@ DeviceType.Camera, method(object({
12742
12845
  auth: "admin"
12743
12846
  }), object({
12744
12847
  motion: array(ZoneRuleSchema).readonly(),
12745
- detection: array(ZoneRuleSchema).readonly()
12848
+ detection: array(ZoneRuleSchema).readonly(),
12849
+ package: array(ZoneRuleSchema).readonly()
12746
12850
  });
12747
12851
  var ProviderStatusSchema = object({
12748
12852
  connected: boolean(),
@@ -15996,6 +16100,7 @@ var EventKindIconSchema = _enum([
15996
16100
  "smoke",
15997
16101
  "water",
15998
16102
  "button",
16103
+ "package",
15999
16104
  "generic"
16000
16105
  ]);
16001
16106
  var EventKindCategorySchema = _enum([
@@ -16003,7 +16108,8 @@ var EventKindCategorySchema = _enum([
16003
16108
  "audio",
16004
16109
  "detection",
16005
16110
  "sensor",
16006
- "custom"
16111
+ "custom",
16112
+ "package"
16007
16113
  ]);
16008
16114
  var EventKindDescriptorSchema = object({
16009
16115
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16344,6 +16450,26 @@ var TrackCascadeCountsSchema = object({
16344
16450
  /** Per-track CLIP search vectors removed (best-effort). */
16345
16451
  embeddings: number().int()
16346
16452
  });
16453
+ /** Event-store footprint for one camera. */
16454
+ var EventStoreDeviceFootprintSchema = object({
16455
+ deviceId: number(),
16456
+ /** Persisted event rows (motion + object + audio) for the camera. */
16457
+ rows: number().int(),
16458
+ /** Event-owned media bytes on disk for the camera. */
16459
+ bytes: number().int()
16460
+ });
16461
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16462
+ var EventStoreFootprintSchema = object({
16463
+ totalRows: number().int(),
16464
+ totalBytes: number().int(),
16465
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16466
+ });
16467
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16468
+ var EventPruneCountsSchema = object({
16469
+ motion: number().int(),
16470
+ object: number().int(),
16471
+ audio: number().int()
16472
+ });
16347
16473
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16348
16474
  deviceId: number(),
16349
16475
  trackId: string()
@@ -16407,6 +16533,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16407
16533
  }), {
16408
16534
  kind: "mutation",
16409
16535
  auth: "admin"
16536
+ }), method(object({}), EventStoreFootprintSchema, {
16537
+ kind: "query",
16538
+ auth: "admin"
16539
+ }), method(object({
16540
+ olderThanMs: number(),
16541
+ reason: OpsLogReasonSchema.optional()
16542
+ }), EventPruneCountsSchema, {
16543
+ kind: "mutation",
16544
+ auth: "admin"
16545
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16546
+ kind: "mutation",
16547
+ auth: "admin"
16548
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16549
+ kind: "query",
16550
+ auth: "admin"
16410
16551
  }), method(object({
16411
16552
  eventId: string(),
16412
16553
  kind: MediaFileKindEnum.optional()
@@ -19640,13 +19781,131 @@ method(object({
19640
19781
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19641
19782
  kind: "mutation",
19642
19783
  auth: "admin"
19643
- }), method(object({ deviceId: number() }), object({
19784
+ }), method(object({
19785
+ deviceId: number(),
19786
+ reason: OpsLogReasonSchema.optional()
19787
+ }), object({
19644
19788
  floorMs: number().nullable(),
19645
19789
  deletedBuckets: number().int(),
19646
19790
  reclaimedBytes: number().int()
19647
19791
  }), {
19648
19792
  kind: "mutation",
19649
19793
  auth: "admin"
19794
+ }), method(object({
19795
+ deviceId: number(),
19796
+ fromMs: number().optional(),
19797
+ toMs: number().optional()
19798
+ }), object({
19799
+ deletedBuckets: number().int(),
19800
+ reclaimedBytes: number().int()
19801
+ }), {
19802
+ kind: "mutation",
19803
+ auth: "admin"
19804
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19805
+ kind: "query",
19806
+ auth: "admin"
19807
+ });
19808
+ /**
19809
+ * `recordingExport` cap — render a footage time range into a single downloadable
19810
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19811
+ * bounded lifetime with a durable history, auto-expiry, and optional
19812
+ * delete-after-download.
19813
+ *
19814
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19815
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19816
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19817
+ * input and dispatch to that single provider; the render runs on the node that
19818
+ * owns the footage (no cross-node segment transfer). Download rides the
19819
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19820
+ * SQLite); history rows survive file deletion for audit.
19821
+ */
19822
+ /** Playback-speed multiplier for the render (1 = realtime). */
19823
+ var ExportSpeedSchema = number().min(.25).max(32);
19824
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19825
+ var ExportTimelapseSchema = object({
19826
+ everyMs: number().int().positive(),
19827
+ outputFps: number().int().min(1).max(60).optional()
19828
+ });
19829
+ /**
19830
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19831
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19832
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19833
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19834
+ */
19835
+ var ExportOptionsSchema = object({
19836
+ speed: ExportSpeedSchema.optional(),
19837
+ timelapse: ExportTimelapseSchema.optional(),
19838
+ includeAudio: boolean(),
19839
+ maxLifeMs: number().int().positive(),
19840
+ deleteAfterDownload: boolean(),
19841
+ title: string().max(200).optional()
19842
+ }).superRefine((v, ctx) => {
19843
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19844
+ code: ZodIssueCode.custom,
19845
+ message: "speed and timelapse are mutually exclusive",
19846
+ path: ["timelapse"]
19847
+ });
19848
+ });
19849
+ var ExportStateSchema = _enum([
19850
+ "queued",
19851
+ "rendering",
19852
+ "ready",
19853
+ "failed",
19854
+ "expired",
19855
+ "deleted"
19856
+ ]);
19857
+ /** One export job / history row. */
19858
+ var ExportRecordSchema = object({
19859
+ id: string(),
19860
+ deviceId: number(),
19861
+ profile: string(),
19862
+ fromMs: number(),
19863
+ toMs: number(),
19864
+ options: ExportOptionsSchema,
19865
+ state: ExportStateSchema,
19866
+ /** 0–100 while rendering; null otherwise. */
19867
+ progressPct: number().nullable(),
19868
+ /** File size once ready; null before. */
19869
+ fileBytes: number().nullable(),
19870
+ expiresAt: number(),
19871
+ deleteAfterDownload: boolean(),
19872
+ /** Epoch of the first complete download; null until then. */
19873
+ downloadedAt: number().nullable(),
19874
+ createdAt: number(),
19875
+ /** User id/name that requested the export. */
19876
+ createdBy: string(),
19877
+ /** Failure reason when state is 'failed'; null otherwise. */
19878
+ error: string().nullable()
19879
+ });
19880
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19881
+ var ExportDownloadSchema = object({
19882
+ url: string(),
19883
+ endpoints: array(string())
19884
+ });
19885
+ method(object({
19886
+ deviceId: number(),
19887
+ profile: string(),
19888
+ fromMs: number(),
19889
+ toMs: number(),
19890
+ options: ExportOptionsSchema
19891
+ }), ExportRecordSchema, {
19892
+ kind: "mutation",
19893
+ auth: "protected"
19894
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19895
+ kind: "query",
19896
+ auth: "protected"
19897
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19898
+ kind: "query",
19899
+ auth: "protected"
19900
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19901
+ kind: "mutation",
19902
+ auth: "protected"
19903
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19904
+ kind: "mutation",
19905
+ auth: "protected"
19906
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19907
+ kind: "query",
19908
+ auth: "protected"
19650
19909
  });
19651
19910
  /**
19652
19911
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22666,6 +22925,12 @@ Object.freeze({
22666
22925
  addonId: null,
22667
22926
  access: "delete"
22668
22927
  },
22928
+ "pipelineAnalytics.deleteDeviceEvents": {
22929
+ capName: "pipeline-analytics",
22930
+ capScope: "device",
22931
+ addonId: null,
22932
+ access: "delete"
22933
+ },
22669
22934
  "pipelineAnalytics.deleteTracks": {
22670
22935
  capName: "pipeline-analytics",
22671
22936
  capScope: "device",
@@ -22696,6 +22961,12 @@ Object.freeze({
22696
22961
  addonId: null,
22697
22962
  access: "view"
22698
22963
  },
22964
+ "pipelineAnalytics.getEventStoreFootprint": {
22965
+ capName: "pipeline-analytics",
22966
+ capScope: "device",
22967
+ addonId: null,
22968
+ access: "view"
22969
+ },
22699
22970
  "pipelineAnalytics.getKeyEvents": {
22700
22971
  capName: "pipeline-analytics",
22701
22972
  capScope: "device",
@@ -22738,6 +23009,12 @@ Object.freeze({
22738
23009
  addonId: null,
22739
23010
  access: "view"
22740
23011
  },
23012
+ "pipelineAnalytics.listOpsLog": {
23013
+ capName: "pipeline-analytics",
23014
+ capScope: "device",
23015
+ addonId: null,
23016
+ access: "view"
23017
+ },
22741
23018
  "pipelineAnalytics.listRecentTracks": {
22742
23019
  capName: "pipeline-analytics",
22743
23020
  capScope: "device",
@@ -22750,6 +23027,12 @@ Object.freeze({
22750
23027
  addonId: null,
22751
23028
  access: "view"
22752
23029
  },
23030
+ "pipelineAnalytics.pruneEvents": {
23031
+ capName: "pipeline-analytics",
23032
+ capScope: "device",
23033
+ addonId: null,
23034
+ access: "create"
23035
+ },
22753
23036
  "pipelineAnalytics.pruneEventsBefore": {
22754
23037
  capName: "pipeline-analytics",
22755
23038
  capScope: "device",
@@ -23512,6 +23795,12 @@ Object.freeze({
23512
23795
  addonId: null,
23513
23796
  access: "create"
23514
23797
  },
23798
+ "recording.deleteFootprint": {
23799
+ capName: "recording",
23800
+ capScope: "system",
23801
+ addonId: null,
23802
+ access: "delete"
23803
+ },
23515
23804
  "recording.getAvailability": {
23516
23805
  capName: "recording",
23517
23806
  capScope: "system",
@@ -23542,6 +23831,12 @@ Object.freeze({
23542
23831
  addonId: null,
23543
23832
  access: "view"
23544
23833
  },
23834
+ "recording.listOpsLog": {
23835
+ capName: "recording",
23836
+ capScope: "system",
23837
+ addonId: null,
23838
+ access: "view"
23839
+ },
23545
23840
  "recording.locateSegment": {
23546
23841
  capName: "recording",
23547
23842
  capScope: "system",
@@ -23572,6 +23867,42 @@ Object.freeze({
23572
23867
  addonId: null,
23573
23868
  access: "create"
23574
23869
  },
23870
+ "recordingExport.cancelExport": {
23871
+ capName: "recordingExport",
23872
+ capScope: "system",
23873
+ addonId: null,
23874
+ access: "create"
23875
+ },
23876
+ "recordingExport.createExport": {
23877
+ capName: "recordingExport",
23878
+ capScope: "system",
23879
+ addonId: null,
23880
+ access: "create"
23881
+ },
23882
+ "recordingExport.deleteExport": {
23883
+ capName: "recordingExport",
23884
+ capScope: "system",
23885
+ addonId: null,
23886
+ access: "delete"
23887
+ },
23888
+ "recordingExport.getDownloadUrl": {
23889
+ capName: "recordingExport",
23890
+ capScope: "system",
23891
+ addonId: null,
23892
+ access: "view"
23893
+ },
23894
+ "recordingExport.getExport": {
23895
+ capName: "recordingExport",
23896
+ capScope: "system",
23897
+ addonId: null,
23898
+ access: "view"
23899
+ },
23900
+ "recordingExport.listExports": {
23901
+ capName: "recordingExport",
23902
+ capScope: "system",
23903
+ addonId: null,
23904
+ access: "view"
23905
+ },
23575
23906
  "sceneMonitor.captureReference": {
23576
23907
  capName: "scene-monitor",
23577
23908
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-export-alexa",
3
- "version": "1.1.24",
3
+ "version": "1.1.26",
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",