@camstack/addon-provider-dreame 0.1.31 → 0.1.33

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.
package/dist/addon.js CHANGED
@@ -37,7 +37,7 @@ let crypto$1 = require("crypto");
37
37
  let events = require("events");
38
38
  let zlib = require("zlib");
39
39
  zlib = __toESM(zlib, 1);
40
- //#region ../types/dist/event-category-H4AVePnn.mjs
40
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
41
41
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
42
42
  EventCategory["SystemBoot"] = "system.boot";
43
43
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -190,6 +190,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
190
190
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
191
191
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
192
192
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
193
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
194
+ * progress bar the client reconciles via `recordingExport.getExport`. */
195
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
196
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
197
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
193
198
  EventCategory["DetectionEvent"] = "detection.event";
194
199
  EventCategory["SessionTrackNew"] = "session.track.new";
195
200
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -479,6 +484,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
479
484
  */
480
485
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
481
486
  /**
487
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
488
+ * a package zone — a newly-appeared stationary object of a package class
489
+ * that cleared the class / zone / dwell / size gates. Payload:
490
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
491
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
492
+ * Telemetry (D8): the durable record is the `package-events` store row;
493
+ * this bus topic drives notifier rules + live UI. See
494
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
495
+ */
496
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
497
+ /**
498
+ * Fired by `addon-post-analysis` when a previously-delivered package
499
+ * leaves its zone (the stationary entry departed — moved or swept).
500
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
501
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
502
+ * Telemetry (D8). See package-zones-design §5.2.
503
+ */
504
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
505
+ /**
482
506
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
483
507
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
484
508
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5231,6 +5255,25 @@ function preprocess(fn, schema) {
5231
5255
  out: schema
5232
5256
  });
5233
5257
  }
5258
+ //#endregion
5259
+ //#region ../../node_modules/zod/v4/classic/compat.js
5260
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5261
+ var ZodIssueCode$1 = {
5262
+ invalid_type: "invalid_type",
5263
+ too_big: "too_big",
5264
+ too_small: "too_small",
5265
+ invalid_format: "invalid_format",
5266
+ not_multiple_of: "not_multiple_of",
5267
+ unrecognized_keys: "unrecognized_keys",
5268
+ invalid_union: "invalid_union",
5269
+ invalid_key: "invalid_key",
5270
+ invalid_element: "invalid_element",
5271
+ invalid_value: "invalid_value",
5272
+ custom: "custom"
5273
+ };
5274
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5275
+ var ZodFirstPartyTypeKind$1;
5276
+ ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5234
5277
  Object.fromEntries([
5235
5278
  {
5236
5279
  id: "overview",
@@ -7353,6 +7396,62 @@ var RecordingConfigSchema = object({
7353
7396
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7354
7397
  });
7355
7398
  /**
7399
+ * Ops-log — the durable, append-only operations audit shared by the
7400
+ * recordings and events management surfaces.
7401
+ *
7402
+ * ONE row shape is reused for both domains so a single "Activity" view can
7403
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7404
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7405
+ * management operation, WHY it ran (reason), and its measurable effect
7406
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7407
+ * never fail the operation it records.
7408
+ */
7409
+ /** Which management domain the operation belongs to. */
7410
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7411
+ /** The kind of management operation performed. */
7412
+ var OpsLogOpSchema = _enum([
7413
+ "prune",
7414
+ "manual-delete",
7415
+ "rescan",
7416
+ "retention-run"
7417
+ ]);
7418
+ /** Why the operation ran. */
7419
+ var OpsLogReasonSchema = _enum([
7420
+ "retention",
7421
+ "quota",
7422
+ "manual",
7423
+ "operator"
7424
+ ]);
7425
+ /** One audit row, shared verbatim by both domains. */
7426
+ var OpsLogEntrySchema = object({
7427
+ /** Unique row id. */
7428
+ id: string(),
7429
+ /** Epoch ms the operation completed. */
7430
+ at: number(),
7431
+ domain: OpsLogDomainSchema,
7432
+ op: OpsLogOpSchema,
7433
+ reason: OpsLogReasonSchema,
7434
+ /** The camera the op targeted; null for a cluster/global op. */
7435
+ deviceId: number().nullable(),
7436
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7437
+ nodeId: string(),
7438
+ /** Buckets / rows deleted (op-specific unit). */
7439
+ itemsAffected: number(),
7440
+ /** Bytes reclaimed by the op (0 when not measurable). */
7441
+ bytesReclaimed: number(),
7442
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7443
+ detail: string().nullable(),
7444
+ /** Who/what triggered the op. */
7445
+ actor: string()
7446
+ });
7447
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7448
+ var OpsLogQueryInputSchema = object({
7449
+ /** Restrict to a single camera; omit for every row. */
7450
+ deviceId: number().optional(),
7451
+ /** Max rows returned, newest-first. */
7452
+ limit: number().int().min(1).max(1e3).optional()
7453
+ });
7454
+ /**
7356
7455
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7357
7456
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7358
7457
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -14708,7 +14807,11 @@ array(ZoneRuleSchema).readonly();
14708
14807
  * Extend the enum here when a new gating consumer comes online (audio
14709
14808
  * gating, alert filtering, …) — no other surface needs to change.
14710
14809
  */
