@camstack/addon-mqtt-broker 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.
@@ -44,7 +44,7 @@ let crypto$10 = __toESM(crypto$1, 1);
44
44
  crypto$1 = __toESM(crypto$1);
45
45
  let node_fs = require("node:fs");
46
46
  let node_path = require("node:path");
47
- //#region ../types/dist/event-category-H4AVePnn.mjs
47
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
48
48
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
49
49
  EventCategory["SystemBoot"] = "system.boot";
50
50
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -197,6 +197,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
197
197
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
198
198
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
199
199
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
200
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
201
+ * progress bar the client reconciles via `recordingExport.getExport`. */
202
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
203
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
204
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
200
205
  EventCategory["DetectionEvent"] = "detection.event";
201
206
  EventCategory["SessionTrackNew"] = "session.track.new";
202
207
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -486,6 +491,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
486
491
  */
487
492
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
488
493
  /**
494
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
495
+ * a package zone — a newly-appeared stationary object of a package class
496
+ * that cleared the class / zone / dwell / size gates. Payload:
497
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
498
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
499
+ * Telemetry (D8): the durable record is the `package-events` store row;
500
+ * this bus topic drives notifier rules + live UI. See
501
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
502
+ */
503
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
504
+ /**
505
+ * Fired by `addon-post-analysis` when a previously-delivered package
506
+ * leaves its zone (the stationary entry departed — moved or swept).
507
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
508
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
509
+ * Telemetry (D8). See package-zones-design §5.2.
510
+ */
511
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
512
+ /**
489
513
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
490
514
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
491
515
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5224,6 +5248,25 @@ function _instanceof(cls, params = {}) {
5224
5248
  };
5225
5249
  return inst;
5226
5250
  }
5251
+ //#endregion
5252
+ //#region ../../node_modules/zod/v4/classic/compat.js
5253
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5254
+ var ZodIssueCode = {
5255
+ invalid_type: "invalid_type",
5256
+ too_big: "too_big",
5257
+ too_small: "too_small",
5258
+ invalid_format: "invalid_format",
5259
+ not_multiple_of: "not_multiple_of",
5260
+ unrecognized_keys: "unrecognized_keys",
5261
+ invalid_union: "invalid_union",
5262
+ invalid_key: "invalid_key",
5263
+ invalid_element: "invalid_element",
5264
+ invalid_value: "invalid_value",
5265
+ custom: "custom"
5266
+ };
5267
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5268
+ var ZodFirstPartyTypeKind;
5269
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5227
5270
  Object.fromEntries([
5228
5271
  {
5229
5272
  id: "overview",
@@ -7330,6 +7373,62 @@ var RecordingConfigSchema = object({
7330
7373
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7331
7374
  });
7332
7375
  /**
7376
+ * Ops-log — the durable, append-only operations audit shared by the
7377
+ * recordings and events management surfaces.
7378
+ *
7379
+ * ONE row shape is reused for both domains so a single "Activity" view can
7380
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7381
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7382
+ * management operation, WHY it ran (reason), and its measurable effect
7383
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7384
+ * never fail the operation it records.
7385
+ */
7386
+ /** Which management domain the operation belongs to. */
7387
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7388
+ /** The kind of management operation performed. */
7389
+ var OpsLogOpSchema = _enum([
7390
+ "prune",
7391
+ "manual-delete",
7392
+ "rescan",
7393
+ "retention-run"
7394
+ ]);
7395
+ /** Why the operation ran. */
7396
+ var OpsLogReasonSchema = _enum([
7397
+ "retention",
7398
+ "quota",
7399
+ "manual",
7400
+ "operator"
7401
+ ]);
7402
+ /** One audit row, shared verbatim by both domains. */
7403
+ var OpsLogEntrySchema = object({
7404
+ /** Unique row id. */
7405
+ id: string(),
7406
+ /** Epoch ms the operation completed. */
7407
+ at: number(),
7408
+ domain: OpsLogDomainSchema,
7409
+ op: OpsLogOpSchema,
7410
+ reason: OpsLogReasonSchema,
7411
+ /** The camera the op targeted; null for a cluster/global op. */
7412
+ deviceId: number().nullable(),
7413
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7414
+ nodeId: string(),
7415
+ /** Buckets / rows deleted (op-specific unit). */
7416
+ itemsAffected: number(),
7417
+ /** Bytes reclaimed by the op (0 when not measurable). */
7418
+ bytesReclaimed: number(),
7419
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7420
+ detail: string().nullable(),
7421
+ /** Who/what triggered the op. */
7422
+ actor: string()
7423
+ });
7424
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7425
+ var OpsLogQueryInputSchema = object({
7426
+ /** Restrict to a single camera; omit for every row. */
7427
+ deviceId: number().optional(),
7428
+ /** Max rows returned, newest-first. */
7429
+ limit: number().int().min(1).max(1e3).optional()
7430
+ });
7431
+ /**
7333
7432
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7334
7433
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7335
7434
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12579,7 +12678,11 @@ array(ZoneRuleSchema).readonly();
12579
12678
  * Extend the enum here when a new gating consumer comes online (audio
12580
12679
  * gating, alert filtering, …) — no other surface needs to change.
12581
12680
  */
