@camstack/addon-decoder-nodeav 1.2.48 → 1.2.49

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/index.js CHANGED
@@ -8018,6 +8018,20 @@ var RelocateJobSchema = object({
8018
8018
  * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8019
8019
  */
8020
8020
  rowsReconciled: number().int().nonnegative().optional(),
8021
+ /**
8022
+ * Rows this run FORGOT because the file they name is not on disk.
8023
+ *
8024
+ * The mover derived the path from the row's own fields and `stat`ed it; an
8025
+ * ENOENT there is a per-path confirmation that the segment is gone (D296),
8026
+ * and the durable row is dropped through the same channel eviction uses. It
8027
+ * is reported for the same reason `rowsReconciled` is: this is a durable
8028
+ * mutation nobody asked for, and a migration that quietly erases hour rows is
8029
+ * the same failure as one that quietly skips them (D295).
8030
+ *
8031
+ * The production drain of 2026-08-30 would have reported 11 074 here — the
8032
+ * ledger claimed 5.65 GB of footage that no longer existed.
8033
+ */
8034
+ rowsForgotten: number().int().nonnegative().optional(),
8021
8035
  startedAt: number(),
8022
8036
  finishedAt: number().nullable(),
8023
8037
  error: string().nullable()
@@ -8381,6 +8395,91 @@ var RelocateResidueSchema = object({
8381
8395
  segments: number().int().nonnegative(),
8382
8396
  bytes: number().int().nonnegative()
8383
8397
  }).nullable();
8398
+ /**
8399
+ * Ask one location whether its durable hour rows describe the disk — the walk
8400
+ * (D319).
8401
+ *
8402
+ * `apply` DEFAULTS TO FALSE and that default is the product: the operator's
8403
+ * missing tool is the question, and the dry run is how they sanity-check the
8404
+ * destructive run before authorising it.
8405
+ */
8406
+ var LedgerWalkInputSchema = object({
8407
+ locationId: string().min(1),
8408
+ /** Forget the confirmed-absent rows, rather than only counting them. */
8409
+ apply: boolean().optional(),
8410
+ /** Narrow to one camera. */
8411
+ deviceId: number().int().positive().optional(),
8412
+ /** Narrow to these recording profiles; empty/absent = every profile. */
8413
+ profiles: array(string().min(1)).optional()
8414
+ });
8415
+ /** Why a whole walk did nothing. Every one leaves the ledger untouched. */
8416
+ var LedgerWalkRefusalSchema = _enum([
8417
+ "location-unknown",
8418
+ "source-writable",
8419
+ "no-ledger",
8420
+ "archive-unreadable",
8421
+ "anchor-absent",
8422
+ "anchor-unreadable",
8423
+ "anchor-moved"
8424
+ ]);
8425
+ _enum([
8426
+ "live-tail",
8427
+ "listing-error",
8428
+ "path-mismatch",
8429
+ "durable-refused"
8430
+ ]);
8431
+ /** Every skip reason, always present, always a number — so a reason that never
8432
+ * fired reports as zero rather than absent and the report shape is constant
8433
+ * between passes. Spelled out rather than `z.record` for exactly that. */
8434
+ var LedgerWalkSkipCountsSchema = object({
8435
+ "live-tail": number().int().nonnegative(),
8436
+ "listing-error": number().int().nonnegative(),
8437
+ "path-mismatch": number().int().nonnegative(),
8438
+ "durable-refused": number().int().nonnegative()
8439
+ });
8440
+ /** One camera's share of a walk, so a report names cameras and not rows. */
8441
+ var LedgerWalkDeviceReportSchema = object({
8442
+ deviceId: number().int(),
8443
+ hoursWalked: number().int().nonnegative(),
8444
+ hoursMissing: number().int().nonnegative(),
8445
+ ghostSegments: number().int().nonnegative(),
8446
+ ghostBytes: number().int().nonnegative(),
8447
+ forgottenSegments: number().int().nonnegative(),
8448
+ orphanFiles: number().int().nonnegative()
8449
+ });
8450
+ /**
8451
+ * What one walk claimed, listed, found and (only when armed) forgot.
8452
+ *
8453
+ * `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
8454
+ * walk that saw a fraction of the location is visible in its own report rather
8455
+ * than in the absence of one.
8456
+ */
8457
+ var LedgerWalkReportSchema = object({
8458
+ locationId: string(),
8459
+ applied: boolean(),
8460
+ refused: LedgerWalkRefusalSchema.nullable(),
8461
+ archiveSegments: number().int().nonnegative().nullable(),
8462
+ archiveBytes: number().int().nonnegative().nullable(),
8463
+ hoursClaimed: number().int().nonnegative(),
8464
+ hoursWalked: number().int().nonnegative(),
8465
+ hoursMissing: number().int().nonnegative(),
8466
+ /** `readdir` calls issued — the cost, stated in the unit that is paid. */
8467
+ listings: number().int().nonnegative(),
8468
+ segmentsClaimed: number().int().nonnegative(),
8469
+ ghostSegments: number().int().nonnegative(),
8470
+ ghostBytes: number().int().nonnegative(),
8471
+ ghostHoursWhole: number().int().nonnegative(),
8472
+ forgottenSegments: number().int().nonnegative(),
8473
+ forgottenBytes: number().int().nonnegative(),
8474
+ /** Files under a claimed hour that no durable row names. Never deleted. */
8475
+ orphanFiles: number().int().nonnegative(),
8476
+ orphanSample: array(string()).readonly(),
8477
+ hoursSkipped: number().int().nonnegative(),
8478
+ skippedByReason: LedgerWalkSkipCountsSchema,
8479
+ /** The walk stopped at its per-pass hour bound with claims unwalked. */
8480
+ bounded: boolean(),
8481
+ byDevice: array(LedgerWalkDeviceReportSchema).readonly()
8482
+ });
8384
8483
  /** How many rows a media pass would still act on against a given target — the
8385
8484
  * media lane's denominator AND its residue, from ONE derivation so the two can
8386
8485
  * never disagree. `null` = the count could not be taken. */
@@ -18784,13 +18883,15 @@ var ListGroupsPageSchema = object({
18784
18883
  groups: array(AnalyticsGroupRecordSchema).readonly(),
18785
18884
  nextCursor: string().nullable()
18786
18885
  });
18886
+ var KEY_EVENTS_DEFAULT_LIMIT = 50;
18887
+ var KEY_EVENTS_MAX_LIMIT = 200;
18787
18888
  var KeyEventQueryInput = object({
18788
18889
  deviceId: number(),
18789
18890
  /** Window lower bound (track firstSeen ≥ since). */
18790
18891
  since: number(),
18791
18892
  /** Window upper bound (track firstSeen ≤ until). */
18792
18893
  until: number(),
18793
- limit: number().int().min(1).max(200).default(50),
18894
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18794
18895
  /** Drop tracks scoring below this importance. */
18795
18896
  minImportance: number().min(0).max(1).optional(),
18796
18897
  /** Restrict to a single class (e.g. 'person'). */
@@ -18812,6 +18913,32 @@ var KeyEventSchema = object({
18812
18913
  ...TrackFlagFields,
18813
18914
  ...TrackRetrainFields
18814
18915
  });
18916
+ /** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
18917
+ var KeyEventBatchQueryInput = object({
18918
+ deviceIds: array(number()).min(1).max(200),
18919
+ since: number(),
18920
+ until: number(),
18921
+ /** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
18922
+ * across the set, which would let a busy camera starve a quiet one of its
18923
+ * rows and change what the merged feed contains. */
18924
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18925
+ minImportance: number().min(0).max(1).optional(),
18926
+ classFilter: string().optional()
18927
+ });
18928
+ /**
18929
+ * One camera's key events in a batch answer.
18930
+ *
18931
+ * The row exists for every requested id. `getKeyEvents` degrades to `[]` on
18932
+ * error rather than throwing, so a camera whose store read failed and one with
18933
+ * no events in the window were ALREADY indistinguishable per camera — the
18934
+ * batch does not make that worse, and the row keeps the deviceId the single
18935
+ * method's output never carried (the caller used to stamp it from the fan-out
18936
+ * key, which only worked because there was one query per camera).
18937
+ */
18938
+ var KeyEventsForDeviceSchema = object({
18939
+ deviceId: number(),
18940
+ events: array(KeyEventSchema).readonly()
18941
+ });
18815
18942
  object({
18816
18943
  trackId: string(),
18817
18944
  className: string(),
@@ -19081,7 +19208,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19081
19208
  until: number().optional(),
19082
19209
  kinds: array(string()).optional(),
19083
19210
  limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
19084
- }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
19211
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
19085
19212
  deviceId: number(),
19086
19213
  since: number(),
19087
19214
  until: number(),
@@ -26733,6 +26860,9 @@ method(object({
26733
26860
  }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
26734
26861
  kind: "query",
26735
26862
  auth: "admin"
26863
+ }), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
26864
+ kind: "mutation",
26865
+ auth: "admin"
26736
26866
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
26737
26867
  kind: "mutation",
26738
26868
  auth: "admin"
@@ -27124,7 +27254,26 @@ var SceneMonitorStatusSchema = object({
27124
27254
  monitors: array(SceneMonitorSchema),
27125
27255
  lastFetchedAt: number()
27126
27256
  });
27127
- DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
27257
+ /**
27258
+ * One camera's row in a `listScenesBatch` answer.
27259
+ *
27260
+ * `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
27261
+ * is a `defaultActive` wrapper, so every camera is asked; a camera whose
27262
+ * provider is absent (pipeline-analytics not deployed, the post-processing node
27263
+ * down) cannot answer, and that is not the same fact as a camera with no scenes
27264
+ * configured. Fanned out per camera the difference was visible — one query
27265
+ * errored while the others resolved — and a batch that returned only the rows
27266
+ * it managed would have destroyed it, silently, by making an unreachable camera
27267
+ * indistinguishable from one that answered `monitors: []`.
27268
+ *
27269
+ * So: EVERY requested deviceId gets a row. `status: null` means "this camera
27270
+ * could not be read"; `status.monitors: []` means "read, and it has none".
27271
+ */
27272
+ var SceneMonitorStatusForDeviceSchema = object({
27273
+ deviceId: number(),
27274
+ status: SceneMonitorStatusSchema.nullable()
27275
+ });
27276
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
27128
27277
  deviceId: number(),
27129
27278
  label: string(),
27130
27279
  roi: MaskRectShapeSchema,
@@ -28448,6 +28597,27 @@ var CameraOccupancySnapshotSchema = object({
28448
28597
  stationaryObjects: array(StationaryObjectSchema).readonly().optional()
28449
28598
  });
28450
28599
  /**
28600
+ * One camera's row in a `getCurrentSnapshotBatch` answer.
28601
+ *
28602
+ * THREE outcomes, and the single-camera method could only express two of them
28603
+ * because `snapshot: null` was already spoken for:
28604
+ *
28605
+ * - `read: 'read'`, `snapshot` present — the live occupancy reading.
28606
+ * - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
28607
+ * yet: no frame since boot, and no parked-object registry to hydrate from.
28608
+ * - `read: 'unreadable'` — the owner could not answer for this
28609
+ * camera. `snapshot` is null, and it does NOT mean "nothing parked here".
28610
+ *
28611
+ * Collapsing the last two is the failure this field exists to prevent: a
28612
+ * hydration that threw would otherwise render as an empty Stationary section,
28613
+ * which is a definite claim about a camera nobody could read.
28614
+ */
28615
+ var CameraOccupancySnapshotForDeviceSchema = object({
28616
+ deviceId: number(),
28617
+ read: _enum(["read", "unreadable"]),
28618
+ snapshot: CameraOccupancySnapshotSchema.nullable()
28619
+ });
28620
+ /**
28451
28621
  * Time-series resolution. The history methods return one bucket per
28452
28622
  * step over the requested range. Smaller resolutions cost more
28453
28623
  * memory + bandwidth; bound to discrete steps so caller cannot ask
@@ -28471,7 +28641,7 @@ var HistoryPointSchema = object({
28471
28641
  /** Object count averaged over the bucket (rounded to nearest integer). */
28472
28642
  count: number().int().nonnegative()
28473
28643
  });
28474
- DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
28644
+ DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
28475
28645
  deviceId: number(),
28476
28646
  zoneId: string(),
28477
28647
  className: string().optional()
@@ -31776,6 +31946,12 @@ Object.freeze({
31776
31946
  addonId: null,
31777
31947
  access: "view"
31778
31948
  },
31949
+ "pipelineAnalytics.getKeyEventsBatch": {
31950
+ capName: "pipeline-analytics",
31951
+ capScope: "device",
31952
+ addonId: null,
31953
+ access: "view"
31954
+ },
31779
31955
  "pipelineAnalytics.getMotionEvents": {
31780
31956
  capName: "pipeline-analytics",
31781
31957
  capScope: "device",
@@ -32952,6 +33128,12 @@ Object.freeze({
32952
33128
  addonId: null,
32953
33129
  access: "view"
32954
33130
  },
33131
+ "recording.reconcileLedgerAgainstDisk": {
33132
+ capName: "recording",
33133
+ capScope: "system",
33134
+ addonId: null,
33135
+ access: "create"
33136
+ },
32955
33137
  "recording.refreshStorageLocationsForMigration": {
32956
33138
  capName: "recording",
32957
33139
  capScope: "system",
@@ -33078,6 +33260,12 @@ Object.freeze({
33078
33260
  addonId: null,
33079
33261
  access: "view"
33080
33262
  },
33263
+ "sceneMonitor.listScenesBatch": {
33264
+ capName: "scene-monitor",
33265
+ capScope: "device",
33266
+ addonId: null,
33267
+ access: "view"
33268
+ },
33081
33269
  "sceneMonitor.recheckNow": {
33082
33270
  capName: "scene-monitor",
33083
33271
  capScope: "device",
@@ -34434,6 +34622,12 @@ Object.freeze({
34434
34622
  addonId: null,
34435
34623
  access: "view"
34436
34624
  },
34625
+ "zoneAnalytics.getCurrentSnapshotBatch": {
34626
+ capName: "zone-analytics",
34627
+ capScope: "device",
34628
+ addonId: null,
34629
+ access: "view"
34630
+ },
34437
34631
  "zoneAnalytics.getUnzonedHistory": {
34438
34632
  capName: "zone-analytics",
34439
34633
  capScope: "device",
@@ -35438,6 +35632,11 @@ Object.freeze({
35438
35632
  form: "single",
35439
35633
  optional: false
35440
35634
  }],
35635
+ "pipelineAnalytics.getKeyEventsBatch": [{
35636
+ name: "deviceIds",
35637
+ form: "array",
35638
+ optional: false
35639
+ }],
35441
35640
  "pipelineAnalytics.getMotionEvents": [{
35442
35641
  name: "deviceId",
35443
35642
  form: "single",
@@ -35878,6 +36077,11 @@ Object.freeze({
35878
36077
  form: "single",
35879
36078
  optional: false
35880
36079
  }],
36080
+ "recording.reconcileLedgerAgainstDisk": [{
36081
+ name: "deviceId",
36082
+ form: "single",
36083
+ optional: true
36084
+ }],
35881
36085
  "recording.relocateFootage": [{
35882
36086
  name: "deviceId",
35883
36087
  form: "single",
@@ -35943,6 +36147,11 @@ Object.freeze({
35943
36147
  form: "single",
35944
36148
  optional: false
35945
36149
  }],
36150
+ "sceneMonitor.listScenesBatch": [{
36151
+ name: "deviceIds",
36152
+ form: "array",
36153
+ optional: false
36154
+ }],
35946
36155
  "sceneMonitor.recheckNow": [{
35947
36156
  name: "deviceId",
35948
36157
  form: "single",
@@ -36204,6 +36413,11 @@ Object.freeze({
36204
36413
  form: "single",
36205
36414
  optional: false
36206
36415
  }],
36416
+ "zoneAnalytics.getCurrentSnapshotBatch": [{
36417
+ name: "deviceIds",
36418
+ form: "array",
36419
+ optional: false
36420
+ }],
36207
36421
  "zoneAnalytics.getUnzonedHistory": [{
36208
36422
  name: "deviceId",
36209
36423
  form: "single",
package/dist/index.mjs CHANGED
@@ -8014,6 +8014,20 @@ var RelocateJobSchema = object({
8014
8014
  * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
8015
8015
  */
8016
8016
  rowsReconciled: number().int().nonnegative().optional(),
8017
+ /**
8018
+ * Rows this run FORGOT because the file they name is not on disk.
8019
+ *
8020
+ * The mover derived the path from the row's own fields and `stat`ed it; an
8021
+ * ENOENT there is a per-path confirmation that the segment is gone (D296),
8022
+ * and the durable row is dropped through the same channel eviction uses. It
8023
+ * is reported for the same reason `rowsReconciled` is: this is a durable
8024
+ * mutation nobody asked for, and a migration that quietly erases hour rows is
8025
+ * the same failure as one that quietly skips them (D295).
8026
+ *
8027
+ * The production drain of 2026-08-30 would have reported 11 074 here — the
8028
+ * ledger claimed 5.65 GB of footage that no longer existed.
8029
+ */
8030
+ rowsForgotten: number().int().nonnegative().optional(),
8017
8031
  startedAt: number(),
8018
8032
  finishedAt: number().nullable(),
8019
8033
  error: string().nullable()
@@ -8377,6 +8391,91 @@ var RelocateResidueSchema = object({
8377
8391
  segments: number().int().nonnegative(),
8378
8392
  bytes: number().int().nonnegative()
8379
8393
  }).nullable();
8394
+ /**
8395
+ * Ask one location whether its durable hour rows describe the disk — the walk
8396
+ * (D319).
8397
+ *
8398
+ * `apply` DEFAULTS TO FALSE and that default is the product: the operator's
8399
+ * missing tool is the question, and the dry run is how they sanity-check the
8400
+ * destructive run before authorising it.
8401
+ */
8402
+ var LedgerWalkInputSchema = object({
8403
+ locationId: string().min(1),
8404
+ /** Forget the confirmed-absent rows, rather than only counting them. */
8405
+ apply: boolean().optional(),
8406
+ /** Narrow to one camera. */
8407
+ deviceId: number().int().positive().optional(),
8408
+ /** Narrow to these recording profiles; empty/absent = every profile. */
8409
+ profiles: array(string().min(1)).optional()
8410
+ });
8411
+ /** Why a whole walk did nothing. Every one leaves the ledger untouched. */
8412
+ var LedgerWalkRefusalSchema = _enum([
8413
+ "location-unknown",
8414
+ "source-writable",
8415
+ "no-ledger",
8416
+ "archive-unreadable",
8417
+ "anchor-absent",
8418
+ "anchor-unreadable",
8419
+ "anchor-moved"
8420
+ ]);
8421
+ _enum([
8422
+ "live-tail",
8423
+ "listing-error",
8424
+ "path-mismatch",
8425
+ "durable-refused"
8426
+ ]);
8427
+ /** Every skip reason, always present, always a number — so a reason that never
8428
+ * fired reports as zero rather than absent and the report shape is constant
8429
+ * between passes. Spelled out rather than `z.record` for exactly that. */
8430
+ var LedgerWalkSkipCountsSchema = object({
8431
+ "live-tail": number().int().nonnegative(),
8432
+ "listing-error": number().int().nonnegative(),
8433
+ "path-mismatch": number().int().nonnegative(),
8434
+ "durable-refused": number().int().nonnegative()
8435
+ });
8436
+ /** One camera's share of a walk, so a report names cameras and not rows. */
8437
+ var LedgerWalkDeviceReportSchema = object({
8438
+ deviceId: number().int(),
8439
+ hoursWalked: number().int().nonnegative(),
8440
+ hoursMissing: number().int().nonnegative(),
8441
+ ghostSegments: number().int().nonnegative(),
8442
+ ghostBytes: number().int().nonnegative(),
8443
+ forgottenSegments: number().int().nonnegative(),
8444
+ orphanFiles: number().int().nonnegative()
8445
+ });
8446
+ /**
8447
+ * What one walk claimed, listed, found and (only when armed) forgot.
8448
+ *
8449
+ * `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
8450
+ * walk that saw a fraction of the location is visible in its own report rather
8451
+ * than in the absence of one.
8452
+ */
8453
+ var LedgerWalkReportSchema = object({
8454
+ locationId: string(),
8455
+ applied: boolean(),
8456
+ refused: LedgerWalkRefusalSchema.nullable(),
8457
+ archiveSegments: number().int().nonnegative().nullable(),
8458
+ archiveBytes: number().int().nonnegative().nullable(),
8459
+ hoursClaimed: number().int().nonnegative(),
8460
+ hoursWalked: number().int().nonnegative(),
8461
+ hoursMissing: number().int().nonnegative(),
8462
+ /** `readdir` calls issued — the cost, stated in the unit that is paid. */
8463
+ listings: number().int().nonnegative(),
8464
+ segmentsClaimed: number().int().nonnegative(),
8465
+ ghostSegments: number().int().nonnegative(),
8466
+ ghostBytes: number().int().nonnegative(),
8467
+ ghostHoursWhole: number().int().nonnegative(),
8468
+ forgottenSegments: number().int().nonnegative(),
8469
+ forgottenBytes: number().int().nonnegative(),
8470
+ /** Files under a claimed hour that no durable row names. Never deleted. */
8471
+ orphanFiles: number().int().nonnegative(),
8472
+ orphanSample: array(string()).readonly(),
8473
+ hoursSkipped: number().int().nonnegative(),
8474
+ skippedByReason: LedgerWalkSkipCountsSchema,
8475
+ /** The walk stopped at its per-pass hour bound with claims unwalked. */
8476
+ bounded: boolean(),
8477
+ byDevice: array(LedgerWalkDeviceReportSchema).readonly()
8478
+ });
8380
8479
  /** How many rows a media pass would still act on against a given target — the
8381
8480
  * media lane's denominator AND its residue, from ONE derivation so the two can
8382
8481
  * never disagree. `null` = the count could not be taken. */
@@ -18780,13 +18879,15 @@ var ListGroupsPageSchema = object({
18780
18879
  groups: array(AnalyticsGroupRecordSchema).readonly(),
18781
18880
  nextCursor: string().nullable()
18782
18881
  });
18882
+ var KEY_EVENTS_DEFAULT_LIMIT = 50;
18883
+ var KEY_EVENTS_MAX_LIMIT = 200;
18783
18884
  var KeyEventQueryInput = object({
18784
18885
  deviceId: number(),
18785
18886
  /** Window lower bound (track firstSeen ≥ since). */
18786
18887
  since: number(),
18787
18888
  /** Window upper bound (track firstSeen ≤ until). */
18788
18889
  until: number(),
18789
- limit: number().int().min(1).max(200).default(50),
18890
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18790
18891
  /** Drop tracks scoring below this importance. */
18791
18892
  minImportance: number().min(0).max(1).optional(),
18792
18893
  /** Restrict to a single class (e.g. 'person'). */
@@ -18808,6 +18909,32 @@ var KeyEventSchema = object({
18808
18909
  ...TrackFlagFields,
18809
18910
  ...TrackRetrainFields
18810
18911
  });
18912
+ /** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
18913
+ var KeyEventBatchQueryInput = object({
18914
+ deviceIds: array(number()).min(1).max(200),
18915
+ since: number(),
18916
+ until: number(),
18917
+ /** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
18918
+ * across the set, which would let a busy camera starve a quiet one of its
18919
+ * rows and change what the merged feed contains. */
18920
+ limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
18921
+ minImportance: number().min(0).max(1).optional(),
18922
+ classFilter: string().optional()
18923
+ });
18924
+ /**
18925
+ * One camera's key events in a batch answer.
18926
+ *
18927
+ * The row exists for every requested id. `getKeyEvents` degrades to `[]` on
18928
+ * error rather than throwing, so a camera whose store read failed and one with
18929
+ * no events in the window were ALREADY indistinguishable per camera — the
18930
+ * batch does not make that worse, and the row keeps the deviceId the single
18931
+ * method's output never carried (the caller used to stamp it from the fan-out
18932
+ * key, which only worked because there was one query per camera).
18933
+ */
18934
+ var KeyEventsForDeviceSchema = object({
18935
+ deviceId: number(),
18936
+ events: array(KeyEventSchema).readonly()
18937
+ });
18811
18938
  object({
18812
18939
  trackId: string(),
18813
18940
  className: string(),
@@ -19077,7 +19204,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19077
19204
  until: number().optional(),
19078
19205
  kinds: array(string()).optional(),
19079
19206
  limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
19080
- }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
19207
+ }), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
19081
19208
  deviceId: number(),
19082
19209
  since: number(),
19083
19210
  until: number(),
@@ -26729,6 +26856,9 @@ method(object({
26729
26856
  }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
26730
26857
  kind: "query",
26731
26858
  auth: "admin"
26859
+ }), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
26860
+ kind: "mutation",
26861
+ auth: "admin"
26732
26862
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
26733
26863
  kind: "mutation",
26734
26864
  auth: "admin"
@@ -27120,7 +27250,26 @@ var SceneMonitorStatusSchema = object({
27120
27250
  monitors: array(SceneMonitorSchema),
27121
27251
  lastFetchedAt: number()
27122
27252
  });
27123
- DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({
27253
+ /**
27254
+ * One camera's row in a `listScenesBatch` answer.
27255
+ *
27256
+ * `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
27257
+ * is a `defaultActive` wrapper, so every camera is asked; a camera whose
27258
+ * provider is absent (pipeline-analytics not deployed, the post-processing node
27259
+ * down) cannot answer, and that is not the same fact as a camera with no scenes
27260
+ * configured. Fanned out per camera the difference was visible — one query
27261
+ * errored while the others resolved — and a batch that returned only the rows
27262
+ * it managed would have destroyed it, silently, by making an unreachable camera
27263
+ * indistinguishable from one that answered `monitors: []`.
27264
+ *
27265
+ * So: EVERY requested deviceId gets a row. `status: null` means "this camera
27266
+ * could not be read"; `status.monitors: []` means "read, and it has none".
27267
+ */
27268
+ var SceneMonitorStatusForDeviceSchema = object({
27269
+ deviceId: number(),
27270
+ status: SceneMonitorStatusSchema.nullable()
27271
+ });
27272
+ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
27124
27273
  deviceId: number(),
27125
27274
  label: string(),
27126
27275
  roi: MaskRectShapeSchema,
@@ -28444,6 +28593,27 @@ var CameraOccupancySnapshotSchema = object({
28444
28593
  stationaryObjects: array(StationaryObjectSchema).readonly().optional()
28445
28594
  });
28446
28595
  /**
28596
+ * One camera's row in a `getCurrentSnapshotBatch` answer.
28597
+ *
28598
+ * THREE outcomes, and the single-camera method could only express two of them
28599
+ * because `snapshot: null` was already spoken for:
28600
+ *
28601
+ * - `read: 'read'`, `snapshot` present — the live occupancy reading.
28602
+ * - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
28603
+ * yet: no frame since boot, and no parked-object registry to hydrate from.
28604
+ * - `read: 'unreadable'` — the owner could not answer for this
28605
+ * camera. `snapshot` is null, and it does NOT mean "nothing parked here".
28606
+ *
28607
+ * Collapsing the last two is the failure this field exists to prevent: a
28608
+ * hydration that threw would otherwise render as an empty Stationary section,
28609
+ * which is a definite claim about a camera nobody could read.
28610
+ */
28611
+ var CameraOccupancySnapshotForDeviceSchema = object({
28612
+ deviceId: number(),
28613
+ read: _enum(["read", "unreadable"]),
28614
+ snapshot: CameraOccupancySnapshotSchema.nullable()
28615
+ });
28616
+ /**
28447
28617
  * Time-series resolution. The history methods return one bucket per
28448
28618
  * step over the requested range. Smaller resolutions cost more
28449
28619
  * memory + bandwidth; bound to discrete steps so caller cannot ask
@@ -28467,7 +28637,7 @@ var HistoryPointSchema = object({
28467
28637
  /** Object count averaged over the bucket (rounded to nearest integer). */
28468
28638
  count: number().int().nonnegative()
28469
28639
  });
28470
- DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
28640
+ DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
28471
28641
  deviceId: number(),
28472
28642
  zoneId: string(),
28473
28643
  className: string().optional()
@@ -31772,6 +31942,12 @@ Object.freeze({
31772
31942
  addonId: null,
31773
31943
  access: "view"
31774
31944
  },
31945
+ "pipelineAnalytics.getKeyEventsBatch": {
31946
+ capName: "pipeline-analytics",
31947
+ capScope: "device",
31948
+ addonId: null,
31949
+ access: "view"
31950
+ },
31775
31951
  "pipelineAnalytics.getMotionEvents": {
31776
31952
  capName: "pipeline-analytics",
31777
31953
  capScope: "device",
@@ -32948,6 +33124,12 @@ Object.freeze({
32948
33124
  addonId: null,
32949
33125
  access: "view"
32950
33126
  },
33127
+ "recording.reconcileLedgerAgainstDisk": {
33128
+ capName: "recording",
33129
+ capScope: "system",
33130
+ addonId: null,
33131
+ access: "create"
33132
+ },
32951
33133
  "recording.refreshStorageLocationsForMigration": {
32952
33134
  capName: "recording",
32953
33135
  capScope: "system",
@@ -33074,6 +33256,12 @@ Object.freeze({
33074
33256
  addonId: null,
33075
33257
  access: "view"
33076
33258
  },
33259
+ "sceneMonitor.listScenesBatch": {
33260
+ capName: "scene-monitor",
33261
+ capScope: "device",
33262
+ addonId: null,
33263
+ access: "view"
33264
+ },
33077
33265
  "sceneMonitor.recheckNow": {
33078
33266
  capName: "scene-monitor",
33079
33267
  capScope: "device",
@@ -34430,6 +34618,12 @@ Object.freeze({
34430
34618
  addonId: null,
34431
34619
  access: "view"
34432
34620
  },
34621
+ "zoneAnalytics.getCurrentSnapshotBatch": {
34622
+ capName: "zone-analytics",
34623
+ capScope: "device",
34624
+ addonId: null,
34625
+ access: "view"
34626
+ },
34433
34627
  "zoneAnalytics.getUnzonedHistory": {
34434
34628
  capName: "zone-analytics",
34435
34629
  capScope: "device",
@@ -35434,6 +35628,11 @@ Object.freeze({
35434
35628
  form: "single",
35435
35629
  optional: false
35436
35630
  }],
35631
+ "pipelineAnalytics.getKeyEventsBatch": [{
35632
+ name: "deviceIds",
35633
+ form: "array",
35634
+ optional: false
35635
+ }],
35437
35636
  "pipelineAnalytics.getMotionEvents": [{
35438
35637
  name: "deviceId",
35439
35638
  form: "single",
@@ -35874,6 +36073,11 @@ Object.freeze({
35874
36073
  form: "single",
35875
36074
  optional: false
35876
36075
  }],
36076
+ "recording.reconcileLedgerAgainstDisk": [{
36077
+ name: "deviceId",
36078
+ form: "single",
36079
+ optional: true
36080
+ }],
35877
36081
  "recording.relocateFootage": [{
35878
36082
  name: "deviceId",
35879
36083
  form: "single",
@@ -35939,6 +36143,11 @@ Object.freeze({
35939
36143
  form: "single",
35940
36144
  optional: false
35941
36145
  }],
36146
+ "sceneMonitor.listScenesBatch": [{
36147
+ name: "deviceIds",
36148
+ form: "array",
36149
+ optional: false
36150
+ }],
35942
36151
  "sceneMonitor.recheckNow": [{
35943
36152
  name: "deviceId",
35944
36153
  form: "single",
@@ -36200,6 +36409,11 @@ Object.freeze({
36200
36409
  form: "single",
36201
36410
  optional: false
36202
36411
  }],
36412
+ "zoneAnalytics.getCurrentSnapshotBatch": [{
36413
+ name: "deviceIds",
36414
+ form: "array",
36415
+ optional: false
36416
+ }],
36203
36417
  "zoneAnalytics.getUnzonedHistory": [{
36204
36418
  name: "deviceId",
36205
36419
  form: "single",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-decoder-nodeav",
3
- "version": "1.2.48",
3
+ "version": "1.2.49",
4
4
  "description": "Standalone in-process node-av decoder addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",