14711
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
14810
+ var ZoneRuleStageEnum = _enum([
14811
+ "motion",
14812
+ "detection",
14813
+ "package"
14814
+ ]);
14712
14815
  /**
14713
14816
  * Runtime registry: cap-property-name → cap definition. `BaseDevice`'s
14714
14817
  * `state` getter looks up the cap definition here to construct a
@@ -14802,16 +14905,25 @@ var DEVICE_LOCAL_STATE_CAPS = {
14802
14905
  })
14803
14906
  },
14804
14907
  /**
14805
- * Runtime-state slice — both stages mirrored together so consumers
14908
+ * Runtime-state slice — every stage mirrored together so consumers
14806
14909
  * see one reactive handle (`device.state.zoneRules.value`) instead
14807
- * of two. Bulk-replace mutations on either stage write the full
14808
- * `{motion, detection}` shape, so subscribers always get the
14910
+ * of one per stage. Bulk-replace mutations on any stage write the full
14911
+ * `{motion, detection, package}` shape, so subscribers always get the
14809
14912
  * complete current set. Consumers that only care about one stage
14810
14913
  * just read the matching property.
14914
+ *
14915
+ * `package` backs the package-drop detector — a package zone is a
14916
+ * `ZoneRule` on the `'package'` stage referencing drawn polygons
14917
+ * (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
14918
+ * The orchestrator provider writes this stage as a first-class slice
14919
+ * (Phase 4): every mutation mirrors the full `{motion, detection,
14920
+ * package}` shape, so consumers read the current package rules directly
14921
+ * off `device.state.zoneRules.value.package`.
14811
14922
  */
14812
14923
  runtimeState: object({
14813
14924
  motion: array(ZoneRuleSchema).readonly(),
14814
- detection: array(ZoneRuleSchema).readonly()
14925
+ detection: array(ZoneRuleSchema).readonly(),
14926
+ package: array(ZoneRuleSchema).readonly()
14815
14927
  })
14816
14928
  },
14817
14929
  zones: zonesCapability
@@ -18790,6 +18902,7 @@ var EventKindIconSchema = _enum([
18790
18902
  "smoke",
18791
18903
  "water",
18792
18904
  "button",
18905
+ "package",
18793
18906
  "generic"
18794
18907
  ]);
