@camstack/addon-advanced-notifier 1.1.27 → 1.1.29

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
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  let node_crypto = require("node:crypto");
6
- //#region ../types/dist/event-category-H4AVePnn.mjs
6
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
7
7
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
8
8
  EventCategory["SystemBoot"] = "system.boot";
9
9
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -156,6 +156,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
156
156
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
157
157
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
158
158
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
159
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
160
+ * progress bar the client reconciles via `recordingExport.getExport`. */
161
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
162
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
163
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
159
164
  EventCategory["DetectionEvent"] = "detection.event";
160
165
  EventCategory["SessionTrackNew"] = "session.track.new";
161
166
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -445,6 +450,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
445
450
  */
446
451
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
447
452
  /**
453
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
454
+ * a package zone — a newly-appeared stationary object of a package class
455
+ * that cleared the class / zone / dwell / size gates. Payload:
456
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
457
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
458
+ * Telemetry (D8): the durable record is the `package-events` store row;
459
+ * this bus topic drives notifier rules + live UI. See
460
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
461
+ */
462
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
463
+ /**
464
+ * Fired by `addon-post-analysis` when a previously-delivered package
465
+ * leaves its zone (the stationary entry departed — moved or swept).
466
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
467
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
468
+ * Telemetry (D8). See package-zones-design §5.2.
469
+ */
470
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
471
+ /**
448
472
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
449
473
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
450
474
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5183,6 +5207,25 @@ function _instanceof(cls, params = {}) {
5183
5207
  };
5184
5208
  return inst;
5185
5209
  }
5210
+ //#endregion
5211
+ //#region ../../node_modules/zod/v4/classic/compat.js
5212
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5213
+ var ZodIssueCode = {
5214
+ invalid_type: "invalid_type",
5215
+ too_big: "too_big",
5216
+ too_small: "too_small",
5217
+ invalid_format: "invalid_format",
5218
+ not_multiple_of: "not_multiple_of",
5219
+ unrecognized_keys: "unrecognized_keys",
5220
+ invalid_union: "invalid_union",
5221
+ invalid_key: "invalid_key",
5222
+ invalid_element: "invalid_element",
5223
+ invalid_value: "invalid_value",
5224
+ custom: "custom"
5225
+ };
5226
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5227
+ var ZodFirstPartyTypeKind;
5228
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5186
5229
  Object.fromEntries([
5187
5230
  {
5188
5231
  id: "overview",
@@ -7289,6 +7332,62 @@ var RecordingConfigSchema = object({
7289
7332
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7290
7333
  });
7291
7334
  /**
7335
+ * Ops-log — the durable, append-only operations audit shared by the
7336
+ * recordings and events management surfaces.
7337
+ *
7338
+ * ONE row shape is reused for both domains so a single "Activity" view can
7339
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7340
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7341
+ * management operation, WHY it ran (reason), and its measurable effect
7342
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7343
+ * never fail the operation it records.
7344
+ */
7345
+ /** Which management domain the operation belongs to. */
7346
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7347
+ /** The kind of management operation performed. */
7348
+ var OpsLogOpSchema = _enum([
7349
+ "prune",
7350
+ "manual-delete",
7351
+ "rescan",
7352
+ "retention-run"
7353
+ ]);
7354
+ /** Why the operation ran. */
7355
+ var OpsLogReasonSchema = _enum([
7356
+ "retention",
7357
+ "quota",
7358
+ "manual",
7359
+ "operator"
7360
+ ]);
7361
+ /** One audit row, shared verbatim by both domains. */
7362
+ var OpsLogEntrySchema = object({
7363
+ /** Unique row id. */
7364
+ id: string(),
7365
+ /** Epoch ms the operation completed. */
7366
+ at: number(),
7367
+ domain: OpsLogDomainSchema,
7368
+ op: OpsLogOpSchema,
7369
+ reason: OpsLogReasonSchema,
7370
+ /** The camera the op targeted; null for a cluster/global op. */
7371
+ deviceId: number().nullable(),
7372
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7373
+ nodeId: string(),
7374
+ /** Buckets / rows deleted (op-specific unit). */
7375
+ itemsAffected: number(),
7376
+ /** Bytes reclaimed by the op (0 when not measurable). */
7377
+ bytesReclaimed: number(),
7378
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7379
+ detail: string().nullable(),
7380
+ /** Who/what triggered the op. */
7381
+ actor: string()
7382
+ });
7383
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7384
+ var OpsLogQueryInputSchema = object({
7385
+ /** Restrict to a single camera; omit for every row. */
7386
+ deviceId: number().optional(),
7387
+ /** Max rows returned, newest-first. */
7388
+ limit: number().int().min(1).max(1e3).optional()
7389
+ });
7390
+ /**
7292
7391
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7293
7392
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7294
7393
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12552,7 +12651,11 @@ array(ZoneRuleSchema).readonly();
12552
12651
  * Extend the enum here when a new gating consumer comes online (audio
12553
12652
  * gating, alert filtering, …) — no other surface needs to change.
12554
12653
  */
