@camstack/addon-provider-unifi 0.1.12 → 0.1.13

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
@@ -7358,6 +7358,62 @@ var RecordingConfigSchema = object({
7358
7358
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7359
7359
  });
7360
7360
  /**
7361
+ * Ops-log — the durable, append-only operations audit shared by the
7362
+ * recordings and events management surfaces.
7363
+ *
7364
+ * ONE row shape is reused for both domains so a single "Activity" view can
7365
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7366
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7367
+ * management operation, WHY it ran (reason), and its measurable effect
7368
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7369
+ * never fail the operation it records.
7370
+ */
7371
+ /** Which management domain the operation belongs to. */
7372
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7373
+ /** The kind of management operation performed. */
7374
+ var OpsLogOpSchema = _enum([
7375
+ "prune",
7376
+ "manual-delete",
7377
+ "rescan",
7378
+ "retention-run"
7379
+ ]);
7380
+ /** Why the operation ran. */
7381
+ var OpsLogReasonSchema = _enum([
7382
+ "retention",
7383
+ "quota",
7384
+ "manual",
7385
+ "operator"
7386
+ ]);
7387
+ /** One audit row, shared verbatim by both domains. */
7388
+ var OpsLogEntrySchema = object({
7389
+ /** Unique row id. */
7390
+ id: string(),
7391
+ /** Epoch ms the operation completed. */
7392
+ at: number(),
7393
+ domain: OpsLogDomainSchema,
7394
+ op: OpsLogOpSchema,
7395
+ reason: OpsLogReasonSchema,
7396
+ /** The camera the op targeted; null for a cluster/global op. */
7397
+ deviceId: number().nullable(),
7398
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7399
+ nodeId: string(),
7400
+ /** Buckets / rows deleted (op-specific unit). */
7401
+ itemsAffected: number(),
7402
+ /** Bytes reclaimed by the op (0 when not measurable). */
7403
+ bytesReclaimed: number(),
7404
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7405
+ detail: string().nullable(),
7406
+ /** Who/what triggered the op. */
7407
+ actor: string()
7408
+ });
7409
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7410
+ var OpsLogQueryInputSchema = object({
7411
+ /** Restrict to a single camera; omit for every row. */
7412
+ deviceId: number().optional(),
7413
+ /** Max rows returned, newest-first. */
7414
+ limit: number().int().min(1).max(1e3).optional()
7415
+ });
7416
+ /**
7361
7417
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7362
7418
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7363
7419
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -14821,9 +14877,10 @@ var DEVICE_LOCAL_STATE_CAPS = {
14821
14877
  * `package` backs the package-drop detector — a package zone is a
14822
14878
  * `ZoneRule` on the `'package'` stage referencing drawn polygons
14823
14879
  * (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
14824
- * The orchestrator provider that writes this stage lands in a later
14825
- * slice; until then the mirror carries only `{motion, detection}` and
14826
- * consumers read `package` as absent (treat as `[]`).
14880
+ * The orchestrator provider writes this stage as a first-class slice
14881
+ * (Phase 4): every mutation mirrors the full `{motion, detection,
14882
+ * package}` shape, so consumers read the current package rules directly
14883
+ * off `device.state.zoneRules.value.package`.
14827
14884
  */