18795
18908
  var EventKindCategorySchema = _enum([
@@ -18797,7 +18910,8 @@ var EventKindCategorySchema = _enum([
18797
18910
  "audio",
18798
18911
  "detection",
18799
18912
  "sensor",
18800
- "custom"
18913
+ "custom",
18914
+ "package"
18801
18915
  ]);
18802
18916
  var EventKindDescriptorSchema = object({
18803
18917
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19138,6 +19252,26 @@ var TrackCascadeCountsSchema = object({
19138
19252
  /** Per-track CLIP search vectors removed (best-effort). */
19139
19253
  embeddings: number().int()
19140
19254
  });
19255
+ /** Event-store footprint for one camera. */
19256
+ var EventStoreDeviceFootprintSchema = object({
19257
+ deviceId: number(),
19258
+ /** Persisted event rows (motion + object + audio) for the camera. */
19259
+ rows: number().int(),
19260
+ /** Event-owned media bytes on disk for the camera. */
19261
+ bytes: number().int()
19262
+ });
19263
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
19264
+ var EventStoreFootprintSchema = object({
19265
+ totalRows: number().int(),
19266
+ totalBytes: number().int(),
19267
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
19268
+ });
19269
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
19270
+ var EventPruneCountsSchema = object({
19271
+ motion: number().int(),
19272
+ object: number().int(),
19273
+ audio: number().int()
19274
+ });
19141
19275
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
19142
19276
  deviceId: number(),
19143
19277
  trackId: string()
@@ -19201,6 +19335,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19201
19335
  }), {
19202
19336
  kind: "mutation",
19203
19337
  auth: "admin"
19338
+ }), method(object({}), EventStoreFootprintSchema, {
19339
+ kind: "query",
19340
+ auth: "admin"
19341
+ }), method(object({
19342
+ olderThanMs: number(),
19343
+ reason: OpsLogReasonSchema.optional()
19344
+ }), EventPruneCountsSchema, {
19345
+ kind: "mutation",
19346
+ auth: "admin"
19347
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
19348
+ kind: "mutation",
19349
+ auth: "admin"
19350
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19351
+ kind: "query",
19352
+ auth: "admin"
19204
19353
  }), method(object({
19205
19354
  eventId: string(),
19206
19355
  kind: MediaFileKindEnum.optional()
@@ -22451,13 +22600,131 @@ method(object({
22451
22600
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
22452
22601
  kind: "mutation",
22453
22602
  auth: "admin"
22454
- }), method(object({ deviceId: number() }), object({
22603
+ }), method(object({
22604
+ deviceId: number(),
22605
+ reason: OpsLogReasonSchema.optional()
22606
+ }), object({
22455
22607
  floorMs: number().nullable(),
22456
22608
  deletedBuckets: number().int(),
22457
22609
  reclaimedBytes: number().int()
22458
22610
  }), {
22459
22611
  kind: "mutation",
22460
22612
  auth: "admin"
22613
+ }), method(object({
22614
+ deviceId: number(),
22615
+ fromMs: number().optional(),
22616
+ toMs: number().optional()
22617
+ }), object({
22618
+ deletedBuckets: number().int(),
22619
+ reclaimedBytes: number().int()
22620
+ }), {
22621
+ kind: "mutation",
22622
+ auth: "admin"
22623
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
22624
+ kind: "query",
22625
+ auth: "admin"
22626
+ });
22627
+ /**
22628
+ * `recordingExport` cap — render a footage time range into a single downloadable
22629
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
22630
+ * bounded lifetime with a durable history, auto-expiry, and optional
22631
+ * delete-after-download.
22632
+ *
22633
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
22634
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
22635
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
22636
+ * input and dispatch to that single provider; the render runs on the node that
22637
+ * owns the footage (no cross-node segment transfer). Download rides the
22638
+ * framework addon data-plane. State persists in a DurableState blob (NOT
22639
+ * SQLite); history rows survive file deletion for audit.
22640
+ */
22641
+ /** Playback-speed multiplier for the render (1 = realtime). */
22642
+ var ExportSpeedSchema = number().min(.25).max(32);
22643
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
22644
+ var ExportTimelapseSchema = object({
22645
+ everyMs: number().int().positive(),
22646
+ outputFps: number().int().min(1).max(60).optional()
22647
+ });
22648
+ /**
22649
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
22650
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
22651
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
22652
+ * `deleteAfterDownload` removes it shortly after the first complete download.
22653
+ */
22654
+ var ExportOptionsSchema = object({
22655
+ speed: ExportSpeedSchema.optional(),
22656
+ timelapse: ExportTimelapseSchema.optional(),
22657
+ includeAudio: boolean(),
22658
+ maxLifeMs: number().int().positive(),
22659
+ deleteAfterDownload: boolean(),
22660
+ title: string().max(200).optional()
22661
+ }).superRefine((v, ctx) => {
22662
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
22663
+ code: ZodIssueCode$1.custom,
22664
+ message: "speed and timelapse are mutually exclusive",
22665
+ path: ["timelapse"]
22666
+ });
22667
+ });
22668
+ var ExportStateSchema = _enum([
22669
+ "queued",
22670
+ "rendering",
22671
+ "ready",
22672
+ "failed",
22673
+ "expired",
22674
+ "deleted"
22675
+ ]);
22676
+ /** One export job / history row. */
22677
+ var ExportRecordSchema = object({
22678
+ id: string(),
22679
+ deviceId: number(),
22680
+ profile: string(),
22681
+ fromMs: number(),
22682
+ toMs: number(),
22683
+ options: ExportOptionsSchema,
22684
+ state: ExportStateSchema,
22685
+ /** 0–100 while rendering; null otherwise. */
22686
+ progressPct: number().nullable(),
22687
+ /** File size once ready; null before. */
22688
+ fileBytes: number().nullable(),
22689
+ expiresAt: number(),
22690
+ deleteAfterDownload: boolean(),
22691
+ /** Epoch of the first complete download; null until then. */
22692
+ downloadedAt: number().nullable(),
22693
+ createdAt: number(),
22694
+ /** User id/name that requested the export. */
22695
+ createdBy: string(),
22696
+ /** Failure reason when state is 'failed'; null otherwise. */
22697
+ error: string().nullable()
22698
+ });
22699
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
22700
+ var ExportDownloadSchema = object({
22701
+ url: string(),
22702
+ endpoints: array(string())
22703
+ });
22704
+ method(object({
22705
+ deviceId: number(),
22706
+ profile: string(),
22707
+ fromMs: number(),
22708
+ toMs: number(),
22709
+ options: ExportOptionsSchema
22710
+ }), ExportRecordSchema, {
22711
+ kind: "mutation",
22712
+ auth: "protected"
22713
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
22714
+ kind: "query",
22715
+ auth: "protected"
22716
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22717
+ kind: "query",
22718
+ auth: "protected"
22719
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22720
+ kind: "mutation",
22721
+ auth: "protected"
22722
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22723
+ kind: "mutation",
22724
+ auth: "protected"
22725
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
22726
+ kind: "query",
22727
+ auth: "protected"
22461
22728
  });
22462
22729
  /**
22463
22730
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -25477,6 +25744,12 @@ Object.freeze({
25477
25744
  addonId: null,
25478
25745
  access: "delete"
25479
25746
  },
25747
+ "pipelineAnalytics.deleteDeviceEvents": {
25748
+ capName: "pipeline-analytics",
25749
+ capScope: "device",
25750
+ addonId: null,
25751
+ access: "delete"
25752
+ },
25480
25753
  "pipelineAnalytics.deleteTracks": {
25481
25754
  capName: "pipeline-analytics",
25482
25755
  capScope: "device",
@@ -25507,6 +25780,12 @@ Object.freeze({
25507
25780
  addonId: null,
25508
25781
  access: "view"
25509
25782
  },
25783
+ "pipelineAnalytics.getEventStoreFootprint": {
25784
+ capName: "pipeline-analytics",
25785
+ capScope: "device",
25786
+ addonId: null,
25787
+ access: "view"
25788
+ },
25510
25789
  "pipelineAnalytics.getKeyEvents": {
25511
25790
  capName: "pipeline-analytics",
25512
25791
  capScope: "device",
@@ -25549,6 +25828,12 @@ Object.freeze({
25549
25828
  addonId: null,
25550
25829
  access: "view"
25551
25830
  },
25831
+ "pipelineAnalytics.listOpsLog": {
25832
+ capName: "pipeline-analytics",
25833
+ capScope: "device",
25834
+ addonId: null,
25835
+ access: "view"
25836
+ },
25552
25837
  "pipelineAnalytics.listRecentTracks": {
25553
25838
  capName: "pipeline-analytics",
25554
25839
  capScope: "device",
@@ -25561,6 +25846,12 @@ Object.freeze({
25561
25846
  addonId: null,
25562
25847
  access: "view"
25563
25848
  },
25849
+ "pipelineAnalytics.pruneEvents": {
25850
+ capName: "pipeline-analytics",
25851
+ capScope: "device",
25852
+ addonId: null,
25853
+ access: "create"
25854
+ },
25564
25855
  "pipelineAnalytics.pruneEventsBefore": {
25565
25856
  capName: "pipeline-analytics",
25566
25857
  capScope: "device",
@@ -26323,6 +26614,12 @@ Object.freeze({
26323
26614
  addonId: null,
26324
26615
  access: "create"
26325
26616
  },
26617
+ "recording.deleteFootprint": {
26618
+ capName: "recording",
26619
+ capScope: "system",
26620
+ addonId: null,
26621
+ access: "delete"
26622
+ },
26326
26623
  "recording.getAvailability": {
26327
26624
  capName: "recording",
26328
26625
  capScope: "system",
@@ -26353,6 +26650,12 @@ Object.freeze({
26353
26650
  addonId: null,
26354
26651
  access: "view"
26355
26652
  },
26653
+ "recording.listOpsLog": {
26654
+ capName: "recording",
26655
+ capScope: "system",
26656
+ addonId: null,
26657
+ access: "view"
26658
+ },
26356
26659
  "recording.locateSegment": {
26357
26660
  capName: "recording",
26358
26661
  capScope: "system",
@@ -26383,6 +26686,42 @@ Object.freeze({
26383
26686
  addonId: null,
26384
26687
  access: "create"
26385
26688
  },
26689
+ "recordingExport.cancelExport": {
26690
+ capName: "recordingExport",
26691
+ capScope: "system",
26692
+ addonId: null,
26693
+ access: "create"
26694
+ },
26695
+ "recordingExport.createExport": {
26696
+ capName: "recordingExport",
26697
+ capScope: "system",
26698
+ addonId: null,
26699
+ access: "create"
26700
+ },
26701
+ "recordingExport.deleteExport": {
26702
+ capName: "recordingExport",
26703
+ capScope: "system",
26704
+ addonId: null,
26705
+ access: "delete"
26706
+ },
26707
+ "recordingExport.getDownloadUrl": {
26708
+ capName: "recordingExport",
26709
+ capScope: "system",
26710
+ addonId: null,
26711
+ access: "view"
26712
+ },
26713
+ "recordingExport.getExport": {
26714
+ capName: "recordingExport",
26715
+ capScope: "system",
26716
+ addonId: null,
26717
+ access: "view"
26718
+ },
26719
+ "recordingExport.listExports": {
26720
+ capName: "recordingExport",
26721
+ capScope: "system",
26722
+ addonId: null,
26723
+ access: "view"
26724
+ },
26386
26725
  "sceneMonitor.captureReference": {
26387
26726
  capName: "scene-monitor",
26388
26727
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -37,7 +37,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
37
37
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
39
39
  //#endregion
40
- //#region ../types/dist/event-category-H4AVePnn.mjs
40
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
41
41
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
42
42
  EventCategory["SystemBoot"] = "system.boot";
43
43
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -190,6 +190,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
190
190
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
191
191
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
192
192
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
193
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
194
+ * progress bar the client reconciles via `recordingExport.getExport`. */
195
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
196
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
197
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
193
198
  EventCategory["DetectionEvent"] = "detection.event";
194
199
  EventCategory["SessionTrackNew"] = "session.track.new";
195
200
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -479,6 +484,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
479
484
  */
480
485
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
481
486
  /**
487
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
488
+ * a package zone — a newly-appeared stationary object of a package class
489
+ * that cleared the class / zone / dwell / size gates. Payload:
490
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
491
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
492
+ * Telemetry (D8): the durable record is the `package-events` store row;
493
+ * this bus topic drives notifier rules + live UI. See
494
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
495
+ */
496
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
497
+ /**
498
+ * Fired by `addon-post-analysis` when a previously-delivered package
499
+ * leaves its zone (the stationary entry departed — moved or swept).
500
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
501
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
502
+ * Telemetry (D8). See package-zones-design §5.2.
503
+ */
504
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
505
+ /**
482
506
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
483
507
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
484
508
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5231,6 +5255,25 @@ function preprocess(fn, schema) {
5231
5255
  out: schema
5232
5256
  });
5233
5257
  }
5258
+ //#endregion
5259
+ //#region ../../node_modules/zod/v4/classic/compat.js
5260
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5261
+ var ZodIssueCode$1 = {
5262
+ invalid_type: "invalid_type",
5263
+ too_big: "too_big",
5264
+ too_small: "too_small",
5265
+ invalid_format: "invalid_format",
5266
+ not_multiple_of: "not_multiple_of",
5267
+ unrecognized_keys: "unrecognized_keys",
5268
+ invalid_union: "invalid_union",
5269
+ invalid_key: "invalid_key",
5270
+ invalid_element: "invalid_element",
5271
+ invalid_value: "invalid_value",
5272
+ custom: "custom"
5273
+ };
5274
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5275
+ var ZodFirstPartyTypeKind$1;
5276
+ ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5234
5277
  Object.fromEntries([
5235
5278
  {
5236
5279
  id: "overview",
@@ -7353,6 +7396,62 @@ var RecordingConfigSchema = object({
7353
7396
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7354
7397
  });
7355
7398
  /**
7399
+ * Ops-log — the durable, append-only operations audit shared by the
7400
+ * recordings and events management surfaces.
7401
+ *
7402
+ * ONE row shape is reused for both domains so a single "Activity" view can
7403
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7404
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7405
+ * management operation, WHY it ran (reason), and its measurable effect
7406
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7407
+ * never fail the operation it records.
7408
+ */
7409
+ /** Which management domain the operation belongs to. */
7410
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7411
+ /** The kind of management operation performed. */
7412
+ var OpsLogOpSchema = _enum([
7413
+ "prune",
7414
+ "manual-delete",
7415
+ "rescan",
7416
+ "retention-run"
7417
+ ]);
7418
+ /** Why the operation ran. */
7419
+ var OpsLogReasonSchema = _enum([
7420
+ "retention",
7421
+ "quota",
7422
+ "manual",
7423
+ "operator"
7424
+ ]);
7425
+ /** One audit row, shared verbatim by both domains. */
7426
+ var OpsLogEntrySchema = object({
7427
+ /** Unique row id. */
7428
+ id: string(),
7429
+ /** Epoch ms the operation completed. */
7430
+ at: number(),
7431
+ domain: OpsLogDomainSchema,
7432
+ op: OpsLogOpSchema,
7433
+ reason: OpsLogReasonSchema,
7434
+ /** The camera the op targeted; null for a cluster/global op. */
7435
+ deviceId: number().nullable(),
7436
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7437
+ nodeId: string(),
7438
+ /** Buckets / rows deleted (op-specific unit). */
7439
+ itemsAffected: number(),
7440
+ /** Bytes reclaimed by the op (0 when not measurable). */
7441
+ bytesReclaimed: number(),
7442
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7443
+ detail: string().nullable(),
7444
+ /** Who/what triggered the op. */
7445
+ actor: string()
7446
+ });
7447
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7448
+ var OpsLogQueryInputSchema = object({
7449
+ /** Restrict to a single camera; omit for every row. */
7450
+ deviceId: number().optional(),
7451
+ /** Max rows returned, newest-first. */
7452
+ limit: number().int().min(1).max(1e3).optional()
7453
+ });
7454
+ /**
7356
7455
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7357
7456
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7358
7457
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -14708,7 +14807,11 @@ array(ZoneRuleSchema).readonly();
14708
14807
  * Extend the enum here when a new gating consumer comes online (audio
14709
14808
  * gating, alert filtering, …) — no other surface needs to change.
14710
14809
  */
14711
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
14810
+ var ZoneRuleStageEnum = _enum([
14811
+ "motion",
14812
+ "detection",
14813
+ "package"
14814
+ ]);
14712
14815
  /**
14713
14816
  * Runtime registry: cap-property-name → cap definition. `BaseDevice`'s
14714
14817
  * `state` getter looks up the cap definition here to construct a
@@ -14802,16 +14905,25 @@ var DEVICE_LOCAL_STATE_CAPS = {
14802
14905
  })
14803
14906
  },
14804
14907
  /**
14805
- * Runtime-state slice — both stages mirrored together so consumers
14908
+ * Runtime-state slice — every stage mirrored together so consumers
14806
14909
  * see one reactive handle (`device.state.zoneRules.value`) instead
14807
- * of two. Bulk-replace mutations on either stage write the full
14808
- * `{motion, detection}` shape, so subscribers always get the
14910
+ * of one per stage. Bulk-replace mutations on any stage write the full
14911
+ * `{motion, detection, package}` shape, so subscribers always get the
14809
14912
  * complete current set. Consumers that only care about one stage
14810
14913
  * just read the matching property.
14914
+ *
14915
+ * `package` backs the package-drop detector — a package zone is a
14916
+ * `ZoneRule` on the `'package'` stage referencing drawn polygons
14917
+ * (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
14918
+ * The orchestrator provider writes this stage as a first-class slice
14919
+ * (Phase 4): every mutation mirrors the full `{motion, detection,
14920
+ * package}` shape, so consumers read the current package rules directly
14921
+ * off `device.state.zoneRules.value.package`.
14811
14922
  */
14812
14923
  runtimeState: object({
14813
14924
  motion: array(ZoneRuleSchema).readonly(),
14814
- detection: array(ZoneRuleSchema).readonly()
14925
+ detection: array(ZoneRuleSchema).readonly(),
14926
+ package: array(ZoneRuleSchema).readonly()
14815
14927
  })
14816
14928
  },
14817
14929
  zones: zonesCapability
@@ -18790,6 +18902,7 @@ var EventKindIconSchema = _enum([
18790
18902
  "smoke",
18791
18903
  "water",
18792
18904
  "button",
18905
+ "package",
18793
18906
  "generic"
18794
18907
  ]);
18795
18908
  var EventKindCategorySchema = _enum([
@@ -18797,7 +18910,8 @@ var EventKindCategorySchema = _enum([
18797
18910
  "audio",
18798
18911
  "detection",
18799
18912
  "sensor",
18800
- "custom"
18913
+ "custom",
18914
+ "package"
18801
18915
  ]);
18802
18916
  var EventKindDescriptorSchema = object({
18803
18917
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19138,6 +19252,26 @@ var TrackCascadeCountsSchema = object({
19138
19252
  /** Per-track CLIP search vectors removed (best-effort). */
19139
19253
  embeddings: number().int()
19140
19254
  });
19255
+ /** Event-store footprint for one camera. */
19256
+ var EventStoreDeviceFootprintSchema = object({
19257
+ deviceId: number(),
19258
+ /** Persisted event rows (motion + object + audio) for the camera. */
19259
+ rows: number().int(),
19260
+ /** Event-owned media bytes on disk for the camera. */
19261
+ bytes: number().int()
19262
+ });
19263
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
19264
+ var EventStoreFootprintSchema = object({
19265
+ totalRows: number().int(),
19266
+ totalBytes: number().int(),
19267
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
19268
+ });
19269
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
19270
+ var EventPruneCountsSchema = object({
19271
+ motion: number().int(),
19272
+ object: number().int(),
19273
+ audio: number().int()
19274
+ });
19141
19275
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
19142
19276
  deviceId: number(),
19143
19277
  trackId: string()
@@ -19201,6 +19335,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19201
19335
  }), {
19202
19336
  kind: "mutation",
19203
19337
  auth: "admin"
19338
+ }), method(object({}), EventStoreFootprintSchema, {
19339
+ kind: "query",
19340
+ auth: "admin"
19341
+ }), method(object({
19342
+ olderThanMs: number(),
19343
+ reason: OpsLogReasonSchema.optional()
19344
+ }), EventPruneCountsSchema, {
19345
+ kind: "mutation",
19346
+ auth: "admin"
19347
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
19348
+ kind: "mutation",
19349
+ auth: "admin"
19350
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19351
+ kind: "query",
19352
+ auth: "admin"
19204
19353
  }), method(object({
19205
19354
  eventId: string(),
19206
19355
  kind: MediaFileKindEnum.optional()
@@ -22451,13 +22600,131 @@ method(object({
22451
22600
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
22452
22601
  kind: "mutation",
22453
22602
  auth: "admin"
22454
- }), method(object({ deviceId: number() }), object({
22603
+ }), method(object({
22604
+ deviceId: number(),
22605
+ reason: OpsLogReasonSchema.optional()
22606
+ }), object({
22455
22607
  floorMs: number().nullable(),
22456
22608
  deletedBuckets: number().int(),
22457
22609
  reclaimedBytes: number().int()
22458
22610
  }), {
22459
22611
  kind: "mutation",
22460
22612
  auth: "admin"
22613
+ }), method(object({
22614
+ deviceId: number(),
22615
+ fromMs: number().optional(),
22616
+ toMs: number().optional()
22617
+ }), object({
22618
+ deletedBuckets: number().int(),
22619
+ reclaimedBytes: number().int()
22620
+ }), {
22621
+ kind: "mutation",
22622
+ auth: "admin"
22623
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
22624
+ kind: "query",
22625
+ auth: "admin"
22626
+ });
22627
+ /**
22628
+ * `recordingExport` cap — render a footage time range into a single downloadable
22629
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
22630
+ * bounded lifetime with a durable history, auto-expiry, and optional
22631
+ * delete-after-download.
22632
+ *
22633
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
22634
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
22635
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
22636
+ * input and dispatch to that single provider; the render runs on the node that
22637
+ * owns the footage (no cross-node segment transfer). Download rides the
22638
+ * framework addon data-plane. State persists in a DurableState blob (NOT
22639
+ * SQLite); history rows survive file deletion for audit.
22640
+ */
22641
+ /** Playback-speed multiplier for the render (1 = realtime). */
22642
+ var ExportSpeedSchema = number().min(.25).max(32);
22643
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
22644
+ var ExportTimelapseSchema = object({
22645
+ everyMs: number().int().positive(),
22646
+ outputFps: number().int().min(1).max(60).optional()
22647
+ });
22648
+ /**
22649
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
22650
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
22651
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
22652
+ * `deleteAfterDownload` removes it shortly after the first complete download.
22653
+ */
22654
+ var ExportOptionsSchema = object({
22655
+ speed: ExportSpeedSchema.optional(),
22656
+ timelapse: ExportTimelapseSchema.optional(),
22657
+ includeAudio: boolean(),
22658
+ maxLifeMs: number().int().positive(),
22659
+ deleteAfterDownload: boolean(),
22660
+ title: string().max(200).optional()
22661
+ }).superRefine((v, ctx) => {
22662
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
22663
+ code: ZodIssueCode$1.custom,
22664
+ message: "speed and timelapse are mutually exclusive",
22665
+ path: ["timelapse"]
22666
+ });
22667
+ });
22668
+ var ExportStateSchema = _enum([
22669
+ "queued",
22670
+ "rendering",
22671
+ "ready",
22672
+ "failed",
22673
+ "expired",
22674
+ "deleted"
22675
+ ]);
22676
+ /** One export job / history row. */
22677
+ var ExportRecordSchema = object({
22678
+ id: string(),
22679
+ deviceId: number(),
22680
+ profile: string(),
22681
+ fromMs: number(),
22682
+ toMs: number(),
22683
+ options: ExportOptionsSchema,
22684
+ state: ExportStateSchema,
22685
+ /** 0–100 while rendering; null otherwise. */
22686
+ progressPct: number().nullable(),
22687
+ /** File size once ready; null before. */
22688
+ fileBytes: number().nullable(),
22689
+ expiresAt: number(),
22690
+ deleteAfterDownload: boolean(),
22691
+ /** Epoch of the first complete download; null until then. */
22692
+ downloadedAt: number().nullable(),
22693
+ createdAt: number(),
22694
+ /** User id/name that requested the export. */
22695
+ createdBy: string(),
22696
+ /** Failure reason when state is 'failed'; null otherwise. */
22697
+ error: string().nullable()
22698
+ });
22699
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
22700
+ var ExportDownloadSchema = object({
22701
+ url: string(),
22702
+ endpoints: array(string())
22703
+ });
22704
+ method(object({
22705
+ deviceId: number(),
22706
+ profile: string(),
22707
+ fromMs: number(),
22708
+ toMs: number(),
22709
+ options: ExportOptionsSchema
22710
+ }), ExportRecordSchema, {
22711
+ kind: "mutation",
22712
+ auth: "protected"
22713
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
22714
+ kind: "query",
22715
+ auth: "protected"
22716
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22717
+ kind: "query",
22718
+ auth: "protected"
22719
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22720
+ kind: "mutation",
22721
+ auth: "protected"
22722
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
22723
+ kind: "mutation",
22724
+ auth: "protected"
22725
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
22726
+ kind: "query",
22727
+ auth: "protected"
22461
22728
  });
22462
22729
  /**
22463
22730
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -25477,6 +25744,12 @@ Object.freeze({
25477
25744
  addonId: null,
25478
25745
  access: "delete"
25479
25746
  },
25747
+ "pipelineAnalytics.deleteDeviceEvents": {
25748
+ capName: "pipeline-analytics",
25749
+ capScope: "device",
25750
+ addonId: null,
25751
+ access: "delete"
25752
+ },
25480
25753
  "pipelineAnalytics.deleteTracks": {
25481
25754
  capName: "pipeline-analytics",
25482
25755
  capScope: "device",
@@ -25507,6 +25780,12 @@ Object.freeze({
25507
25780
  addonId: null,
25508
25781
  access: "view"
25509
25782
  },
25783
+ "pipelineAnalytics.getEventStoreFootprint": {
25784
+ capName: "pipeline-analytics",
25785
+ capScope: "device",
25786
+ addonId: null,
25787
+ access: "view"
25788
+ },
25510
25789
  "pipelineAnalytics.getKeyEvents": {
25511
25790
  capName: "pipeline-analytics",
25512
25791
  capScope: "device",
@@ -25549,6 +25828,12 @@ Object.freeze({
25549
25828
  addonId: null,
25550
25829
  access: "view"
25551
25830
  },
25831
+ "pipelineAnalytics.listOpsLog": {
25832
+ capName: "pipeline-analytics",
25833
+ capScope: "device",
25834
+ addonId: null,
25835
+ access: "view"
25836
+ },
25552
25837
  "pipelineAnalytics.listRecentTracks": {
25553
25838
  capName: "pipeline-analytics",
25554
25839
  capScope: "device",
@@ -25561,6 +25846,12 @@ Object.freeze({
25561
25846
  addonId: null,
25562
25847
  access: "view"
25563
25848
  },
25849
+ "pipelineAnalytics.pruneEvents": {
25850
+ capName: "pipeline-analytics",
25851
+ capScope: "device",
25852
+ addonId: null,
25853
+ access: "create"
25854
+ },
25564
25855
  "pipelineAnalytics.pruneEventsBefore": {
25565
25856
  capName: "pipeline-analytics",
25566
25857
  capScope: "device",
@@ -26323,6 +26614,12 @@ Object.freeze({
26323
26614
  addonId: null,
26324
26615
  access: "create"
26325
26616
  },
26617
+ "recording.deleteFootprint": {
26618
+ capName: "recording",
26619
+ capScope: "system",
26620
+ addonId: null,
26621
+ access: "delete"
26622
+ },
26326
26623
  "recording.getAvailability": {
26327
26624
  capName: "recording",
26328
26625
  capScope: "system",
@@ -26353,6 +26650,12 @@ Object.freeze({
26353
26650
  addonId: null,
26354
26651
  access: "view"
26355
26652
  },
26653
+ "recording.listOpsLog": {
26654
+ capName: "recording",
26655
+ capScope: "system",
26656
+ addonId: null,
26657
+ access: "view"
26658
+ },
26356
26659
  "recording.locateSegment": {
26357
26660
  capName: "recording",
26358
26661
  capScope: "system",
@@ -26383,6 +26686,42 @@ Object.freeze({
26383
26686
  addonId: null,
26384
26687
  access: "create"
26385
26688
  },
26689
+ "recordingExport.cancelExport": {
26690
+ capName: "recordingExport",
26691
+ capScope: "system",
26692
+ addonId: null,
26693
+ access: "create"
26694
+ },
26695
+ "recordingExport.createExport": {
26696
+ capName: "recordingExport",
26697
+ capScope: "system",
26698
+ addonId: null,
26699
+ access: "create"
26700
+ },
26701
+ "recordingExport.deleteExport": {
26702
+ capName: "recordingExport",
26703
+ capScope: "system",
26704
+ addonId: null,
26705
+ access: "delete"
26706
+ },
26707
+ "recordingExport.getDownloadUrl": {
26708
+ capName: "recordingExport",
26709
+ capScope: "system",
26710
+ addonId: null,
26711
+ access: "view"
26712
+ },
26713
+ "recordingExport.getExport": {
26714
+ capName: "recordingExport",
26715
+ capScope: "system",
26716
+ addonId: null,
26717
+ access: "view"
26718
+ },
26719
+ "recordingExport.listExports": {
26720
+ capName: "recordingExport",
26721
+ capScope: "system",
26722
+ addonId: null,
26723
+ access: "view"
26724
+ },
26386
26725
  "sceneMonitor.captureReference": {
26387
26726
  capName: "scene-monitor",
26388
26727
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
5
5
  "keywords": [
6
6
  "camstack",