@camstack/addon-provider-onvif 1.2.47 → 1.2.48
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 +218 -4
- package/dist/addon.mjs +218 -4
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8017,6 +8017,20 @@ var RelocateJobSchema = object({
|
|
|
8017
8017
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8018
8018
|
*/
|
|
8019
8019
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8020
|
+
/**
|
|
8021
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8022
|
+
*
|
|
8023
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8024
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8025
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8026
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8027
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8028
|
+
* the same failure as one that quietly skips them (D295).
|
|
8029
|
+
*
|
|
8030
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8031
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8032
|
+
*/
|
|
8033
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8020
8034
|
startedAt: number(),
|
|
8021
8035
|
finishedAt: number().nullable(),
|
|
8022
8036
|
error: string().nullable()
|
|
@@ -8380,6 +8394,91 @@ var RelocateResidueSchema = object({
|
|
|
8380
8394
|
segments: number().int().nonnegative(),
|
|
8381
8395
|
bytes: number().int().nonnegative()
|
|
8382
8396
|
}).nullable();
|
|
8397
|
+
/**
|
|
8398
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8399
|
+
* (D319).
|
|
8400
|
+
*
|
|
8401
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8402
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8403
|
+
* destructive run before authorising it.
|
|
8404
|
+
*/
|
|
8405
|
+
var LedgerWalkInputSchema = object({
|
|
8406
|
+
locationId: string().min(1),
|
|
8407
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8408
|
+
apply: boolean().optional(),
|
|
8409
|
+
/** Narrow to one camera. */
|
|
8410
|
+
deviceId: number().int().positive().optional(),
|
|
8411
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8412
|
+
profiles: array(string().min(1)).optional()
|
|
8413
|
+
});
|
|
8414
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8415
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8416
|
+
"location-unknown",
|
|
8417
|
+
"source-writable",
|
|
8418
|
+
"no-ledger",
|
|
8419
|
+
"archive-unreadable",
|
|
8420
|
+
"anchor-absent",
|
|
8421
|
+
"anchor-unreadable",
|
|
8422
|
+
"anchor-moved"
|
|
8423
|
+
]);
|
|
8424
|
+
_enum([
|
|
8425
|
+
"live-tail",
|
|
8426
|
+
"listing-error",
|
|
8427
|
+
"path-mismatch",
|
|
8428
|
+
"durable-refused"
|
|
8429
|
+
]);
|
|
8430
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8431
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8432
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8433
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8434
|
+
"live-tail": number().int().nonnegative(),
|
|
8435
|
+
"listing-error": number().int().nonnegative(),
|
|
8436
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8437
|
+
"durable-refused": number().int().nonnegative()
|
|
8438
|
+
});
|
|
8439
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8440
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8441
|
+
deviceId: number().int(),
|
|
8442
|
+
hoursWalked: number().int().nonnegative(),
|
|
8443
|
+
hoursMissing: number().int().nonnegative(),
|
|
8444
|
+
ghostSegments: number().int().nonnegative(),
|
|
8445
|
+
ghostBytes: number().int().nonnegative(),
|
|
8446
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8447
|
+
orphanFiles: number().int().nonnegative()
|
|
8448
|
+
});
|
|
8449
|
+
/**
|
|
8450
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8451
|
+
*
|
|
8452
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8453
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8454
|
+
* than in the absence of one.
|
|
8455
|
+
*/
|
|
8456
|
+
var LedgerWalkReportSchema = object({
|
|
8457
|
+
locationId: string(),
|
|
8458
|
+
applied: boolean(),
|
|
8459
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8460
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8461
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8462
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8463
|
+
hoursWalked: number().int().nonnegative(),
|
|
8464
|
+
hoursMissing: number().int().nonnegative(),
|
|
8465
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8466
|
+
listings: number().int().nonnegative(),
|
|
8467
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8468
|
+
ghostSegments: number().int().nonnegative(),
|
|
8469
|
+
ghostBytes: number().int().nonnegative(),
|
|
8470
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8471
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8472
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8473
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8474
|
+
orphanFiles: number().int().nonnegative(),
|
|
8475
|
+
orphanSample: array(string()).readonly(),
|
|
8476
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8477
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8478
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8479
|
+
bounded: boolean(),
|
|
8480
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8481
|
+
});
|
|
8383
8482
|
/** How many rows a media pass would still act on against a given target — the
|
|
8384
8483
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8385
8484
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18708,13 +18807,15 @@ var ListGroupsPageSchema = object({
|
|
|
18708
18807
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18709
18808
|
nextCursor: string().nullable()
|
|
18710
18809
|
});
|
|
18810
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
18811
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18711
18812
|
var KeyEventQueryInput = object({
|
|
18712
18813
|
deviceId: number(),
|
|
18713
18814
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18714
18815
|
since: number(),
|
|
18715
18816
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18716
18817
|
until: number(),
|
|
18717
|
-
limit: number().int().min(1).max(
|
|
18818
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18718
18819
|
/** Drop tracks scoring below this importance. */
|
|
18719
18820
|
minImportance: number().min(0).max(1).optional(),
|
|
18720
18821
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18736,6 +18837,32 @@ var KeyEventSchema = object({
|
|
|
18736
18837
|
...TrackFlagFields,
|
|
18737
18838
|
...TrackRetrainFields
|
|
18738
18839
|
});
|
|
18840
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
18841
|
+
var KeyEventBatchQueryInput = object({
|
|
18842
|
+
deviceIds: array(number()).min(1).max(200),
|
|
18843
|
+
since: number(),
|
|
18844
|
+
until: number(),
|
|
18845
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
18846
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
18847
|
+
* rows and change what the merged feed contains. */
|
|
18848
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18849
|
+
minImportance: number().min(0).max(1).optional(),
|
|
18850
|
+
classFilter: string().optional()
|
|
18851
|
+
});
|
|
18852
|
+
/**
|
|
18853
|
+
* One camera's key events in a batch answer.
|
|
18854
|
+
*
|
|
18855
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
18856
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
18857
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
18858
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
18859
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
18860
|
+
* key, which only worked because there was one query per camera).
|
|
18861
|
+
*/
|
|
18862
|
+
var KeyEventsForDeviceSchema = object({
|
|
18863
|
+
deviceId: number(),
|
|
18864
|
+
events: array(KeyEventSchema).readonly()
|
|
18865
|
+
});
|
|
18739
18866
|
object({
|
|
18740
18867
|
trackId: string(),
|
|
18741
18868
|
className: string(),
|
|
@@ -19005,7 +19132,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19005
19132
|
until: number().optional(),
|
|
19006
19133
|
kinds: array(string()).optional(),
|
|
19007
19134
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19008
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19135
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19009
19136
|
deviceId: number(),
|
|
19010
19137
|
since: number(),
|
|
19011
19138
|
until: number(),
|
|
@@ -26803,6 +26930,9 @@ method(object({
|
|
|
26803
26930
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26804
26931
|
kind: "query",
|
|
26805
26932
|
auth: "admin"
|
|
26933
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
26934
|
+
kind: "mutation",
|
|
26935
|
+
auth: "admin"
|
|
26806
26936
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26807
26937
|
kind: "mutation",
|
|
26808
26938
|
auth: "admin"
|
|
@@ -27194,7 +27324,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27194
27324
|
monitors: array(SceneMonitorSchema),
|
|
27195
27325
|
lastFetchedAt: number()
|
|
27196
27326
|
});
|
|
27197
|
-
|
|
27327
|
+
/**
|
|
27328
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27329
|
+
*
|
|
27330
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27331
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27332
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27333
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27334
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27335
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27336
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27337
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27338
|
+
*
|
|
27339
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27340
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27341
|
+
*/
|
|
27342
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27343
|
+
deviceId: number(),
|
|
27344
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27345
|
+
});
|
|
27346
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27198
27347
|
deviceId: number(),
|
|
27199
27348
|
label: string(),
|
|
27200
27349
|
roi: MaskRectShapeSchema,
|
|
@@ -28518,6 +28667,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28518
28667
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28519
28668
|
});
|
|
28520
28669
|
/**
|
|
28670
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28671
|
+
*
|
|
28672
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28673
|
+
* because `snapshot: null` was already spoken for:
|
|
28674
|
+
*
|
|
28675
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28676
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28677
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28678
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28679
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28680
|
+
*
|
|
28681
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28682
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28683
|
+
* which is a definite claim about a camera nobody could read.
|
|
28684
|
+
*/
|
|
28685
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28686
|
+
deviceId: number(),
|
|
28687
|
+
read: _enum(["read", "unreadable"]),
|
|
28688
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28689
|
+
});
|
|
28690
|
+
/**
|
|
28521
28691
|
* Time-series resolution. The history methods return one bucket per
|
|
28522
28692
|
* step over the requested range. Smaller resolutions cost more
|
|
28523
28693
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28541,7 +28711,7 @@ var HistoryPointSchema = object({
|
|
|
28541
28711
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28542
28712
|
count: number().int().nonnegative()
|
|
28543
28713
|
});
|
|
28544
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28714
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28545
28715
|
deviceId: number(),
|
|
28546
28716
|
zoneId: string(),
|
|
28547
28717
|
className: string().optional()
|
|
@@ -32256,6 +32426,12 @@ Object.freeze({
|
|
|
32256
32426
|
addonId: null,
|
|
32257
32427
|
access: "view"
|
|
32258
32428
|
},
|
|
32429
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32430
|
+
capName: "pipeline-analytics",
|
|
32431
|
+
capScope: "device",
|
|
32432
|
+
addonId: null,
|
|
32433
|
+
access: "view"
|
|
32434
|
+
},
|
|
32259
32435
|
"pipelineAnalytics.getMotionEvents": {
|
|
32260
32436
|
capName: "pipeline-analytics",
|
|
32261
32437
|
capScope: "device",
|
|
@@ -33432,6 +33608,12 @@ Object.freeze({
|
|
|
33432
33608
|
addonId: null,
|
|
33433
33609
|
access: "view"
|
|
33434
33610
|
},
|
|
33611
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33612
|
+
capName: "recording",
|
|
33613
|
+
capScope: "system",
|
|
33614
|
+
addonId: null,
|
|
33615
|
+
access: "create"
|
|
33616
|
+
},
|
|
33435
33617
|
"recording.refreshStorageLocationsForMigration": {
|
|
33436
33618
|
capName: "recording",
|
|
33437
33619
|
capScope: "system",
|
|
@@ -33558,6 +33740,12 @@ Object.freeze({
|
|
|
33558
33740
|
addonId: null,
|
|
33559
33741
|
access: "view"
|
|
33560
33742
|
},
|
|
33743
|
+
"sceneMonitor.listScenesBatch": {
|
|
33744
|
+
capName: "scene-monitor",
|
|
33745
|
+
capScope: "device",
|
|
33746
|
+
addonId: null,
|
|
33747
|
+
access: "view"
|
|
33748
|
+
},
|
|
33561
33749
|
"sceneMonitor.recheckNow": {
|
|
33562
33750
|
capName: "scene-monitor",
|
|
33563
33751
|
capScope: "device",
|
|
@@ -34914,6 +35102,12 @@ Object.freeze({
|
|
|
34914
35102
|
addonId: null,
|
|
34915
35103
|
access: "view"
|
|
34916
35104
|
},
|
|
35105
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
35106
|
+
capName: "zone-analytics",
|
|
35107
|
+
capScope: "device",
|
|
35108
|
+
addonId: null,
|
|
35109
|
+
access: "view"
|
|
35110
|
+
},
|
|
34917
35111
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34918
35112
|
capName: "zone-analytics",
|
|
34919
35113
|
capScope: "device",
|
|
@@ -35918,6 +36112,11 @@ Object.freeze({
|
|
|
35918
36112
|
form: "single",
|
|
35919
36113
|
optional: false
|
|
35920
36114
|
}],
|
|
36115
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
36116
|
+
name: "deviceIds",
|
|
36117
|
+
form: "array",
|
|
36118
|
+
optional: false
|
|
36119
|
+
}],
|
|
35921
36120
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35922
36121
|
name: "deviceId",
|
|
35923
36122
|
form: "single",
|
|
@@ -36358,6 +36557,11 @@ Object.freeze({
|
|
|
36358
36557
|
form: "single",
|
|
36359
36558
|
optional: false
|
|
36360
36559
|
}],
|
|
36560
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36561
|
+
name: "deviceId",
|
|
36562
|
+
form: "single",
|
|
36563
|
+
optional: true
|
|
36564
|
+
}],
|
|
36361
36565
|
"recording.relocateFootage": [{
|
|
36362
36566
|
name: "deviceId",
|
|
36363
36567
|
form: "single",
|
|
@@ -36423,6 +36627,11 @@ Object.freeze({
|
|
|
36423
36627
|
form: "single",
|
|
36424
36628
|
optional: false
|
|
36425
36629
|
}],
|
|
36630
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36631
|
+
name: "deviceIds",
|
|
36632
|
+
form: "array",
|
|
36633
|
+
optional: false
|
|
36634
|
+
}],
|
|
36426
36635
|
"sceneMonitor.recheckNow": [{
|
|
36427
36636
|
name: "deviceId",
|
|
36428
36637
|
form: "single",
|
|
@@ -36684,6 +36893,11 @@ Object.freeze({
|
|
|
36684
36893
|
form: "single",
|
|
36685
36894
|
optional: false
|
|
36686
36895
|
}],
|
|
36896
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36897
|
+
name: "deviceIds",
|
|
36898
|
+
form: "array",
|
|
36899
|
+
optional: false
|
|
36900
|
+
}],
|
|
36687
36901
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36688
36902
|
name: "deviceId",
|
|
36689
36903
|
form: "single",
|
package/dist/addon.mjs
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. */
|
|
@@ -18709,13 +18808,15 @@ var ListGroupsPageSchema = object({
|
|
|
18709
18808
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18710
18809
|
nextCursor: string().nullable()
|
|
18711
18810
|
});
|
|
18811
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
18812
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18712
18813
|
var KeyEventQueryInput = object({
|
|
18713
18814
|
deviceId: number(),
|
|
18714
18815
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18715
18816
|
since: number(),
|
|
18716
18817
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18717
18818
|
until: number(),
|
|
18718
|
-
limit: number().int().min(1).max(
|
|
18819
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18719
18820
|
/** Drop tracks scoring below this importance. */
|
|
18720
18821
|
minImportance: number().min(0).max(1).optional(),
|
|
18721
18822
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18737,6 +18838,32 @@ var KeyEventSchema = object({
|
|
|
18737
18838
|
...TrackFlagFields,
|
|
18738
18839
|
...TrackRetrainFields
|
|
18739
18840
|
});
|
|
18841
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
18842
|
+
var KeyEventBatchQueryInput = object({
|
|
18843
|
+
deviceIds: array(number()).min(1).max(200),
|
|
18844
|
+
since: number(),
|
|
18845
|
+
until: number(),
|
|
18846
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
18847
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
18848
|
+
* rows and change what the merged feed contains. */
|
|
18849
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18850
|
+
minImportance: number().min(0).max(1).optional(),
|
|
18851
|
+
classFilter: string().optional()
|
|
18852
|
+
});
|
|
18853
|
+
/**
|
|
18854
|
+
* One camera's key events in a batch answer.
|
|
18855
|
+
*
|
|
18856
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
18857
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
18858
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
18859
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
18860
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
18861
|
+
* key, which only worked because there was one query per camera).
|
|
18862
|
+
*/
|
|
18863
|
+
var KeyEventsForDeviceSchema = object({
|
|
18864
|
+
deviceId: number(),
|
|
18865
|
+
events: array(KeyEventSchema).readonly()
|
|
18866
|
+
});
|
|
18740
18867
|
object({
|
|
18741
18868
|
trackId: string(),
|
|
18742
18869
|
className: string(),
|
|
@@ -19006,7 +19133,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19006
19133
|
until: number().optional(),
|
|
19007
19134
|
kinds: array(string()).optional(),
|
|
19008
19135
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19009
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19136
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19010
19137
|
deviceId: number(),
|
|
19011
19138
|
since: number(),
|
|
19012
19139
|
until: number(),
|
|
@@ -26804,6 +26931,9 @@ method(object({
|
|
|
26804
26931
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26805
26932
|
kind: "query",
|
|
26806
26933
|
auth: "admin"
|
|
26934
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
26935
|
+
kind: "mutation",
|
|
26936
|
+
auth: "admin"
|
|
26807
26937
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26808
26938
|
kind: "mutation",
|
|
26809
26939
|
auth: "admin"
|
|
@@ -27195,7 +27325,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27195
27325
|
monitors: array(SceneMonitorSchema),
|
|
27196
27326
|
lastFetchedAt: number()
|
|
27197
27327
|
});
|
|
27198
|
-
|
|
27328
|
+
/**
|
|
27329
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27330
|
+
*
|
|
27331
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27332
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27333
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27334
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27335
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27336
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27337
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27338
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27339
|
+
*
|
|
27340
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27341
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27342
|
+
*/
|
|
27343
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27344
|
+
deviceId: number(),
|
|
27345
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27346
|
+
});
|
|
27347
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27199
27348
|
deviceId: number(),
|
|
27200
27349
|
label: string(),
|
|
27201
27350
|
roi: MaskRectShapeSchema,
|
|
@@ -28519,6 +28668,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28519
28668
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28520
28669
|
});
|
|
28521
28670
|
/**
|
|
28671
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28672
|
+
*
|
|
28673
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28674
|
+
* because `snapshot: null` was already spoken for:
|
|
28675
|
+
*
|
|
28676
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28677
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28678
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28679
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28680
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28681
|
+
*
|
|
28682
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28683
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28684
|
+
* which is a definite claim about a camera nobody could read.
|
|
28685
|
+
*/
|
|
28686
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28687
|
+
deviceId: number(),
|
|
28688
|
+
read: _enum(["read", "unreadable"]),
|
|
28689
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28690
|
+
});
|
|
28691
|
+
/**
|
|
28522
28692
|
* Time-series resolution. The history methods return one bucket per
|
|
28523
28693
|
* step over the requested range. Smaller resolutions cost more
|
|
28524
28694
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28542,7 +28712,7 @@ var HistoryPointSchema = object({
|
|
|
28542
28712
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28543
28713
|
count: number().int().nonnegative()
|
|
28544
28714
|
});
|
|
28545
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28715
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28546
28716
|
deviceId: number(),
|
|
28547
28717
|
zoneId: string(),
|
|
28548
28718
|
className: string().optional()
|
|
@@ -32257,6 +32427,12 @@ Object.freeze({
|
|
|
32257
32427
|
addonId: null,
|
|
32258
32428
|
access: "view"
|
|
32259
32429
|
},
|
|
32430
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32431
|
+
capName: "pipeline-analytics",
|
|
32432
|
+
capScope: "device",
|
|
32433
|
+
addonId: null,
|
|
32434
|
+
access: "view"
|
|
32435
|
+
},
|
|
32260
32436
|
"pipelineAnalytics.getMotionEvents": {
|
|
32261
32437
|
capName: "pipeline-analytics",
|
|
32262
32438
|
capScope: "device",
|
|
@@ -33433,6 +33609,12 @@ Object.freeze({
|
|
|
33433
33609
|
addonId: null,
|
|
33434
33610
|
access: "view"
|
|
33435
33611
|
},
|
|
33612
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33613
|
+
capName: "recording",
|
|
33614
|
+
capScope: "system",
|
|
33615
|
+
addonId: null,
|
|
33616
|
+
access: "create"
|
|
33617
|
+
},
|
|
33436
33618
|
"recording.refreshStorageLocationsForMigration": {
|
|
33437
33619
|
capName: "recording",
|
|
33438
33620
|
capScope: "system",
|
|
@@ -33559,6 +33741,12 @@ Object.freeze({
|
|
|
33559
33741
|
addonId: null,
|
|
33560
33742
|
access: "view"
|
|
33561
33743
|
},
|
|
33744
|
+
"sceneMonitor.listScenesBatch": {
|
|
33745
|
+
capName: "scene-monitor",
|
|
33746
|
+
capScope: "device",
|
|
33747
|
+
addonId: null,
|
|
33748
|
+
access: "view"
|
|
33749
|
+
},
|
|
33562
33750
|
"sceneMonitor.recheckNow": {
|
|
33563
33751
|
capName: "scene-monitor",
|
|
33564
33752
|
capScope: "device",
|
|
@@ -34915,6 +35103,12 @@ Object.freeze({
|
|
|
34915
35103
|
addonId: null,
|
|
34916
35104
|
access: "view"
|
|
34917
35105
|
},
|
|
35106
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
35107
|
+
capName: "zone-analytics",
|
|
35108
|
+
capScope: "device",
|
|
35109
|
+
addonId: null,
|
|
35110
|
+
access: "view"
|
|
35111
|
+
},
|
|
34918
35112
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34919
35113
|
capName: "zone-analytics",
|
|
34920
35114
|
capScope: "device",
|
|
@@ -35919,6 +36113,11 @@ Object.freeze({
|
|
|
35919
36113
|
form: "single",
|
|
35920
36114
|
optional: false
|
|
35921
36115
|
}],
|
|
36116
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
36117
|
+
name: "deviceIds",
|
|
36118
|
+
form: "array",
|
|
36119
|
+
optional: false
|
|
36120
|
+
}],
|
|
35922
36121
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35923
36122
|
name: "deviceId",
|
|
35924
36123
|
form: "single",
|
|
@@ -36359,6 +36558,11 @@ Object.freeze({
|
|
|
36359
36558
|
form: "single",
|
|
36360
36559
|
optional: false
|
|
36361
36560
|
}],
|
|
36561
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36562
|
+
name: "deviceId",
|
|
36563
|
+
form: "single",
|
|
36564
|
+
optional: true
|
|
36565
|
+
}],
|
|
36362
36566
|
"recording.relocateFootage": [{
|
|
36363
36567
|
name: "deviceId",
|
|
36364
36568
|
form: "single",
|
|
@@ -36424,6 +36628,11 @@ Object.freeze({
|
|
|
36424
36628
|
form: "single",
|
|
36425
36629
|
optional: false
|
|
36426
36630
|
}],
|
|
36631
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36632
|
+
name: "deviceIds",
|
|
36633
|
+
form: "array",
|
|
36634
|
+
optional: false
|
|
36635
|
+
}],
|
|
36427
36636
|
"sceneMonitor.recheckNow": [{
|
|
36428
36637
|
name: "deviceId",
|
|
36429
36638
|
form: "single",
|
|
@@ -36685,6 +36894,11 @@ Object.freeze({
|
|
|
36685
36894
|
form: "single",
|
|
36686
36895
|
optional: false
|
|
36687
36896
|
}],
|
|
36897
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36898
|
+
name: "deviceIds",
|
|
36899
|
+
form: "array",
|
|
36900
|
+
optional: false
|
|
36901
|
+
}],
|
|
36688
36902
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36689
36903
|
name: "deviceId",
|
|
36690
36904
|
form: "single",
|