14828
14885
  runtimeState: object({
14829
14886
  motion: array(ZoneRuleSchema).readonly(),
@@ -19140,6 +19197,26 @@ var TrackCascadeCountsSchema = object({
19140
19197
  /** Per-track CLIP search vectors removed (best-effort). */
19141
19198
  embeddings: number().int()
19142
19199
  });
19200
+ /** Event-store footprint for one camera. */
19201
+ var EventStoreDeviceFootprintSchema = object({
19202
+ deviceId: number(),
19203
+ /** Persisted event rows (motion + object + audio) for the camera. */
19204
+ rows: number().int(),
19205
+ /** Event-owned media bytes on disk for the camera. */
19206
+ bytes: number().int()
19207
+ });
19208
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
19209
+ var EventStoreFootprintSchema = object({
19210
+ totalRows: number().int(),
19211
+ totalBytes: number().int(),
19212
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
19213
+ });
19214
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
19215
+ var EventPruneCountsSchema = object({
19216
+ motion: number().int(),
19217
+ object: number().int(),
19218
+ audio: number().int()
19219
+ });
19143
19220
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
19144
19221
  deviceId: number(),
19145
19222
  trackId: string()
@@ -19203,6 +19280,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19203
19280
  }), {
19204
19281
  kind: "mutation",
19205
19282
  auth: "admin"
19283
+ }), method(object({}), EventStoreFootprintSchema, {
19284
+ kind: "query",
19285
+ auth: "admin"
19286
+ }), method(object({
19287
+ olderThanMs: number(),
19288
+ reason: OpsLogReasonSchema.optional()
19289
+ }), EventPruneCountsSchema, {
19290
+ kind: "mutation",
19291
+ auth: "admin"
19292
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
19293
+ kind: "mutation",
19294
+ auth: "admin"
19295
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19296
+ kind: "query",
19297
+ auth: "admin"
19206
19298
  }), method(object({
19207
19299
  eventId: string(),
19208
19300
  kind: MediaFileKindEnum.optional()
@@ -22453,13 +22545,29 @@ method(object({
22453
22545
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
22454
22546
  kind: "mutation",
22455
22547
  auth: "admin"
22456
- }), method(object({ deviceId: number() }), object({
22548
+ }), method(object({
22549
+ deviceId: number(),
22550
+ reason: OpsLogReasonSchema.optional()
22551
+ }), object({
22457
22552
  floorMs: number().nullable(),
22458
22553
  deletedBuckets: number().int(),
22459
22554
  reclaimedBytes: number().int()
22460
22555
  }), {
22461
22556
  kind: "mutation",
22462
22557
  auth: "admin"
22558
+ }), method(object({
22559
+ deviceId: number(),
22560
+ fromMs: number().optional(),
22561
+ toMs: number().optional()
22562
+ }), object({
22563
+ deletedBuckets: number().int(),
22564
+ reclaimedBytes: number().int()
22565
+ }), {
22566
+ kind: "mutation",
22567
+ auth: "admin"
22568
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
22569
+ kind: "query",
22570
+ auth: "admin"
22463
22571
  });
22464
22572
  /**
22465
22573
  * `recordingExport` cap — render a footage time range into a single downloadable
@@ -25581,6 +25689,12 @@ Object.freeze({
25581
25689
  addonId: null,
25582
25690
  access: "delete"
25583
25691
  },
25692
+ "pipelineAnalytics.deleteDeviceEvents": {
25693
+ capName: "pipeline-analytics",
25694
+ capScope: "device",
25695
+ addonId: null,
25696
+ access: "delete"
25697
+ },
25584
25698
  "pipelineAnalytics.deleteTracks": {
25585
25699
  capName: "pipeline-analytics",
25586
25700
  capScope: "device",
@@ -25611,6 +25725,12 @@ Object.freeze({
25611
25725
  addonId: null,
25612
25726
  access: "view"
25613
25727
  },
25728
+ "pipelineAnalytics.getEventStoreFootprint": {
25729
+ capName: "pipeline-analytics",
25730
+ capScope: "device",
25731
+ addonId: null,
25732
+ access: "view"
25733
+ },
25614
25734
  "pipelineAnalytics.getKeyEvents": {
25615
25735
  capName: "pipeline-analytics",
25616
25736
  capScope: "device",
@@ -25653,6 +25773,12 @@ Object.freeze({
25653
25773
  addonId: null,
25654
25774
  access: "view"
25655
25775
  },
25776
+ "pipelineAnalytics.listOpsLog": {
25777
+ capName: "pipeline-analytics",
25778
+ capScope: "device",
25779
+ addonId: null,
25780
+ access: "view"
25781
+ },
25656
25782
  "pipelineAnalytics.listRecentTracks": {
25657
25783
  capName: "pipeline-analytics",
25658
25784
  capScope: "device",
@@ -25665,6 +25791,12 @@ Object.freeze({
25665
25791
  addonId: null,
25666
25792
  access: "view"
25667
25793
  },
25794
+ "pipelineAnalytics.pruneEvents": {
25795
+ capName: "pipeline-analytics",
25796
+ capScope: "device",
25797
+ addonId: null,
25798
+ access: "create"
25799
+ },
25668
25800
  "pipelineAnalytics.pruneEventsBefore": {
25669
25801
  capName: "pipeline-analytics",
25670
25802
  capScope: "device",
@@ -26427,6 +26559,12 @@ Object.freeze({
26427
26559
  addonId: null,
26428
26560
  access: "create"
26429
26561
  },
26562
+ "recording.deleteFootprint": {
26563
+ capName: "recording",
26564
+ capScope: "system",
26565
+ addonId: null,
26566
+ access: "delete"
26567
+ },
26430
26568
  "recording.getAvailability": {
26431
26569
  capName: "recording",
26432
26570
  capScope: "system",
@@ -26457,6 +26595,12 @@ Object.freeze({
26457
26595
  addonId: null,
26458
26596
  access: "view"
26459
26597
  },
26598
+ "recording.listOpsLog": {
26599
+ capName: "recording",
26600
+ capScope: "system",
26601
+ addonId: null,
26602
+ access: "view"
26603
+ },
26460
26604
  "recording.locateSegment": {
26461
26605
  capName: "recording",
26462
26606
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -7357,6 +7357,62 @@ var RecordingConfigSchema = object({
7357
7357
  scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7358
7358
  });
7359
7359
  /**
7360
+ * Ops-log — the durable, append-only operations audit shared by the
7361
+ * recordings and events management surfaces.
7362
+ *
7363
+ * ONE row shape is reused for both domains so a single "Activity" view can
7364
+ * merge the recorder's DurableState ring (recordings ops-log) and the
7365
+ * pipeline-analytics SQLite collection (events ops-log). Each row records a
7366
+ * management operation, WHY it ran (reason), and its measurable effect
7367
+ * (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
7368
+ * never fail the operation it records.
7369
+ */
7370
+ /** Which management domain the operation belongs to. */
7371
+ var OpsLogDomainSchema = _enum(["recording", "events"]);
7372
+ /** The kind of management operation performed. */
7373
+ var OpsLogOpSchema = _enum([
7374
+ "prune",
7375
+ "manual-delete",
7376
+ "rescan",
7377
+ "retention-run"
7378
+ ]);
7379
+ /** Why the operation ran. */
7380
+ var OpsLogReasonSchema = _enum([
7381
+ "retention",
7382
+ "quota",
7383
+ "manual",
7384
+ "operator"
7385
+ ]);
7386
+ /** One audit row, shared verbatim by both domains. */
7387
+ var OpsLogEntrySchema = object({
7388
+ /** Unique row id. */
7389
+ id: string(),
7390
+ /** Epoch ms the operation completed. */
7391
+ at: number(),
7392
+ domain: OpsLogDomainSchema,
7393
+ op: OpsLogOpSchema,
7394
+ reason: OpsLogReasonSchema,
7395
+ /** The camera the op targeted; null for a cluster/global op. */
7396
+ deviceId: number().nullable(),
7397
+ /** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
7398
+ nodeId: string(),
7399
+ /** Buckets / rows deleted (op-specific unit). */
7400
+ itemsAffected: number(),
7401
+ /** Bytes reclaimed by the op (0 when not measurable). */
7402
+ bytesReclaimed: number(),
7403
+ /** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
7404
+ detail: string().nullable(),
7405
+ /** Who/what triggered the op. */
7406
+ actor: string()
7407
+ });
7408
+ /** Shared query input for the per-domain `listOpsLog` cap methods. */
7409
+ var OpsLogQueryInputSchema = object({
7410
+ /** Restrict to a single camera; omit for every row. */
7411
+ deviceId: number().optional(),
7412
+ /** Max rows returned, newest-first. */
7413
+ limit: number().int().min(1).max(1e3).optional()
7414
+ });
7415
+ /**
7360
7416
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
7361
7417
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
7362
7418
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -14820,9 +14876,10 @@ var DEVICE_LOCAL_STATE_CAPS = {
14820
14876
  * `package` backs the package-drop detector — a package zone is a
14821
14877
  * `ZoneRule` on the `'package'` stage referencing drawn polygons
14822
14878
  * (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
14823
- * The orchestrator provider that writes this stage lands in a later
14824
- * slice; until then the mirror carries only `{motion, detection}` and
14825
- * consumers read `package` as absent (treat as `[]`).
14879
+ * The orchestrator provider writes this stage as a first-class slice
14880
+ * (Phase 4): every mutation mirrors the full `{motion, detection,
14881
+ * package}` shape, so consumers read the current package rules directly
14882
+ * off `device.state.zoneRules.value.package`.
14826
14883
  */
14827
14884
  runtimeState: object({
14828
14885
  motion: array(ZoneRuleSchema).readonly(),
@@ -19139,6 +19196,26 @@ var TrackCascadeCountsSchema = object({
19139
19196
  /** Per-track CLIP search vectors removed (best-effort). */
19140
19197
  embeddings: number().int()
19141
19198
  });
19199
+ /** Event-store footprint for one camera. */
19200
+ var EventStoreDeviceFootprintSchema = object({
19201
+ deviceId: number(),
19202
+ /** Persisted event rows (motion + object + audio) for the camera. */
19203
+ rows: number().int(),
19204
+ /** Event-owned media bytes on disk for the camera. */
19205
+ bytes: number().int()
19206
+ });
19207
+ /** Aggregate event-store footprint: global totals + per-camera breakdown. */
19208
+ var EventStoreFootprintSchema = object({
19209
+ totalRows: number().int(),
19210
+ totalBytes: number().int(),
19211
+ devices: array(EventStoreDeviceFootprintSchema).readonly()
19212
+ });
19213
+ /** Per-kind counts returned by the event-prune / device-delete mutations. */
19214
+ var EventPruneCountsSchema = object({
19215
+ motion: number().int(),
19216
+ object: number().int(),
19217
+ audio: number().int()
19218
+ });
19142
19219
  DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
19143
19220
  deviceId: number(),
19144
19221
  trackId: string()
@@ -19202,6 +19279,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19202
19279
  }), {
19203
19280
  kind: "mutation",
19204
19281
  auth: "admin"
19282
+ }), method(object({}), EventStoreFootprintSchema, {
19283
+ kind: "query",
19284
+ auth: "admin"
19285
+ }), method(object({
19286
+ olderThanMs: number(),
19287
+ reason: OpsLogReasonSchema.optional()
19288
+ }), EventPruneCountsSchema, {
19289
+ kind: "mutation",
19290
+ auth: "admin"
19291
+ }), method(object({ deviceId: number() }), EventPruneCountsSchema, {
19292
+ kind: "mutation",
19293
+ auth: "admin"
19294
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
19295
+ kind: "query",
19296
+ auth: "admin"
19205
19297
  }), method(object({
19206
19298
  eventId: string(),
19207
19299
  kind: MediaFileKindEnum.optional()
@@ -22452,13 +22544,29 @@ method(object({
22452
22544
  }), method(object({ deviceId: number() }), RecordingStatusSchema, {
22453
22545
  kind: "mutation",
22454
22546
  auth: "admin"
22455
- }), method(object({ deviceId: number() }), object({
22547
+ }), method(object({
22548
+ deviceId: number(),
22549
+ reason: OpsLogReasonSchema.optional()
22550
+ }), object({
22456
22551
  floorMs: number().nullable(),
22457
22552
  deletedBuckets: number().int(),
22458
22553
  reclaimedBytes: number().int()
22459
22554
  }), {
22460
22555
  kind: "mutation",
22461
22556
  auth: "admin"
22557
+ }), method(object({
22558
+ deviceId: number(),
22559
+ fromMs: number().optional(),
22560
+ toMs: number().optional()
22561
+ }), object({
22562
+ deletedBuckets: number().int(),
22563
+ reclaimedBytes: number().int()
22564
+ }), {
22565
+ kind: "mutation",
22566
+ auth: "admin"
22567
+ }), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
22568
+ kind: "query",
22569
+ auth: "admin"
22462
22570
  });
22463
22571
  /**
22464
22572
  * `recordingExport` cap — render a footage time range into a single downloadable
@@ -25580,6 +25688,12 @@ Object.freeze({
25580
25688
  addonId: null,
25581
25689
  access: "delete"
25582
25690
  },
25691
+ "pipelineAnalytics.deleteDeviceEvents": {
25692
+ capName: "pipeline-analytics",
25693
+ capScope: "device",
25694
+ addonId: null,
25695
+ access: "delete"
25696
+ },
25583
25697
  "pipelineAnalytics.deleteTracks": {
25584
25698
  capName: "pipeline-analytics",
25585
25699
  capScope: "device",
@@ -25610,6 +25724,12 @@ Object.freeze({
25610
25724
  addonId: null,
25611
25725
  access: "view"
25612
25726
  },
25727
+ "pipelineAnalytics.getEventStoreFootprint": {
25728
+ capName: "pipeline-analytics",
25729
+ capScope: "device",
25730
+ addonId: null,
25731
+ access: "view"
25732
+ },
25613
25733
  "pipelineAnalytics.getKeyEvents": {
25614
25734
  capName: "pipeline-analytics",
25615
25735
  capScope: "device",
@@ -25652,6 +25772,12 @@ Object.freeze({
25652
25772
  addonId: null,
25653
25773
  access: "view"
25654
25774
  },
25775
+ "pipelineAnalytics.listOpsLog": {
25776
+ capName: "pipeline-analytics",
25777
+ capScope: "device",
25778
+ addonId: null,
25779
+ access: "view"
25780
+ },
25655
25781
  "pipelineAnalytics.listRecentTracks": {
25656
25782
  capName: "pipeline-analytics",
25657
25783
  capScope: "device",
@@ -25664,6 +25790,12 @@ Object.freeze({
25664
25790
  addonId: null,
25665
25791
  access: "view"
25666
25792
  },
25793
+ "pipelineAnalytics.pruneEvents": {
25794
+ capName: "pipeline-analytics",
25795
+ capScope: "device",
25796
+ addonId: null,
25797
+ access: "create"
25798
+ },
25667
25799
  "pipelineAnalytics.pruneEventsBefore": {
25668
25800
  capName: "pipeline-analytics",
25669
25801
  capScope: "device",
@@ -26426,6 +26558,12 @@ Object.freeze({
26426
26558
  addonId: null,
26427
26559
  access: "create"
26428
26560
  },
26561
+ "recording.deleteFootprint": {
26562
+ capName: "recording",
26563
+ capScope: "system",
26564
+ addonId: null,
26565
+ access: "delete"
26566
+ },
26429
26567
  "recording.getAvailability": {
26430
26568
  capName: "recording",
26431
26569
  capScope: "system",
@@ -26456,6 +26594,12 @@ Object.freeze({
26456
26594
  addonId: null,
26457
26595
  access: "view"
26458
26596
  },
26597
+ "recording.listOpsLog": {
26598
+ capName: "recording",
26599
+ capScope: "system",
26600
+ addonId: null,
26601
+ access: "view"
26602
+ },
26459
26603
  "recording.locateSegment": {
26460
26604
  capName: "recording",
26461
26605
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-unifi",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "UniFi Network controller device-provider addon for CamStack — local-controller infra switches/APs (as containers) + network-client presence. NO cameras/Protect.",
5
5
  "keywords": [
6
6
  "camstack",