12582
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12681
+ var ZoneRuleStageEnum = _enum([
12682
+ "motion",
12683
+ "detection",
12684
+ "package"
12685
+ ]);
12583
12686
  DeviceType.Camera, method(object({
12584
12687
  deviceId: number(),
12585
12688
  stage: ZoneRuleStageEnum
@@ -12592,7 +12695,8 @@ DeviceType.Camera, method(object({
12592
12695
  auth: "admin"
12593
12696
  }), object({
12594
12697
  motion: array(ZoneRuleSchema).readonly(),
12595
- detection: array(ZoneRuleSchema).readonly()
12698
+ detection: array(ZoneRuleSchema).readonly(),
12699
+ package: array(ZoneRuleSchema).readonly()
12596
12700
  });
12597
12701
  var ProviderStatusSchema = object({
12598
12702
  connected: boolean(),
@@ -15843,6 +15947,7 @@ var EventKindIconSchema = _enum([
15843
15947
  "smoke",
15844
15948
  "water",
15845
15949
  "button",
15950
+ "package",
15846
15951
  "generic"
15847
15952
  ]);
15848
15953
  var EventKindCategorySchema = _enum([
@@ -15850,7 +15955,8 @@ var EventKindCategorySchema = _enum([
15850
15955
  "audio",
15851
15956
  "detection",
15852
15957
  "sensor",
15853
- "custom"
15958
+ "custom",
15959
+ "package"
15854
15960
  ]);
15855
15961
  var EventKindDescriptorSchema = object({
15856
15962
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16191,6 +16297,26 @@ var TrackCascadeCountsSchema = object({
16191
16297
  /** Per-track CLIP search vectors removed (best-effort). */
16192
16298
  embeddings: number().int()
16193
16299
  });
16300
+ /** Event-store footprint for one camera. */
16301
+ var EventStoreDeviceFootprintSchema = object({
16302
+ deviceId: number(),
16303
+ /** Persisted event rows (motion + object + audio) for the camera. */
16304
+ rows: number().int(),
16305
+ /** Event-owned media bytes on disk for the camera. */
16306
+ bytes: number().int()
16307
+ });
16308
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16309
+ var EventStoreFootprintSchema = object({
16310
+ totalRows: number().int(),
16311
+ totalBytes: number().int(),
16312
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16313
+ });
16314
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16315
+ var EventPruneCountsSchema = object({
16316
+ motion: number().int(),
16317
+ object: number().int(),
16318
+ audio: number().int()
16319
+ });
16194
16320
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16195
16321
  deviceId: number(),
16196
16322
  trackId: string()
@@ -16254,6 +16380,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16254
16380
  }), {
16255
16381
  kind: "mutation",
16256
16382
  auth: "admin"
16383
+ }), method(object({}), EventStoreFootprintSchema, {
16384
+ kind: "query",
16385
+ auth: "admin"
16386
+ }), method(object({
16387
+ olderThanMs: number(),
16388
+ reason: OpsLogReasonSchema.optional()
16389
+ }), EventPruneCountsSchema, {
16390
+ kind: "mutation",
16391
+ auth: "admin"
16392
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16393
+ kind: "mutation",
16394
+ auth: "admin"
16395
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16396
+ kind: "query",
16397
+ auth: "admin"
16257
16398
  }), method(object({
16258
16399
  eventId: string(),
16259
16400
  kind: MediaFileKindEnum.optional()
@@ -19487,13 +19628,131 @@ method(object({
19487
19628
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19488
19629
  kind: "mutation",
19489
19630
  auth: "admin"
19490
- }), method(object({ deviceId: number() }), object({
19631
+ }), method(object({
19632
+ deviceId: number(),
19633
+ reason: OpsLogReasonSchema.optional()
19634
+ }), object({
19491
19635
  floorMs: number().nullable(),
19492
19636
  deletedBuckets: number().int(),
19493
19637
  reclaimedBytes: number().int()
19494
19638
  }), {
19495
19639
  kind: "mutation",
19496
19640
  auth: "admin"
19641
+ }), method(object({
19642
+ deviceId: number(),
19643
+ fromMs: number().optional(),
19644
+ toMs: number().optional()
19645
+ }), object({
19646
+ deletedBuckets: number().int(),
19647
+ reclaimedBytes: number().int()
19648
+ }), {
19649
+ kind: "mutation",
19650
+ auth: "admin"
19651
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19652
+ kind: "query",
19653
+ auth: "admin"
19654
+ });
19655
+ /**
19656
+ * `recordingExport` cap — render a footage time range into a single downloadable
19657
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19658
+ * bounded lifetime with a durable history, auto-expiry, and optional
19659
+ * delete-after-download.
19660
+ *
19661
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19662
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19663
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19664
+ * input and dispatch to that single provider; the render runs on the node that
19665
+ * owns the footage (no cross-node segment transfer). Download rides the
19666
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19667
+ * SQLite); history rows survive file deletion for audit.
19668
+ */
19669
+ /** Playback-speed multiplier for the render (1 = realtime). */
19670
+ var ExportSpeedSchema = number().min(.25).max(32);
19671
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19672
+ var ExportTimelapseSchema = object({
19673
+ everyMs: number().int().positive(),
19674
+ outputFps: number().int().min(1).max(60).optional()
19675
+ });
19676
+ /**
19677
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19678
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19679
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19680
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19681
+ */
19682
+ var ExportOptionsSchema = object({
19683
+ speed: ExportSpeedSchema.optional(),
19684
+ timelapse: ExportTimelapseSchema.optional(),
19685
+ includeAudio: boolean(),
19686
+ maxLifeMs: number().int().positive(),
19687
+ deleteAfterDownload: boolean(),
19688
+ title: string().max(200).optional()
19689
+ }).superRefine((v, ctx) => {
19690
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19691
+ code: ZodIssueCode.custom,
19692
+ message: "speed and timelapse are mutually exclusive",
19693
+ path: ["timelapse"]
19694
+ });
19695
+ });
19696
+ var ExportStateSchema = _enum([
19697
+ "queued",
19698
+ "rendering",
19699
+ "ready",
19700
+ "failed",
19701
+ "expired",
19702
+ "deleted"
19703
+ ]);
19704
+ /** One export job / history row. */
19705
+ var ExportRecordSchema = object({
19706
+ id: string(),
19707
+ deviceId: number(),
19708
+ profile: string(),
19709
+ fromMs: number(),
19710
+ toMs: number(),
19711
+ options: ExportOptionsSchema,
19712
+ state: ExportStateSchema,
19713
+ /** 0–100 while rendering; null otherwise. */
19714
+ progressPct: number().nullable(),
19715
+ /** File size once ready; null before. */
19716
+ fileBytes: number().nullable(),
19717
+ expiresAt: number(),
19718
+ deleteAfterDownload: boolean(),
19719
+ /** Epoch of the first complete download; null until then. */
19720
+ downloadedAt: number().nullable(),
19721
+ createdAt: number(),
19722
+ /** User id/name that requested the export. */
19723
+ createdBy: string(),
19724
+ /** Failure reason when state is 'failed'; null otherwise. */
19725
+ error: string().nullable()
19726
+ });
19727
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19728
+ var ExportDownloadSchema = object({
19729
+ url: string(),
19730
+ endpoints: array(string())
19731
+ });
19732
+ method(object({
19733
+ deviceId: number(),
19734
+ profile: string(),
19735
+ fromMs: number(),
19736
+ toMs: number(),
19737
+ options: ExportOptionsSchema
19738
+ }), ExportRecordSchema, {
19739
+ kind: "mutation",
19740
+ auth: "protected"
19741
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19742
+ kind: "query",
19743
+ auth: "protected"
19744
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19745
+ kind: "query",
19746
+ auth: "protected"
19747
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19748
+ kind: "mutation",
19749
+ auth: "protected"
19750
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19751
+ kind: "mutation",
19752
+ auth: "protected"
19753
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19754
+ kind: "query",
19755
+ auth: "protected"
19497
19756
  });
19498
19757
  /**
19499
19758
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22513,6 +22772,12 @@ Object.freeze({
22513
22772
  addonId: null,
22514
22773
  access: "delete"
22515
22774
  },
22775
+ "pipelineAnalytics.deleteDeviceEvents": {
22776
+ capName: "pipeline-analytics",
22777
+ capScope: "device",
22778
+ addonId: null,
22779
+ access: "delete"
22780
+ },
22516
22781
  "pipelineAnalytics.deleteTracks": {
22517
22782
  capName: "pipeline-analytics",
22518
22783
  capScope: "device",
@@ -22543,6 +22808,12 @@ Object.freeze({
22543
22808
  addonId: null,
22544
22809
  access: "view"
22545
22810
  },
22811
+ "pipelineAnalytics.getEventStoreFootprint": {
22812
+ capName: "pipeline-analytics",
22813
+ capScope: "device",
22814
+ addonId: null,
22815
+ access: "view"
22816
+ },
22546
22817
  "pipelineAnalytics.getKeyEvents": {
22547
22818
  capName: "pipeline-analytics",
22548
22819
  capScope: "device",
@@ -22585,6 +22856,12 @@ Object.freeze({
22585
22856
  addonId: null,
22586
22857
  access: "view"
22587
22858
  },
22859
+ "pipelineAnalytics.listOpsLog": {
22860
+ capName: "pipeline-analytics",
22861
+ capScope: "device",
22862
+ addonId: null,
22863
+ access: "view"
22864
+ },
22588
22865
  "pipelineAnalytics.listRecentTracks": {
22589
22866
  capName: "pipeline-analytics",
22590
22867
  capScope: "device",
@@ -22597,6 +22874,12 @@ Object.freeze({
22597
22874
  addonId: null,
22598
22875
  access: "view"
22599
22876
  },
22877
+ "pipelineAnalytics.pruneEvents": {
22878
+ capName: "pipeline-analytics",
22879
+ capScope: "device",
22880
+ addonId: null,
22881
+ access: "create"
22882
+ },
22600
22883
  "pipelineAnalytics.pruneEventsBefore": {
22601
22884
  capName: "pipeline-analytics",
22602
22885
  capScope: "device",
@@ -23359,6 +23642,12 @@ Object.freeze({
23359
23642
  addonId: null,
23360
23643
  access: "create"
23361
23644
  },
23645
+ "recording.deleteFootprint": {
23646
+ capName: "recording",
23647
+ capScope: "system",
23648
+ addonId: null,
23649
+ access: "delete"
23650
+ },
23362
23651
  "recording.getAvailability": {
23363
23652
  capName: "recording",
23364
23653
  capScope: "system",
@@ -23389,6 +23678,12 @@ Object.freeze({
23389
23678
  addonId: null,
23390
23679
  access: "view"
23391
23680
  },
23681
+ "recording.listOpsLog": {
23682
+ capName: "recording",
23683
+ capScope: "system",
23684
+ addonId: null,
23685
+ access: "view"
23686
+ },
23392
23687
  "recording.locateSegment": {
23393
23688
  capName: "recording",
23394
23689
  capScope: "system",
@@ -23419,6 +23714,42 @@ Object.freeze({
23419
23714
  addonId: null,
23420
23715
  access: "create"
23421
23716
  },
23717
+ "recordingExport.cancelExport": {
23718
+ capName: "recordingExport",
23719
+ capScope: "system",
23720
+ addonId: null,
23721
+ access: "create"
23722
+ },
23723
+ "recordingExport.createExport": {
23724
+ capName: "recordingExport",
23725
+ capScope: "system",
23726
+ addonId: null,
23727
+ access: "create"
23728
+ },
23729
+ "recordingExport.deleteExport": {
23730
+ capName: "recordingExport",
23731
+ capScope: "system",
23732
+ addonId: null,
23733
+ access: "delete"
23734
+ },
23735
+ "recordingExport.getDownloadUrl": {
23736
+ capName: "recordingExport",
23737
+ capScope: "system",
23738
+ addonId: null,
23739
+ access: "view"
23740
+ },
23741
+ "recordingExport.getExport": {
23742
+ capName: "recordingExport",
23743
+ capScope: "system",
23744
+ addonId: null,
23745
+ access: "view"
23746
+ },
23747
+ "recordingExport.listExports": {
23748
+ capName: "recordingExport",
23749
+ capScope: "system",
23750
+ addonId: null,
23751
+ access: "view"
23752
+ },
23422
23753
  "sceneMonitor.captureReference": {
23423
23754
  capName: "scene-monitor",
23424
23755
  capScope: "device",
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
41
41
  //#endregion
42
- //#region ../types/dist/event-category-H4AVePnn.mjs
42
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
43
43
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
44
44
  EventCategory["SystemBoot"] = "system.boot";
45
45
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -192,6 +192,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
192
192
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
193
193
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
194
194
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
195
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
196
+ * progress bar the client reconciles via `recordingExport.getExport`. */
197
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
198
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
199
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
195
200
  EventCategory["DetectionEvent"] = "detection.event";
196
201
  EventCategory["SessionTrackNew"] = "session.track.new";
197
202
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -481,6 +486,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
481
486
  */
482
487
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
483
488
  /**
489
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
490
+ * a package zone — a newly-appeared stationary object of a package class
491
+ * that cleared the class / zone / dwell / size gates. Payload:
492
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
493
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
494
+ * Telemetry (D8): the durable record is the `package-events` store row;
495
+ * this bus topic drives notifier rules + live UI. See
496
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
497
+ */
498
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
499
+ /**
500
+ * Fired by `addon-post-analysis` when a previously-delivered package
501
+ * leaves its zone (the stationary entry departed — moved or swept).
502
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
503
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
504
+ * Telemetry (D8). See package-zones-design §5.2.
505
+ */
506
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
507
+ /**
484
508
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
485
509
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
486
510
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5219,6 +5243,25 @@ function _instanceof(cls, params = {}) {
5219
5243
  };
5220
5244
  return inst;
5221
5245
  }
5246
+ //#endregion
5247
+ //#region ../../node_modules/zod/v4/classic/compat.js
5248
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5249
+ var ZodIssueCode = {
5250
+ invalid_type: "invalid_type",
5251
+ too_big: "too_big",
5252
+ too_small: "too_small",
5253
+ invalid_format: "invalid_format",
5254
+ not_multiple_of: "not_multiple_of",
5255
+ unrecognized_keys: "unrecognized_keys",
5256
+ invalid_union: "invalid_union",
5257
+ invalid_key: "invalid_key",
5258
+ invalid_element: "invalid_element",
5259
+ invalid_value: "invalid_value",
5260
+ custom: "custom"
5261
+ };
5262
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5263
+ var ZodFirstPartyTypeKind;
5264
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5222
5265
  Object.fromEntries([
5223
5266
  {
5224
5267
  id: "overview",
@@ -7325,6 +7368,62 @@ var RecordingConfigSchema = object({
7325
7368
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7326
7369
  });
7327
7370
  /**
7371
+ * Ops-log — the durable, append-only operations audit shared by the
7372
+ * recordings and events management surfaces.
7373
+ *
7374
+ * ONE row shape is reused for both domains so a single "Activity" view can
7375
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7376
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7377
+ * management operation, WHY it ran (reason), and its measurable effect
7378
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7379
+ * never fail the operation it records.
7380
+ */
7381
+ /** Which management domain the operation belongs to. */
7382
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7383
+ /** The kind of management operation performed. */
7384
+ var OpsLogOpSchema = _enum([
7385
+ "prune",
7386
+ "manual-delete",
7387
+ "rescan",
7388
+ "retention-run"
7389
+ ]);
7390
+ /** Why the operation ran. */
7391
+ var OpsLogReasonSchema = _enum([
7392
+ "retention",
7393
+ "quota",
7394
+ "manual",
7395
+ "operator"
7396
+ ]);
7397
+ /** One audit row, shared verbatim by both domains. */
7398
+ var OpsLogEntrySchema = object({
7399
+ /** Unique row id. */
7400
+ id: string(),
7401
+ /** Epoch ms the operation completed. */
7402
+ at: number(),
7403
+ domain: OpsLogDomainSchema,
7404
+ op: OpsLogOpSchema,
7405
+ reason: OpsLogReasonSchema,
7406
+ /** The camera the op targeted; null for a cluster/global op. */
7407
+ deviceId: number().nullable(),
7408
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7409
+ nodeId: string(),
7410
+ /** Buckets / rows deleted (op-specific unit). */
7411
+ itemsAffected: number(),
7412
+ /** Bytes reclaimed by the op (0 when not measurable). */
7413
+ bytesReclaimed: number(),
7414
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7415
+ detail: string().nullable(),
7416
+ /** Who/what triggered the op. */
7417
+ actor: string()
7418
+ });
7419
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7420
+ var OpsLogQueryInputSchema = object({
7421
+ /** Restrict to a single camera; omit for every row. */
7422
+ deviceId: number().optional(),
7423
+ /** Max rows returned, newest-first. */
7424
+ limit: number().int().min(1).max(1e3).optional()
7425
+ });
7426
+ /**
7328
7427
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7329
7428
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7330
7429
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12574,7 +12673,11 @@ array(ZoneRuleSchema).readonly();
12574
12673
  * Extend the enum here when a new gating consumer comes online (audio
12575
12674
  * gating, alert filtering, …) — no other surface needs to change.
12576
12675
  */
12577
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12676
+ var ZoneRuleStageEnum = _enum([
12677
+ "motion",
12678
+ "detection",
12679
+ "package"
12680
+ ]);
12578
12681
  DeviceType.Camera, method(object({
12579
12682
  deviceId: number(),
12580
12683
  stage: ZoneRuleStageEnum
@@ -12587,7 +12690,8 @@ DeviceType.Camera, method(object({
12587
12690
  auth: "admin"
12588
12691
  }), object({
12589
12692
  motion: array(ZoneRuleSchema).readonly(),
12590
- detection: array(ZoneRuleSchema).readonly()
12693
+ detection: array(ZoneRuleSchema).readonly(),
12694
+ package: array(ZoneRuleSchema).readonly()
12591
12695
  });
12592
12696
  var ProviderStatusSchema = object({
12593
12697
  connected: boolean(),
@@ -15838,6 +15942,7 @@ var EventKindIconSchema = _enum([
15838
15942
  "smoke",
15839
15943
  "water",
15840
15944
  "button",
15945
+ "package",
15841
15946
  "generic"
15842
15947
  ]);
15843
15948
  var EventKindCategorySchema = _enum([
@@ -15845,7 +15950,8 @@ var EventKindCategorySchema = _enum([
15845
15950
  "audio",
15846
15951
  "detection",
15847
15952
  "sensor",
15848
- "custom"
15953
+ "custom",
15954
+ "package"
15849
15955
  ]);
15850
15956
  var EventKindDescriptorSchema = object({
15851
15957
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16186,6 +16292,26 @@ var TrackCascadeCountsSchema = object({
16186
16292
  /** Per-track CLIP search vectors removed (best-effort). */
16187
16293
  embeddings: number().int()
16188
16294
  });
16295
+ /** Event-store footprint for one camera. */
16296
+ var EventStoreDeviceFootprintSchema = object({
16297
+ deviceId: number(),
16298
+ /** Persisted event rows (motion + object + audio) for the camera. */
16299
+ rows: number().int(),
16300
+ /** Event-owned media bytes on disk for the camera. */
16301
+ bytes: number().int()
16302
+ });
16303
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16304
+ var EventStoreFootprintSchema = object({
16305
+ totalRows: number().int(),
16306
+ totalBytes: number().int(),
16307
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16308
+ });
16309
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16310
+ var EventPruneCountsSchema = object({
16311
+ motion: number().int(),
16312
+ object: number().int(),
16313
+ audio: number().int()
16314
+ });
16189
16315
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16190
16316
  deviceId: number(),
16191
16317
  trackId: string()
@@ -16249,6 +16375,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16249
16375
  }), {
16250
16376
  kind: "mutation",
16251
16377
  auth: "admin"
16378
+ }), method(object({}), EventStoreFootprintSchema, {
16379
+ kind: "query",
16380
+ auth: "admin"
16381
+ }), method(object({
16382
+ olderThanMs: number(),
16383
+ reason: OpsLogReasonSchema.optional()
16384
+ }), EventPruneCountsSchema, {
16385
+ kind: "mutation",
16386
+ auth: "admin"
16387
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16388
+ kind: "mutation",
16389
+ auth: "admin"
16390
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16391
+ kind: "query",
16392
+ auth: "admin"
16252
16393
  }), method(object({
16253
16394
  eventId: string(),
16254
16395
  kind: MediaFileKindEnum.optional()
@@ -19482,13 +19623,131 @@ method(object({
19482
19623
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19483
19624
  kind: "mutation",
19484
19625
  auth: "admin"
19485
- }), method(object({ deviceId: number() }), object({
19626
+ }), method(object({
19627
+ deviceId: number(),
19628
+ reason: OpsLogReasonSchema.optional()
19629
+ }), object({
19486
19630
  floorMs: number().nullable(),
19487
19631
  deletedBuckets: number().int(),
19488
19632
  reclaimedBytes: number().int()
19489
19633
  }), {
19490
19634
  kind: "mutation",
19491
19635
  auth: "admin"
19636
+ }), method(object({
19637
+ deviceId: number(),
19638
+ fromMs: number().optional(),
19639
+ toMs: number().optional()
19640
+ }), object({
19641
+ deletedBuckets: number().int(),
19642
+ reclaimedBytes: number().int()
19643
+ }), {
19644
+ kind: "mutation",
19645
+ auth: "admin"
19646
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19647
+ kind: "query",
19648
+ auth: "admin"
19649
+ });
19650
+ /**
19651
+ * `recordingExport` cap — render a footage time range into a single downloadable
19652
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19653
+ * bounded lifetime with a durable history, auto-expiry, and optional
19654
+ * delete-after-download.
19655
+ *
19656
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19657
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19658
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19659
+ * input and dispatch to that single provider; the render runs on the node that
19660
+ * owns the footage (no cross-node segment transfer). Download rides the
19661
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19662
+ * SQLite); history rows survive file deletion for audit.
19663
+ */
19664
+ /** Playback-speed multiplier for the render (1 = realtime). */
19665
+ var ExportSpeedSchema = number().min(.25).max(32);
19666
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19667
+ var ExportTimelapseSchema = object({
19668
+ everyMs: number().int().positive(),
19669
+ outputFps: number().int().min(1).max(60).optional()
19670
+ });
19671
+ /**
19672
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19673
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19674
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19675
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19676
+ */
19677
+ var ExportOptionsSchema = object({
19678
+ speed: ExportSpeedSchema.optional(),
19679
+ timelapse: ExportTimelapseSchema.optional(),
19680
+ includeAudio: boolean(),
19681
+ maxLifeMs: number().int().positive(),
19682
+ deleteAfterDownload: boolean(),
19683
+ title: string().max(200).optional()
19684
+ }).superRefine((v, ctx) => {
19685
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19686
+ code: ZodIssueCode.custom,
19687
+ message: "speed and timelapse are mutually exclusive",
19688
+ path: ["timelapse"]
19689
+ });
19690
+ });
19691
+ var ExportStateSchema = _enum([
19692
+ "queued",
19693
+ "rendering",
19694
+ "ready",
19695
+ "failed",
19696
+ "expired",
19697
+ "deleted"
19698
+ ]);
19699
+ /** One export job / history row. */
19700
+ var ExportRecordSchema = object({
19701
+ id: string(),
19702
+ deviceId: number(),
19703
+ profile: string(),
19704
+ fromMs: number(),
19705
+ toMs: number(),
19706
+ options: ExportOptionsSchema,
19707
+ state: ExportStateSchema,
19708
+ /** 0–100 while rendering; null otherwise. */
19709
+ progressPct: number().nullable(),
19710
+ /** File size once ready; null before. */
19711
+ fileBytes: number().nullable(),
19712
+ expiresAt: number(),
19713
+ deleteAfterDownload: boolean(),
19714
+ /** Epoch of the first complete download; null until then. */
19715
+ downloadedAt: number().nullable(),
19716
+ createdAt: number(),
19717
+ /** User id/name that requested the export. */
19718
+ createdBy: string(),
19719
+ /** Failure reason when state is 'failed'; null otherwise. */
19720
+ error: string().nullable()
19721
+ });
19722
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19723
+ var ExportDownloadSchema = object({
19724
+ url: string(),
19725
+ endpoints: array(string())
19726
+ });
19727
+ method(object({
19728
+ deviceId: number(),
19729
+ profile: string(),
19730
+ fromMs: number(),
19731
+ toMs: number(),
19732
+ options: ExportOptionsSchema
19733
+ }), ExportRecordSchema, {
19734
+ kind: "mutation",
19735
+ auth: "protected"
19736
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19737
+ kind: "query",
19738
+ auth: "protected"
19739
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19740
+ kind: "query",
19741
+ auth: "protected"
19742
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19743
+ kind: "mutation",
19744
+ auth: "protected"
19745
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19746
+ kind: "mutation",
19747
+ auth: "protected"
19748
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19749
+ kind: "query",
19750
+ auth: "protected"
19492
19751
  });
19493
19752
  /**
19494
19753
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22508,6 +22767,12 @@ Object.freeze({
22508
22767
  addonId: null,
22509
22768
  access: "delete"
22510
22769
  },
22770
+ "pipelineAnalytics.deleteDeviceEvents": {
22771
+ capName: "pipeline-analytics",
22772
+ capScope: "device",
22773
+ addonId: null,
22774
+ access: "delete"
22775
+ },
22511
22776
  "pipelineAnalytics.deleteTracks": {
22512
22777
  capName: "pipeline-analytics",
22513
22778
  capScope: "device",
@@ -22538,6 +22803,12 @@ Object.freeze({
22538
22803
  addonId: null,
22539
22804
  access: "view"
22540
22805
  },
22806
+ "pipelineAnalytics.getEventStoreFootprint": {
22807
+ capName: "pipeline-analytics",
22808
+ capScope: "device",
22809
+ addonId: null,
22810
+ access: "view"
22811
+ },
22541
22812
  "pipelineAnalytics.getKeyEvents": {
22542
22813
  capName: "pipeline-analytics",
22543
22814
  capScope: "device",
@@ -22580,6 +22851,12 @@ Object.freeze({
22580
22851
  addonId: null,
22581
22852
  access: "view"
22582
22853
  },
22854
+ "pipelineAnalytics.listOpsLog": {
22855
+ capName: "pipeline-analytics",
22856
+ capScope: "device",
22857
+ addonId: null,
22858
+ access: "view"
22859
+ },
22583
22860
  "pipelineAnalytics.listRecentTracks": {
22584
22861
  capName: "pipeline-analytics",
22585
22862
  capScope: "device",
@@ -22592,6 +22869,12 @@ Object.freeze({
22592
22869
  addonId: null,
22593
22870
  access: "view"
22594
22871
  },
22872
+ "pipelineAnalytics.pruneEvents": {
22873
+ capName: "pipeline-analytics",
22874
+ capScope: "device",
22875
+ addonId: null,
22876
+ access: "create"
22877
+ },
22595
22878
  "pipelineAnalytics.pruneEventsBefore": {
22596
22879
  capName: "pipeline-analytics",
22597
22880
  capScope: "device",
@@ -23354,6 +23637,12 @@ Object.freeze({
23354
23637
  addonId: null,
23355
23638
  access: "create"
23356
23639
  },
23640
+ "recording.deleteFootprint": {
23641
+ capName: "recording",
23642
+ capScope: "system",
23643
+ addonId: null,
23644
+ access: "delete"
23645
+ },
23357
23646
  "recording.getAvailability": {
23358
23647
  capName: "recording",
23359
23648
  capScope: "system",
@@ -23384,6 +23673,12 @@ Object.freeze({
23384
23673
  addonId: null,
23385
23674
  access: "view"
23386
23675
  },
23676
+ "recording.listOpsLog": {
23677
+ capName: "recording",
23678
+ capScope: "system",
23679
+ addonId: null,
23680
+ access: "view"
23681
+ },
23387
23682
  "recording.locateSegment": {
23388
23683
  capName: "recording",
23389
23684
  capScope: "system",
@@ -23414,6 +23709,42 @@ Object.freeze({
23414
23709
  addonId: null,
23415
23710
  access: "create"
23416
23711
  },
23712
+ "recordingExport.cancelExport": {
23713
+ capName: "recordingExport",
23714
+ capScope: "system",
23715
+ addonId: null,
23716
+ access: "create"
23717
+ },
23718
+ "recordingExport.createExport": {
23719
+ capName: "recordingExport",
23720
+ capScope: "system",
23721
+ addonId: null,
23722
+ access: "create"
23723
+ },
23724
+ "recordingExport.deleteExport": {
23725
+ capName: "recordingExport",
23726
+ capScope: "system",
23727
+ addonId: null,
23728
+ access: "delete"
23729
+ },
23730
+ "recordingExport.getDownloadUrl": {
23731
+ capName: "recordingExport",
23732
+ capScope: "system",
23733
+ addonId: null,
23734
+ access: "view"
23735
+ },
23736
+ "recordingExport.getExport": {
23737
+ capName: "recordingExport",
23738
+ capScope: "system",
23739
+ addonId: null,
23740
+ access: "view"
23741
+ },
23742
+ "recordingExport.listExports": {
23743
+ capName: "recordingExport",
23744
+ capScope: "system",
23745
+ addonId: null,
23746
+ access: "view"
23747
+ },
23417
23748
  "sceneMonitor.captureReference": {
23418
23749
  capName: "scene-monitor",
23419
23750
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-mqtt-broker",
3
- "version": "1.1.25",
3
+ "version": "1.1.27",
4
4
  "description": "MQTT broker registry addon for CamStack — manages external broker entries + an optional embedded aedes broker. Consumers spin up their own `mqtt.js` clients via the `mqtt-broker` cap.",
5
5
  "keywords": [
6
6
  "camstack",