12555
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12654
+ var ZoneRuleStageEnum = _enum([
12655
+ "motion",
12656
+ "detection",
12657
+ "package"
12658
+ ]);
12556
12659
  DeviceType.Camera, method(object({
12557
12660
  deviceId: number(),
12558
12661
  stage: ZoneRuleStageEnum
@@ -12565,7 +12668,8 @@ DeviceType.Camera, method(object({
12565
12668
  auth: "admin"
12566
12669
  }), object({
12567
12670
  motion: array(ZoneRuleSchema).readonly(),
12568
- detection: array(ZoneRuleSchema).readonly()
12671
+ detection: array(ZoneRuleSchema).readonly(),
12672
+ package: array(ZoneRuleSchema).readonly()
12569
12673
  });
12570
12674
  var ProviderStatusSchema = object({
12571
12675
  connected: boolean(),
@@ -15774,6 +15878,7 @@ var EventKindIconSchema = _enum([
15774
15878
  "smoke",
15775
15879
  "water",
15776
15880
  "button",
15881
+ "package",
15777
15882
  "generic"
15778
15883
  ]);
15779
15884
  var EventKindCategorySchema = _enum([
@@ -15781,7 +15886,8 @@ var EventKindCategorySchema = _enum([
15781
15886
  "audio",
15782
15887
  "detection",
15783
15888
  "sensor",
15784
- "custom"
15889
+ "custom",
15890
+ "package"
15785
15891
  ]);
15786
15892
  var EventKindDescriptorSchema = object({
15787
15893
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16122,6 +16228,26 @@ var TrackCascadeCountsSchema = object({
16122
16228
  /** Per-track CLIP search vectors removed (best-effort). */
16123
16229
  embeddings: number().int()
16124
16230
  });
16231
+ /** Event-store footprint for one camera. */
16232
+ var EventStoreDeviceFootprintSchema = object({
16233
+ deviceId: number(),
16234
+ /** Persisted event rows (motion + object + audio) for the camera. */
16235
+ rows: number().int(),
16236
+ /** Event-owned media bytes on disk for the camera. */
16237
+ bytes: number().int()
16238
+ });
16239
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16240
+ var EventStoreFootprintSchema = object({
16241
+ totalRows: number().int(),
16242
+ totalBytes: number().int(),
16243
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16244
+ });
16245
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16246
+ var EventPruneCountsSchema = object({
16247
+ motion: number().int(),
16248
+ object: number().int(),
16249
+ audio: number().int()
16250
+ });
16125
16251
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16126
16252
  deviceId: number(),
16127
16253
  trackId: string()
@@ -16185,6 +16311,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16185
16311
  }), {
16186
16312
  kind: "mutation",
16187
16313
  auth: "admin"
16314
+ }), method(object({}), EventStoreFootprintSchema, {
16315
+ kind: "query",
16316
+ auth: "admin"
16317
+ }), method(object({
16318
+ olderThanMs: number(),
16319
+ reason: OpsLogReasonSchema.optional()
16320
+ }), EventPruneCountsSchema, {
16321
+ kind: "mutation",
16322
+ auth: "admin"
16323
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16324
+ kind: "mutation",
16325
+ auth: "admin"
16326
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16327
+ kind: "query",
16328
+ auth: "admin"
16188
16329
  }), method(object({
16189
16330
  eventId: string(),
16190
16331
  kind: MediaFileKindEnum.optional()
@@ -19418,13 +19559,131 @@ method(object({
19418
19559
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19419
19560
  kind: "mutation",
19420
19561
  auth: "admin"
19421
- }), method(object({ deviceId: number() }), object({
19562
+ }), method(object({
19563
+ deviceId: number(),
19564
+ reason: OpsLogReasonSchema.optional()
19565
+ }), object({
19422
19566
  floorMs: number().nullable(),
19423
19567
  deletedBuckets: number().int(),
19424
19568
  reclaimedBytes: number().int()
19425
19569
  }), {
19426
19570
  kind: "mutation",
19427
19571
  auth: "admin"
19572
+ }), method(object({
19573
+ deviceId: number(),
19574
+ fromMs: number().optional(),
19575
+ toMs: number().optional()
19576
+ }), object({
19577
+ deletedBuckets: number().int(),
19578
+ reclaimedBytes: number().int()
19579
+ }), {
19580
+ kind: "mutation",
19581
+ auth: "admin"
19582
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19583
+ kind: "query",
19584
+ auth: "admin"
19585
+ });
19586
+ /**
19587
+ * `recordingExport` cap — render a footage time range into a single downloadable
19588
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19589
+ * bounded lifetime with a durable history, auto-expiry, and optional
19590
+ * delete-after-download.
19591
+ *
19592
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19593
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19594
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19595
+ * input and dispatch to that single provider; the render runs on the node that
19596
+ * owns the footage (no cross-node segment transfer). Download rides the
19597
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19598
+ * SQLite); history rows survive file deletion for audit.
19599
+ */
19600
+ /** Playback-speed multiplier for the render (1 = realtime). */
19601
+ var ExportSpeedSchema = number().min(.25).max(32);
19602
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19603
+ var ExportTimelapseSchema = object({
19604
+ everyMs: number().int().positive(),
19605
+ outputFps: number().int().min(1).max(60).optional()
19606
+ });
19607
+ /**
19608
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19609
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19610
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19611
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19612
+ */
19613
+ var ExportOptionsSchema = object({
19614
+ speed: ExportSpeedSchema.optional(),
19615
+ timelapse: ExportTimelapseSchema.optional(),
19616
+ includeAudio: boolean(),
19617
+ maxLifeMs: number().int().positive(),
19618
+ deleteAfterDownload: boolean(),
19619
+ title: string().max(200).optional()
19620
+ }).superRefine((v, ctx) => {
19621
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19622
+ code: ZodIssueCode.custom,
19623
+ message: "speed and timelapse are mutually exclusive",
19624
+ path: ["timelapse"]
19625
+ });
19626
+ });
19627
+ var ExportStateSchema = _enum([
19628
+ "queued",
19629
+ "rendering",
19630
+ "ready",
19631
+ "failed",
19632
+ "expired",
19633
+ "deleted"
19634
+ ]);
19635
+ /** One export job / history row. */
19636
+ var ExportRecordSchema = object({
19637
+ id: string(),
19638
+ deviceId: number(),
19639
+ profile: string(),
19640
+ fromMs: number(),
19641
+ toMs: number(),
19642
+ options: ExportOptionsSchema,
19643
+ state: ExportStateSchema,
19644
+ /** 0–100 while rendering; null otherwise. */
19645
+ progressPct: number().nullable(),
19646
+ /** File size once ready; null before. */
19647
+ fileBytes: number().nullable(),
19648
+ expiresAt: number(),
19649
+ deleteAfterDownload: boolean(),
19650
+ /** Epoch of the first complete download; null until then. */
19651
+ downloadedAt: number().nullable(),
19652
+ createdAt: number(),
19653
+ /** User id/name that requested the export. */
19654
+ createdBy: string(),
19655
+ /** Failure reason when state is 'failed'; null otherwise. */
19656
+ error: string().nullable()
19657
+ });
19658
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19659
+ var ExportDownloadSchema = object({
19660
+ url: string(),
19661
+ endpoints: array(string())
19662
+ });
19663
+ method(object({
19664
+ deviceId: number(),
19665
+ profile: string(),
19666
+ fromMs: number(),
19667
+ toMs: number(),
19668
+ options: ExportOptionsSchema
19669
+ }), ExportRecordSchema, {
19670
+ kind: "mutation",
19671
+ auth: "protected"
19672
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19673
+ kind: "query",
19674
+ auth: "protected"
19675
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19676
+ kind: "query",
19677
+ auth: "protected"
19678
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19679
+ kind: "mutation",
19680
+ auth: "protected"
19681
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19682
+ kind: "mutation",
19683
+ auth: "protected"
19684
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19685
+ kind: "query",
19686
+ auth: "protected"
19428
19687
  });
19429
19688
  /**
19430
19689
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22444,6 +22703,12 @@ Object.freeze({
22444
22703
  addonId: null,
22445
22704
  access: "delete"
22446
22705
  },
22706
+ "pipelineAnalytics.deleteDeviceEvents": {
22707
+ capName: "pipeline-analytics",
22708
+ capScope: "device",
22709
+ addonId: null,
22710
+ access: "delete"
22711
+ },
22447
22712
  "pipelineAnalytics.deleteTracks": {
22448
22713
  capName: "pipeline-analytics",
22449
22714
  capScope: "device",
@@ -22474,6 +22739,12 @@ Object.freeze({
22474
22739
  addonId: null,
22475
22740
  access: "view"
22476
22741
  },
22742
+ "pipelineAnalytics.getEventStoreFootprint": {
22743
+ capName: "pipeline-analytics",
22744
+ capScope: "device",
22745
+ addonId: null,
22746
+ access: "view"
22747
+ },
22477
22748
  "pipelineAnalytics.getKeyEvents": {
22478
22749
  capName: "pipeline-analytics",
22479
22750
  capScope: "device",
@@ -22516,6 +22787,12 @@ Object.freeze({
22516
22787
  addonId: null,
22517
22788
  access: "view"
22518
22789
  },
22790
+ "pipelineAnalytics.listOpsLog": {
22791
+ capName: "pipeline-analytics",
22792
+ capScope: "device",
22793
+ addonId: null,
22794
+ access: "view"
22795
+ },
22519
22796
  "pipelineAnalytics.listRecentTracks": {
22520
22797
  capName: "pipeline-analytics",
22521
22798
  capScope: "device",
@@ -22528,6 +22805,12 @@ Object.freeze({
22528
22805
  addonId: null,
22529
22806
  access: "view"
22530
22807
  },
22808
+ "pipelineAnalytics.pruneEvents": {
22809
+ capName: "pipeline-analytics",
22810
+ capScope: "device",
22811
+ addonId: null,
22812
+ access: "create"
22813
+ },
22531
22814
  "pipelineAnalytics.pruneEventsBefore": {
22532
22815
  capName: "pipeline-analytics",
22533
22816
  capScope: "device",
@@ -23290,6 +23573,12 @@ Object.freeze({
23290
23573
  addonId: null,
23291
23574
  access: "create"
23292
23575
  },
23576
+ "recording.deleteFootprint": {
23577
+ capName: "recording",
23578
+ capScope: "system",
23579
+ addonId: null,
23580
+ access: "delete"
23581
+ },
23293
23582
  "recording.getAvailability": {
23294
23583
  capName: "recording",
23295
23584
  capScope: "system",
@@ -23320,6 +23609,12 @@ Object.freeze({
23320
23609
  addonId: null,
23321
23610
  access: "view"
23322
23611
  },
23612
+ "recording.listOpsLog": {
23613
+ capName: "recording",
23614
+ capScope: "system",
23615
+ addonId: null,
23616
+ access: "view"
23617
+ },
23323
23618
  "recording.locateSegment": {
23324
23619
  capName: "recording",
23325
23620
  capScope: "system",
@@ -23350,6 +23645,42 @@ Object.freeze({
23350
23645
  addonId: null,
23351
23646
  access: "create"
23352
23647
  },
23648
+ "recordingExport.cancelExport": {
23649
+ capName: "recordingExport",
23650
+ capScope: "system",
23651
+ addonId: null,
23652
+ access: "create"
23653
+ },
23654
+ "recordingExport.createExport": {
23655
+ capName: "recordingExport",
23656
+ capScope: "system",
23657
+ addonId: null,
23658
+ access: "create"
23659
+ },
23660
+ "recordingExport.deleteExport": {
23661
+ capName: "recordingExport",
23662
+ capScope: "system",
23663
+ addonId: null,
23664
+ access: "delete"
23665
+ },
23666
+ "recordingExport.getDownloadUrl": {
23667
+ capName: "recordingExport",
23668
+ capScope: "system",
23669
+ addonId: null,
23670
+ access: "view"
23671
+ },
23672
+ "recordingExport.getExport": {
23673
+ capName: "recordingExport",
23674
+ capScope: "system",
23675
+ addonId: null,
23676
+ access: "view"
23677
+ },
23678
+ "recordingExport.listExports": {
23679
+ capName: "recordingExport",
23680
+ capScope: "system",
23681
+ addonId: null,
23682
+ access: "view"
23683
+ },
23353
23684
  "sceneMonitor.captureReference": {
23354
23685
  capName: "scene-monitor",
23355
23686
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
- //#region ../types/dist/event-category-H4AVePnn.mjs
2
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -152,6 +152,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
152
152
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
153
153
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
154
154
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
155
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
156
+ * progress bar the client reconciles via `recordingExport.getExport`. */
157
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
158
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
159
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
155
160
  EventCategory["DetectionEvent"] = "detection.event";
156
161
  EventCategory["SessionTrackNew"] = "session.track.new";
157
162
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -441,6 +446,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
441
446
  */
442
447
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
443
448
  /**
449
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
450
+ * a package zone — a newly-appeared stationary object of a package class
451
+ * that cleared the class / zone / dwell / size gates. Payload:
452
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
453
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
454
+ * Telemetry (D8): the durable record is the `package-events` store row;
455
+ * this bus topic drives notifier rules + live UI. See
456
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
457
+ */
458
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
459
+ /**
460
+ * Fired by `addon-post-analysis` when a previously-delivered package
461
+ * leaves its zone (the stationary entry departed — moved or swept).
462
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
463
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
464
+ * Telemetry (D8). See package-zones-design §5.2.
465
+ */
466
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
467
+ /**
444
468
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
445
469
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
446
470
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5179,6 +5203,25 @@ function _instanceof(cls, params = {}) {
5179
5203
  };
5180
5204
  return inst;
5181
5205
  }
5206
+ //#endregion
5207
+ //#region ../../node_modules/zod/v4/classic/compat.js
5208
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5209
+ var ZodIssueCode = {
5210
+ invalid_type: "invalid_type",
5211
+ too_big: "too_big",
5212
+ too_small: "too_small",
5213
+ invalid_format: "invalid_format",
5214
+ not_multiple_of: "not_multiple_of",
5215
+ unrecognized_keys: "unrecognized_keys",
5216
+ invalid_union: "invalid_union",
5217
+ invalid_key: "invalid_key",
5218
+ invalid_element: "invalid_element",
5219
+ invalid_value: "invalid_value",
5220
+ custom: "custom"
5221
+ };
5222
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5223
+ var ZodFirstPartyTypeKind;
5224
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5182
5225
  Object.fromEntries([
5183
5226
  {
5184
5227
  id: "overview",
@@ -7285,6 +7328,62 @@ var RecordingConfigSchema = object({
7285
7328
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7286
7329
  });
7287
7330
  /**
7331
+ * Ops-log — the durable, append-only operations audit shared by the
7332
+ * recordings and events management surfaces.
7333
+ *
7334
+ * ONE row shape is reused for both domains so a single "Activity" view can
7335
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7336
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7337
+ * management operation, WHY it ran (reason), and its measurable effect
7338
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7339
+ * never fail the operation it records.
7340
+ */
7341
+ /** Which management domain the operation belongs to. */
7342
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7343
+ /** The kind of management operation performed. */
7344
+ var OpsLogOpSchema = _enum([
7345
+ "prune",
7346
+ "manual-delete",
7347
+ "rescan",
7348
+ "retention-run"
7349
+ ]);
7350
+ /** Why the operation ran. */
7351
+ var OpsLogReasonSchema = _enum([
7352
+ "retention",
7353
+ "quota",
7354
+ "manual",
7355
+ "operator"
7356
+ ]);
7357
+ /** One audit row, shared verbatim by both domains. */
7358
+ var OpsLogEntrySchema = object({
7359
+ /** Unique row id. */
7360
+ id: string(),
7361
+ /** Epoch ms the operation completed. */
7362
+ at: number(),
7363
+ domain: OpsLogDomainSchema,
7364
+ op: OpsLogOpSchema,
7365
+ reason: OpsLogReasonSchema,
7366
+ /** The camera the op targeted; null for a cluster/global op. */
7367
+ deviceId: number().nullable(),
7368
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7369
+ nodeId: string(),
7370
+ /** Buckets / rows deleted (op-specific unit). */
7371
+ itemsAffected: number(),
7372
+ /** Bytes reclaimed by the op (0 when not measurable). */
7373
+ bytesReclaimed: number(),
7374
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7375
+ detail: string().nullable(),
7376
+ /** Who/what triggered the op. */
7377
+ actor: string()
7378
+ });
7379
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7380
+ var OpsLogQueryInputSchema = object({
7381
+ /** Restrict to a single camera; omit for every row. */
7382
+ deviceId: number().optional(),
7383
+ /** Max rows returned, newest-first. */
7384
+ limit: number().int().min(1).max(1e3).optional()
7385
+ });
7386
+ /**
7288
7387
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7289
7388
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7290
7389
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -12548,7 +12647,11 @@ array(ZoneRuleSchema).readonly();
12548
12647
  * Extend the enum here when a new gating consumer comes online (audio
12549
12648
  * gating, alert filtering, …) — no other surface needs to change.
12550
12649
  */
12551
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12650
+ var ZoneRuleStageEnum = _enum([
12651
+ "motion",
12652
+ "detection",
12653
+ "package"
12654
+ ]);
12552
12655
  DeviceType.Camera, method(object({
12553
12656
  deviceId: number(),
12554
12657
  stage: ZoneRuleStageEnum
@@ -12561,7 +12664,8 @@ DeviceType.Camera, method(object({
12561
12664
  auth: "admin"
12562
12665
  }), object({
12563
12666
  motion: array(ZoneRuleSchema).readonly(),
12564
- detection: array(ZoneRuleSchema).readonly()
12667
+ detection: array(ZoneRuleSchema).readonly(),
12668
+ package: array(ZoneRuleSchema).readonly()
12565
12669
  });
12566
12670
  var ProviderStatusSchema = object({
12567
12671
  connected: boolean(),
@@ -15770,6 +15874,7 @@ var EventKindIconSchema = _enum([
15770
15874
  "smoke",
15771
15875
  "water",
15772
15876
  "button",
15877
+ "package",
15773
15878
  "generic"
15774
15879
  ]);
15775
15880
  var EventKindCategorySchema = _enum([
@@ -15777,7 +15882,8 @@ var EventKindCategorySchema = _enum([
15777
15882
  "audio",
15778
15883
  "detection",
15779
15884
  "sensor",
15780
- "custom"
15885
+ "custom",
15886
+ "package"
15781
15887
  ]);
15782
15888
  var EventKindDescriptorSchema = object({
15783
15889
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -16118,6 +16224,26 @@ var TrackCascadeCountsSchema = object({
16118
16224
  /** Per-track CLIP search vectors removed (best-effort). */
16119
16225
  embeddings: number().int()
16120
16226
  });
16227
+ /** Event-store footprint for one camera. */
16228
+ var EventStoreDeviceFootprintSchema = object({
16229
+ deviceId: number(),
16230
+ /** Persisted event rows (motion + object + audio) for the camera. */
16231
+ rows: number().int(),
16232
+ /** Event-owned media bytes on disk for the camera. */
16233
+ bytes: number().int()
16234
+ });
16235
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
16236
+ var EventStoreFootprintSchema = object({
16237
+ totalRows: number().int(),
16238
+ totalBytes: number().int(),
16239
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
16240
+ });
16241
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
16242
+ var EventPruneCountsSchema = object({
16243
+ motion: number().int(),
16244
+ object: number().int(),
16245
+ audio: number().int()
16246
+ });
16121
16247
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
16122
16248
  deviceId: number(),
16123
16249
  trackId: string()
@@ -16181,6 +16307,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
16181
16307
  }), {
16182
16308
  kind: "mutation",
16183
16309
  auth: "admin"
16310
+ }), method(object({}), EventStoreFootprintSchema, {
16311
+ kind: "query",
16312
+ auth: "admin"
16313
+ }), method(object({
16314
+ olderThanMs: number(),
16315
+ reason: OpsLogReasonSchema.optional()
16316
+ }), EventPruneCountsSchema, {
16317
+ kind: "mutation",
16318
+ auth: "admin"
16319
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
16320
+ kind: "mutation",
16321
+ auth: "admin"
16322
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
16323
+ kind: "query",
16324
+ auth: "admin"
16184
16325
  }), method(object({
16185
16326
  eventId: string(),
16186
16327
  kind: MediaFileKindEnum.optional()
@@ -19414,13 +19555,131 @@ method(object({
19414
19555
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
19415
19556
  kind: "mutation",
19416
19557
  auth: "admin"
19417
- }), method(object({ deviceId: number() }), object({
19558
+ }), method(object({
19559
+ deviceId: number(),
19560
+ reason: OpsLogReasonSchema.optional()
19561
+ }), object({
19418
19562
  floorMs: number().nullable(),
19419
19563
  deletedBuckets: number().int(),
19420
19564
  reclaimedBytes: number().int()
19421
19565
  }), {
19422
19566
  kind: "mutation",
19423
19567
  auth: "admin"
19568
+ }), method(object({
19569
+ deviceId: number(),
19570
+ fromMs: number().optional(),
19571
+ toMs: number().optional()
19572
+ }), object({
19573
+ deletedBuckets: number().int(),
19574
+ reclaimedBytes: number().int()
19575
+ }), {
19576
+ kind: "mutation",
19577
+ auth: "admin"
19578
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19579
+ kind: "query",
19580
+ auth: "admin"
19581
+ });
19582
+ /**
19583
+ * `recordingExport` cap — render a footage time range into a single downloadable
19584
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19585
+ * bounded lifetime with a durable history, auto-expiry, and optional
19586
+ * delete-after-download.
19587
+ *
19588
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19589
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19590
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19591
+ * input and dispatch to that single provider; the render runs on the node that
19592
+ * owns the footage (no cross-node segment transfer). Download rides the
19593
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19594
+ * SQLite); history rows survive file deletion for audit.
19595
+ */
19596
+ /** Playback-speed multiplier for the render (1 = realtime). */
19597
+ var ExportSpeedSchema = number().min(.25).max(32);
19598
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19599
+ var ExportTimelapseSchema = object({
19600
+ everyMs: number().int().positive(),
19601
+ outputFps: number().int().min(1).max(60).optional()
19602
+ });
19603
+ /**
19604
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19605
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19606
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19607
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19608
+ */
19609
+ var ExportOptionsSchema = object({
19610
+ speed: ExportSpeedSchema.optional(),
19611
+ timelapse: ExportTimelapseSchema.optional(),
19612
+ includeAudio: boolean(),
19613
+ maxLifeMs: number().int().positive(),
19614
+ deleteAfterDownload: boolean(),
19615
+ title: string().max(200).optional()
19616
+ }).superRefine((v, ctx) => {
19617
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19618
+ code: ZodIssueCode.custom,
19619
+ message: "speed and timelapse are mutually exclusive",
19620
+ path: ["timelapse"]
19621
+ });
19622
+ });
19623
+ var ExportStateSchema = _enum([
19624
+ "queued",
19625
+ "rendering",
19626
+ "ready",
19627
+ "failed",
19628
+ "expired",
19629
+ "deleted"
19630
+ ]);
19631
+ /** One export job / history row. */
19632
+ var ExportRecordSchema = object({
19633
+ id: string(),
19634
+ deviceId: number(),
19635
+ profile: string(),
19636
+ fromMs: number(),
19637
+ toMs: number(),
19638
+ options: ExportOptionsSchema,
19639
+ state: ExportStateSchema,
19640
+ /** 0–100 while rendering; null otherwise. */
19641
+ progressPct: number().nullable(),
19642
+ /** File size once ready; null before. */
19643
+ fileBytes: number().nullable(),
19644
+ expiresAt: number(),
19645
+ deleteAfterDownload: boolean(),
19646
+ /** Epoch of the first complete download; null until then. */
19647
+ downloadedAt: number().nullable(),
19648
+ createdAt: number(),
19649
+ /** User id/name that requested the export. */
19650
+ createdBy: string(),
19651
+ /** Failure reason when state is 'failed'; null otherwise. */
19652
+ error: string().nullable()
19653
+ });
19654
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19655
+ var ExportDownloadSchema = object({
19656
+ url: string(),
19657
+ endpoints: array(string())
19658
+ });
19659
+ method(object({
19660
+ deviceId: number(),
19661
+ profile: string(),
19662
+ fromMs: number(),
19663
+ toMs: number(),
19664
+ options: ExportOptionsSchema
19665
+ }), ExportRecordSchema, {
19666
+ kind: "mutation",
19667
+ auth: "protected"
19668
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19669
+ kind: "query",
19670
+ auth: "protected"
19671
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19672
+ kind: "query",
19673
+ auth: "protected"
19674
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19675
+ kind: "mutation",
19676
+ auth: "protected"
19677
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19678
+ kind: "mutation",
19679
+ auth: "protected"
19680
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19681
+ kind: "query",
19682
+ auth: "protected"
19424
19683
  });
19425
19684
  /**
19426
19685
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
@@ -22440,6 +22699,12 @@ Object.freeze({
22440
22699
  addonId: null,
22441
22700
  access: "delete"
22442
22701
  },
22702
+ "pipelineAnalytics.deleteDeviceEvents": {
22703
+ capName: "pipeline-analytics",
22704
+ capScope: "device",
22705
+ addonId: null,
22706
+ access: "delete"
22707
+ },
22443
22708
  "pipelineAnalytics.deleteTracks": {
22444
22709
  capName: "pipeline-analytics",
22445
22710
  capScope: "device",
@@ -22470,6 +22735,12 @@ Object.freeze({
22470
22735
  addonId: null,
22471
22736
  access: "view"
22472
22737
  },
22738
+ "pipelineAnalytics.getEventStoreFootprint": {
22739
+ capName: "pipeline-analytics",
22740
+ capScope: "device",
22741
+ addonId: null,
22742
+ access: "view"
22743
+ },
22473
22744
  "pipelineAnalytics.getKeyEvents": {
22474
22745
  capName: "pipeline-analytics",
22475
22746
  capScope: "device",
@@ -22512,6 +22783,12 @@ Object.freeze({
22512
22783
  addonId: null,
22513
22784
  access: "view"
22514
22785
  },
22786
+ "pipelineAnalytics.listOpsLog": {
22787
+ capName: "pipeline-analytics",
22788
+ capScope: "device",
22789
+ addonId: null,
22790
+ access: "view"
22791
+ },
22515
22792
  "pipelineAnalytics.listRecentTracks": {
22516
22793
  capName: "pipeline-analytics",
22517
22794
  capScope: "device",
@@ -22524,6 +22801,12 @@ Object.freeze({
22524
22801
  addonId: null,
22525
22802
  access: "view"
22526
22803
  },
22804
+ "pipelineAnalytics.pruneEvents": {
22805
+ capName: "pipeline-analytics",
22806
+ capScope: "device",
22807
+ addonId: null,
22808
+ access: "create"
22809
+ },
22527
22810
  "pipelineAnalytics.pruneEventsBefore": {
22528
22811
  capName: "pipeline-analytics",
22529
22812
  capScope: "device",
@@ -23286,6 +23569,12 @@ Object.freeze({
23286
23569
  addonId: null,
23287
23570
  access: "create"
23288
23571
  },
23572
+ "recording.deleteFootprint": {
23573
+ capName: "recording",
23574
+ capScope: "system",
23575
+ addonId: null,
23576
+ access: "delete"
23577
+ },
23289
23578
  "recording.getAvailability": {
23290
23579
  capName: "recording",
23291
23580
  capScope: "system",
@@ -23316,6 +23605,12 @@ Object.freeze({
23316
23605
  addonId: null,
23317
23606
  access: "view"
23318
23607
  },
23608
+ "recording.listOpsLog": {
23609
+ capName: "recording",
23610
+ capScope: "system",
23611
+ addonId: null,
23612
+ access: "view"
23613
+ },
23319
23614
  "recording.locateSegment": {
23320
23615
  capName: "recording",
23321
23616
  capScope: "system",
@@ -23346,6 +23641,42 @@ Object.freeze({
23346
23641
  addonId: null,
23347
23642
  access: "create"
23348
23643
  },
23644
+ "recordingExport.cancelExport": {
23645
+ capName: "recordingExport",
23646
+ capScope: "system",
23647
+ addonId: null,
23648
+ access: "create"
23649
+ },
23650
+ "recordingExport.createExport": {
23651
+ capName: "recordingExport",
23652
+ capScope: "system",
23653
+ addonId: null,
23654
+ access: "create"
23655
+ },
23656
+ "recordingExport.deleteExport": {
23657
+ capName: "recordingExport",
23658
+ capScope: "system",
23659
+ addonId: null,
23660
+ access: "delete"
23661
+ },
23662
+ "recordingExport.getDownloadUrl": {
23663
+ capName: "recordingExport",
23664
+ capScope: "system",
23665
+ addonId: null,
23666
+ access: "view"
23667
+ },
23668
+ "recordingExport.getExport": {
23669
+ capName: "recordingExport",
23670
+ capScope: "system",
23671
+ addonId: null,
23672
+ access: "view"
23673
+ },
23674
+ "recordingExport.listExports": {
23675
+ capName: "recordingExport",
23676
+ capScope: "system",
23677
+ addonId: null,
23678
+ access: "view"
23679
+ },
23349
23680
  "sceneMonitor.captureReference": {
23350
23681
  capName: "scene-monitor",
23351
23682
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-advanced-notifier",
3
- "version": "1.1.27",
3
+ "version": "1.1.29",
4
4
  "description": "Rules-based notification engine for CamStack",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",