@camstack/addon-provider-reolink 1.2.71 → 1.2.72
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 +246 -2
- package/dist/addon.mjs +246 -2
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8308,6 +8308,20 @@ var RelocateJobSchema = object({
|
|
|
8308
8308
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8309
8309
|
*/
|
|
8310
8310
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8311
|
+
/**
|
|
8312
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8313
|
+
*
|
|
8314
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8315
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8316
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8317
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8318
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8319
|
+
* the same failure as one that quietly skips them (D295).
|
|
8320
|
+
*
|
|
8321
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8322
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8323
|
+
*/
|
|
8324
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8311
8325
|
startedAt: number(),
|
|
8312
8326
|
finishedAt: number().nullable(),
|
|
8313
8327
|
error: string().nullable()
|
|
@@ -8671,6 +8685,91 @@ var RelocateResidueSchema = object({
|
|
|
8671
8685
|
segments: number().int().nonnegative(),
|
|
8672
8686
|
bytes: number().int().nonnegative()
|
|
8673
8687
|
}).nullable();
|
|
8688
|
+
/**
|
|
8689
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8690
|
+
* (D319).
|
|
8691
|
+
*
|
|
8692
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8693
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8694
|
+
* destructive run before authorising it.
|
|
8695
|
+
*/
|
|
8696
|
+
var LedgerWalkInputSchema = object({
|
|
8697
|
+
locationId: string().min(1),
|
|
8698
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8699
|
+
apply: boolean().optional(),
|
|
8700
|
+
/** Narrow to one camera. */
|
|
8701
|
+
deviceId: number().int().positive().optional(),
|
|
8702
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8703
|
+
profiles: array(string().min(1)).optional()
|
|
8704
|
+
});
|
|
8705
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8706
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8707
|
+
"location-unknown",
|
|
8708
|
+
"source-writable",
|
|
8709
|
+
"no-ledger",
|
|
8710
|
+
"archive-unreadable",
|
|
8711
|
+
"anchor-absent",
|
|
8712
|
+
"anchor-unreadable",
|
|
8713
|
+
"anchor-moved"
|
|
8714
|
+
]);
|
|
8715
|
+
_enum([
|
|
8716
|
+
"live-tail",
|
|
8717
|
+
"listing-error",
|
|
8718
|
+
"path-mismatch",
|
|
8719
|
+
"durable-refused"
|
|
8720
|
+
]);
|
|
8721
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8722
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8723
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8724
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8725
|
+
"live-tail": number().int().nonnegative(),
|
|
8726
|
+
"listing-error": number().int().nonnegative(),
|
|
8727
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8728
|
+
"durable-refused": number().int().nonnegative()
|
|
8729
|
+
});
|
|
8730
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8731
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8732
|
+
deviceId: number().int(),
|
|
8733
|
+
hoursWalked: number().int().nonnegative(),
|
|
8734
|
+
hoursMissing: number().int().nonnegative(),
|
|
8735
|
+
ghostSegments: number().int().nonnegative(),
|
|
8736
|
+
ghostBytes: number().int().nonnegative(),
|
|
8737
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8738
|
+
orphanFiles: number().int().nonnegative()
|
|
8739
|
+
});
|
|
8740
|
+
/**
|
|
8741
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8742
|
+
*
|
|
8743
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8744
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8745
|
+
* than in the absence of one.
|
|
8746
|
+
*/
|
|
8747
|
+
var LedgerWalkReportSchema = object({
|
|
8748
|
+
locationId: string(),
|
|
8749
|
+
applied: boolean(),
|
|
8750
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8751
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8752
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8753
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8754
|
+
hoursWalked: number().int().nonnegative(),
|
|
8755
|
+
hoursMissing: number().int().nonnegative(),
|
|
8756
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8757
|
+
listings: number().int().nonnegative(),
|
|
8758
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8759
|
+
ghostSegments: number().int().nonnegative(),
|
|
8760
|
+
ghostBytes: number().int().nonnegative(),
|
|
8761
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8762
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8763
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8764
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8765
|
+
orphanFiles: number().int().nonnegative(),
|
|
8766
|
+
orphanSample: array(string()).readonly(),
|
|
8767
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8768
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8769
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8770
|
+
bounded: boolean(),
|
|
8771
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8772
|
+
});
|
|
8674
8773
|
/** How many rows a media pass would still act on against a given target — the
|
|
8675
8774
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8676
8775
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -19619,13 +19718,15 @@ var ListGroupsPageSchema = object({
|
|
|
19619
19718
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
19620
19719
|
nextCursor: string().nullable()
|
|
19621
19720
|
});
|
|
19721
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19722
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
19622
19723
|
var KeyEventQueryInput = object({
|
|
19623
19724
|
deviceId: number(),
|
|
19624
19725
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
19625
19726
|
since: number(),
|
|
19626
19727
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
19627
19728
|
until: number(),
|
|
19628
|
-
limit: number().int().min(1).max(
|
|
19729
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19629
19730
|
/** Drop tracks scoring below this importance. */
|
|
19630
19731
|
minImportance: number().min(0).max(1).optional(),
|
|
19631
19732
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -19647,6 +19748,32 @@ var KeyEventSchema = object({
|
|
|
19647
19748
|
...TrackFlagFields,
|
|
19648
19749
|
...TrackRetrainFields
|
|
19649
19750
|
});
|
|
19751
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19752
|
+
var KeyEventBatchQueryInput = object({
|
|
19753
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19754
|
+
since: number(),
|
|
19755
|
+
until: number(),
|
|
19756
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19757
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19758
|
+
* rows and change what the merged feed contains. */
|
|
19759
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19760
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19761
|
+
classFilter: string().optional()
|
|
19762
|
+
});
|
|
19763
|
+
/**
|
|
19764
|
+
* One camera's key events in a batch answer.
|
|
19765
|
+
*
|
|
19766
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19767
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19768
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19769
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19770
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19771
|
+
* key, which only worked because there was one query per camera).
|
|
19772
|
+
*/
|
|
19773
|
+
var KeyEventsForDeviceSchema = object({
|
|
19774
|
+
deviceId: number(),
|
|
19775
|
+
events: array(KeyEventSchema).readonly()
|
|
19776
|
+
});
|
|
19650
19777
|
object({
|
|
19651
19778
|
trackId: string(),
|
|
19652
19779
|
className: string(),
|
|
@@ -19916,7 +20043,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19916
20043
|
until: number().optional(),
|
|
19917
20044
|
kinds: array(string()).optional(),
|
|
19918
20045
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19919
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
20046
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19920
20047
|
deviceId: number(),
|
|
19921
20048
|
since: number(),
|
|
19922
20049
|
until: number(),
|
|
@@ -29474,6 +29601,9 @@ method(object({
|
|
|
29474
29601
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
29475
29602
|
kind: "query",
|
|
29476
29603
|
auth: "admin"
|
|
29604
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
29605
|
+
kind: "mutation",
|
|
29606
|
+
auth: "admin"
|
|
29477
29607
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
29478
29608
|
kind: "mutation",
|
|
29479
29609
|
auth: "admin"
|
|
@@ -29865,6 +29995,25 @@ var SceneMonitorStatusSchema = object({
|
|
|
29865
29995
|
monitors: array(SceneMonitorSchema),
|
|
29866
29996
|
lastFetchedAt: number()
|
|
29867
29997
|
});
|
|
29998
|
+
/**
|
|
29999
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
30000
|
+
*
|
|
30001
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
30002
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
30003
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
30004
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
30005
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
30006
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
30007
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
30008
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
30009
|
+
*
|
|
30010
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
30011
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
30012
|
+
*/
|
|
30013
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
30014
|
+
deviceId: number(),
|
|
30015
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
30016
|
+
});
|
|
29868
30017
|
var sceneMonitorCapability = {
|
|
29869
30018
|
name: "scene-monitor",
|
|
29870
30019
|
scope: "device",
|
|
@@ -29874,6 +30023,22 @@ var sceneMonitorCapability = {
|
|
|
29874
30023
|
deviceTypes: [DeviceType.Camera],
|
|
29875
30024
|
methods: {
|
|
29876
30025
|
listScenes: method(object({ deviceId: number() }), SceneMonitorStatusSchema),
|
|
30026
|
+
/**
|
|
30027
|
+
* The same answer, for a SET of cameras, in one round trip.
|
|
30028
|
+
*
|
|
30029
|
+
* `/scenes` renders every camera and re-reads them on a 30s safety-net
|
|
30030
|
+
* poll behind the push slice. Fanned out client-side that was one query
|
|
30031
|
+
* per camera — 29 round trips through the browser, the hub and the
|
|
30032
|
+
* post-analysis runner every 30 seconds to read an in-memory map the
|
|
30033
|
+
* owner had already merged. The work is unchanged (`statusFor` per
|
|
30034
|
+
* device, all in-process at the owner); what collapses is the transport.
|
|
30035
|
+
*
|
|
30036
|
+
* A camera that cannot answer still gets a row, with `status: null` —
|
|
30037
|
+
* see {@link SceneMonitorStatusForDeviceSchema}. Never fewer rows than
|
|
30038
|
+
* ids: a caller that asked for twenty-nine and got twenty-seven cannot
|
|
30039
|
+
* tell which two are missing, or that any are.
|
|
30040
|
+
*/
|
|
30041
|
+
listScenesBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()),
|
|
29877
30042
|
createScene: method(object({
|
|
29878
30043
|
deviceId: number(),
|
|
29879
30044
|
label: string(),
|
|
@@ -31907,6 +32072,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
31907
32072
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
31908
32073
|
});
|
|
31909
32074
|
/**
|
|
32075
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
32076
|
+
*
|
|
32077
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
32078
|
+
* because `snapshot: null` was already spoken for:
|
|
32079
|
+
*
|
|
32080
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
32081
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
32082
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
32083
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
32084
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
32085
|
+
*
|
|
32086
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
32087
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
32088
|
+
* which is a definite claim about a camera nobody could read.
|
|
32089
|
+
*/
|
|
32090
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
32091
|
+
deviceId: number(),
|
|
32092
|
+
read: _enum(["read", "unreadable"]),
|
|
32093
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
32094
|
+
});
|
|
32095
|
+
/**
|
|
31910
32096
|
* Time-series resolution. The history methods return one bucket per
|
|
31911
32097
|
* step over the requested range. Smaller resolutions cost more
|
|
31912
32098
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -31963,6 +32149,20 @@ var zoneAnalyticsCapability = {
|
|
|
31963
32149
|
* (no inference result emitted since boot or since binding was
|
|
31964
32150
|
* activated). */
|
|
31965
32151
|
getCurrentSnapshot: method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()),
|
|
32152
|
+
/**
|
|
32153
|
+
* The same snapshot, for a SET of cameras, in one round trip.
|
|
32154
|
+
*
|
|
32155
|
+
* The Events page's Stationary section polls this every 15s for every
|
|
32156
|
+
* selected camera. Fanned out client-side that is one query per camera to
|
|
32157
|
+
* read a `Map.get` at the owner — the answer costs nothing, the round trip
|
|
32158
|
+
* costs everything. Batched, N transports become one and the per-device
|
|
32159
|
+
* work is unchanged.
|
|
32160
|
+
*
|
|
32161
|
+
* Every requested deviceId gets a row, tagged `read` — see
|
|
32162
|
+
* {@link CameraOccupancySnapshotForDeviceSchema}. A camera the owner could
|
|
32163
|
+
* not answer for is `'unreadable'`, never an empty reading.
|
|
32164
|
+
*/
|
|
32165
|
+
getCurrentSnapshotBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()),
|
|
31966
32166
|
/** Time-series object count inside one zone. `className` optional —
|
|
31967
32167
|
* omit to count every class in the zone. */
|
|
31968
32168
|
getZoneHistory: method(object({
|
|
@@ -36551,6 +36751,12 @@ Object.freeze({
|
|
|
36551
36751
|
addonId: null,
|
|
36552
36752
|
access: "view"
|
|
36553
36753
|
},
|
|
36754
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
36755
|
+
capName: "pipeline-analytics",
|
|
36756
|
+
capScope: "device",
|
|
36757
|
+
addonId: null,
|
|
36758
|
+
access: "view"
|
|
36759
|
+
},
|
|
36554
36760
|
"pipelineAnalytics.getMotionEvents": {
|
|
36555
36761
|
capName: "pipeline-analytics",
|
|
36556
36762
|
capScope: "device",
|
|
@@ -37727,6 +37933,12 @@ Object.freeze({
|
|
|
37727
37933
|
addonId: null,
|
|
37728
37934
|
access: "view"
|
|
37729
37935
|
},
|
|
37936
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
37937
|
+
capName: "recording",
|
|
37938
|
+
capScope: "system",
|
|
37939
|
+
addonId: null,
|
|
37940
|
+
access: "create"
|
|
37941
|
+
},
|
|
37730
37942
|
"recording.refreshStorageLocationsForMigration": {
|
|
37731
37943
|
capName: "recording",
|
|
37732
37944
|
capScope: "system",
|
|
@@ -37853,6 +38065,12 @@ Object.freeze({
|
|
|
37853
38065
|
addonId: null,
|
|
37854
38066
|
access: "view"
|
|
37855
38067
|
},
|
|
38068
|
+
"sceneMonitor.listScenesBatch": {
|
|
38069
|
+
capName: "scene-monitor",
|
|
38070
|
+
capScope: "device",
|
|
38071
|
+
addonId: null,
|
|
38072
|
+
access: "view"
|
|
38073
|
+
},
|
|
37856
38074
|
"sceneMonitor.recheckNow": {
|
|
37857
38075
|
capName: "scene-monitor",
|
|
37858
38076
|
capScope: "device",
|
|
@@ -39209,6 +39427,12 @@ Object.freeze({
|
|
|
39209
39427
|
addonId: null,
|
|
39210
39428
|
access: "view"
|
|
39211
39429
|
},
|
|
39430
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
39431
|
+
capName: "zone-analytics",
|
|
39432
|
+
capScope: "device",
|
|
39433
|
+
addonId: null,
|
|
39434
|
+
access: "view"
|
|
39435
|
+
},
|
|
39212
39436
|
"zoneAnalytics.getUnzonedHistory": {
|
|
39213
39437
|
capName: "zone-analytics",
|
|
39214
39438
|
capScope: "device",
|
|
@@ -40213,6 +40437,11 @@ Object.freeze({
|
|
|
40213
40437
|
form: "single",
|
|
40214
40438
|
optional: false
|
|
40215
40439
|
}],
|
|
40440
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
40441
|
+
name: "deviceIds",
|
|
40442
|
+
form: "array",
|
|
40443
|
+
optional: false
|
|
40444
|
+
}],
|
|
40216
40445
|
"pipelineAnalytics.getMotionEvents": [{
|
|
40217
40446
|
name: "deviceId",
|
|
40218
40447
|
form: "single",
|
|
@@ -40653,6 +40882,11 @@ Object.freeze({
|
|
|
40653
40882
|
form: "single",
|
|
40654
40883
|
optional: false
|
|
40655
40884
|
}],
|
|
40885
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
40886
|
+
name: "deviceId",
|
|
40887
|
+
form: "single",
|
|
40888
|
+
optional: true
|
|
40889
|
+
}],
|
|
40656
40890
|
"recording.relocateFootage": [{
|
|
40657
40891
|
name: "deviceId",
|
|
40658
40892
|
form: "single",
|
|
@@ -40718,6 +40952,11 @@ Object.freeze({
|
|
|
40718
40952
|
form: "single",
|
|
40719
40953
|
optional: false
|
|
40720
40954
|
}],
|
|
40955
|
+
"sceneMonitor.listScenesBatch": [{
|
|
40956
|
+
name: "deviceIds",
|
|
40957
|
+
form: "array",
|
|
40958
|
+
optional: false
|
|
40959
|
+
}],
|
|
40721
40960
|
"sceneMonitor.recheckNow": [{
|
|
40722
40961
|
name: "deviceId",
|
|
40723
40962
|
form: "single",
|
|
@@ -40979,6 +41218,11 @@ Object.freeze({
|
|
|
40979
41218
|
form: "single",
|
|
40980
41219
|
optional: false
|
|
40981
41220
|
}],
|
|
41221
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
41222
|
+
name: "deviceIds",
|
|
41223
|
+
form: "array",
|
|
41224
|
+
optional: false
|
|
41225
|
+
}],
|
|
40982
41226
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
40983
41227
|
name: "deviceId",
|
|
40984
41228
|
form: "single",
|
package/dist/addon.mjs
CHANGED
|
@@ -8303,6 +8303,20 @@ var RelocateJobSchema = object({
|
|
|
8303
8303
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8304
8304
|
*/
|
|
8305
8305
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8306
|
+
/**
|
|
8307
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8308
|
+
*
|
|
8309
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8310
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8311
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8312
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8313
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8314
|
+
* the same failure as one that quietly skips them (D295).
|
|
8315
|
+
*
|
|
8316
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8317
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8318
|
+
*/
|
|
8319
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8306
8320
|
startedAt: number(),
|
|
8307
8321
|
finishedAt: number().nullable(),
|
|
8308
8322
|
error: string().nullable()
|
|
@@ -8666,6 +8680,91 @@ var RelocateResidueSchema = object({
|
|
|
8666
8680
|
segments: number().int().nonnegative(),
|
|
8667
8681
|
bytes: number().int().nonnegative()
|
|
8668
8682
|
}).nullable();
|
|
8683
|
+
/**
|
|
8684
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8685
|
+
* (D319).
|
|
8686
|
+
*
|
|
8687
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8688
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8689
|
+
* destructive run before authorising it.
|
|
8690
|
+
*/
|
|
8691
|
+
var LedgerWalkInputSchema = object({
|
|
8692
|
+
locationId: string().min(1),
|
|
8693
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8694
|
+
apply: boolean().optional(),
|
|
8695
|
+
/** Narrow to one camera. */
|
|
8696
|
+
deviceId: number().int().positive().optional(),
|
|
8697
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8698
|
+
profiles: array(string().min(1)).optional()
|
|
8699
|
+
});
|
|
8700
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8701
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8702
|
+
"location-unknown",
|
|
8703
|
+
"source-writable",
|
|
8704
|
+
"no-ledger",
|
|
8705
|
+
"archive-unreadable",
|
|
8706
|
+
"anchor-absent",
|
|
8707
|
+
"anchor-unreadable",
|
|
8708
|
+
"anchor-moved"
|
|
8709
|
+
]);
|
|
8710
|
+
_enum([
|
|
8711
|
+
"live-tail",
|
|
8712
|
+
"listing-error",
|
|
8713
|
+
"path-mismatch",
|
|
8714
|
+
"durable-refused"
|
|
8715
|
+
]);
|
|
8716
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8717
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8718
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8719
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8720
|
+
"live-tail": number().int().nonnegative(),
|
|
8721
|
+
"listing-error": number().int().nonnegative(),
|
|
8722
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8723
|
+
"durable-refused": number().int().nonnegative()
|
|
8724
|
+
});
|
|
8725
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8726
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8727
|
+
deviceId: number().int(),
|
|
8728
|
+
hoursWalked: number().int().nonnegative(),
|
|
8729
|
+
hoursMissing: number().int().nonnegative(),
|
|
8730
|
+
ghostSegments: number().int().nonnegative(),
|
|
8731
|
+
ghostBytes: number().int().nonnegative(),
|
|
8732
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8733
|
+
orphanFiles: number().int().nonnegative()
|
|
8734
|
+
});
|
|
8735
|
+
/**
|
|
8736
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8737
|
+
*
|
|
8738
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8739
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8740
|
+
* than in the absence of one.
|
|
8741
|
+
*/
|
|
8742
|
+
var LedgerWalkReportSchema = object({
|
|
8743
|
+
locationId: string(),
|
|
8744
|
+
applied: boolean(),
|
|
8745
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8746
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8747
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8748
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8749
|
+
hoursWalked: number().int().nonnegative(),
|
|
8750
|
+
hoursMissing: number().int().nonnegative(),
|
|
8751
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8752
|
+
listings: number().int().nonnegative(),
|
|
8753
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8754
|
+
ghostSegments: number().int().nonnegative(),
|
|
8755
|
+
ghostBytes: number().int().nonnegative(),
|
|
8756
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8757
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8758
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8759
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8760
|
+
orphanFiles: number().int().nonnegative(),
|
|
8761
|
+
orphanSample: array(string()).readonly(),
|
|
8762
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8763
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8764
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8765
|
+
bounded: boolean(),
|
|
8766
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8767
|
+
});
|
|
8669
8768
|
/** How many rows a media pass would still act on against a given target — the
|
|
8670
8769
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8671
8770
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -19614,13 +19713,15 @@ var ListGroupsPageSchema = object({
|
|
|
19614
19713
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
19615
19714
|
nextCursor: string().nullable()
|
|
19616
19715
|
});
|
|
19716
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19717
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
19617
19718
|
var KeyEventQueryInput = object({
|
|
19618
19719
|
deviceId: number(),
|
|
19619
19720
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
19620
19721
|
since: number(),
|
|
19621
19722
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
19622
19723
|
until: number(),
|
|
19623
|
-
limit: number().int().min(1).max(
|
|
19724
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19624
19725
|
/** Drop tracks scoring below this importance. */
|
|
19625
19726
|
minImportance: number().min(0).max(1).optional(),
|
|
19626
19727
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -19642,6 +19743,32 @@ var KeyEventSchema = object({
|
|
|
19642
19743
|
...TrackFlagFields,
|
|
19643
19744
|
...TrackRetrainFields
|
|
19644
19745
|
});
|
|
19746
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19747
|
+
var KeyEventBatchQueryInput = object({
|
|
19748
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19749
|
+
since: number(),
|
|
19750
|
+
until: number(),
|
|
19751
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19752
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19753
|
+
* rows and change what the merged feed contains. */
|
|
19754
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19755
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19756
|
+
classFilter: string().optional()
|
|
19757
|
+
});
|
|
19758
|
+
/**
|
|
19759
|
+
* One camera's key events in a batch answer.
|
|
19760
|
+
*
|
|
19761
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19762
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19763
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19764
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19765
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19766
|
+
* key, which only worked because there was one query per camera).
|
|
19767
|
+
*/
|
|
19768
|
+
var KeyEventsForDeviceSchema = object({
|
|
19769
|
+
deviceId: number(),
|
|
19770
|
+
events: array(KeyEventSchema).readonly()
|
|
19771
|
+
});
|
|
19645
19772
|
object({
|
|
19646
19773
|
trackId: string(),
|
|
19647
19774
|
className: string(),
|
|
@@ -19911,7 +20038,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19911
20038
|
until: number().optional(),
|
|
19912
20039
|
kinds: array(string()).optional(),
|
|
19913
20040
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19914
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
20041
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19915
20042
|
deviceId: number(),
|
|
19916
20043
|
since: number(),
|
|
19917
20044
|
until: number(),
|
|
@@ -29469,6 +29596,9 @@ method(object({
|
|
|
29469
29596
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
29470
29597
|
kind: "query",
|
|
29471
29598
|
auth: "admin"
|
|
29599
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
29600
|
+
kind: "mutation",
|
|
29601
|
+
auth: "admin"
|
|
29472
29602
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
29473
29603
|
kind: "mutation",
|
|
29474
29604
|
auth: "admin"
|
|
@@ -29860,6 +29990,25 @@ var SceneMonitorStatusSchema = object({
|
|
|
29860
29990
|
monitors: array(SceneMonitorSchema),
|
|
29861
29991
|
lastFetchedAt: number()
|
|
29862
29992
|
});
|
|
29993
|
+
/**
|
|
29994
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
29995
|
+
*
|
|
29996
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
29997
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
29998
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
29999
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
30000
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
30001
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
30002
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
30003
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
30004
|
+
*
|
|
30005
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
30006
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
30007
|
+
*/
|
|
30008
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
30009
|
+
deviceId: number(),
|
|
30010
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
30011
|
+
});
|
|
29863
30012
|
var sceneMonitorCapability = {
|
|
29864
30013
|
name: "scene-monitor",
|
|
29865
30014
|
scope: "device",
|
|
@@ -29869,6 +30018,22 @@ var sceneMonitorCapability = {
|
|
|
29869
30018
|
deviceTypes: [DeviceType.Camera],
|
|
29870
30019
|
methods: {
|
|
29871
30020
|
listScenes: method(object({ deviceId: number() }), SceneMonitorStatusSchema),
|
|
30021
|
+
/**
|
|
30022
|
+
* The same answer, for a SET of cameras, in one round trip.
|
|
30023
|
+
*
|
|
30024
|
+
* `/scenes` renders every camera and re-reads them on a 30s safety-net
|
|
30025
|
+
* poll behind the push slice. Fanned out client-side that was one query
|
|
30026
|
+
* per camera — 29 round trips through the browser, the hub and the
|
|
30027
|
+
* post-analysis runner every 30 seconds to read an in-memory map the
|
|
30028
|
+
* owner had already merged. The work is unchanged (`statusFor` per
|
|
30029
|
+
* device, all in-process at the owner); what collapses is the transport.
|
|
30030
|
+
*
|
|
30031
|
+
* A camera that cannot answer still gets a row, with `status: null` —
|
|
30032
|
+
* see {@link SceneMonitorStatusForDeviceSchema}. Never fewer rows than
|
|
30033
|
+
* ids: a caller that asked for twenty-nine and got twenty-seven cannot
|
|
30034
|
+
* tell which two are missing, or that any are.
|
|
30035
|
+
*/
|
|
30036
|
+
listScenesBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()),
|
|
29872
30037
|
createScene: method(object({
|
|
29873
30038
|
deviceId: number(),
|
|
29874
30039
|
label: string(),
|
|
@@ -31902,6 +32067,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
31902
32067
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
31903
32068
|
});
|
|
31904
32069
|
/**
|
|
32070
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
32071
|
+
*
|
|
32072
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
32073
|
+
* because `snapshot: null` was already spoken for:
|
|
32074
|
+
*
|
|
32075
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
32076
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
32077
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
32078
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
32079
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
32080
|
+
*
|
|
32081
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
32082
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
32083
|
+
* which is a definite claim about a camera nobody could read.
|
|
32084
|
+
*/
|
|
32085
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
32086
|
+
deviceId: number(),
|
|
32087
|
+
read: _enum(["read", "unreadable"]),
|
|
32088
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
32089
|
+
});
|
|
32090
|
+
/**
|
|
31905
32091
|
* Time-series resolution. The history methods return one bucket per
|
|
31906
32092
|
* step over the requested range. Smaller resolutions cost more
|
|
31907
32093
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -31958,6 +32144,20 @@ var zoneAnalyticsCapability = {
|
|
|
31958
32144
|
* (no inference result emitted since boot or since binding was
|
|
31959
32145
|
* activated). */
|
|
31960
32146
|
getCurrentSnapshot: method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()),
|
|
32147
|
+
/**
|
|
32148
|
+
* The same snapshot, for a SET of cameras, in one round trip.
|
|
32149
|
+
*
|
|
32150
|
+
* The Events page's Stationary section polls this every 15s for every
|
|
32151
|
+
* selected camera. Fanned out client-side that is one query per camera to
|
|
32152
|
+
* read a `Map.get` at the owner — the answer costs nothing, the round trip
|
|
32153
|
+
* costs everything. Batched, N transports become one and the per-device
|
|
32154
|
+
* work is unchanged.
|
|
32155
|
+
*
|
|
32156
|
+
* Every requested deviceId gets a row, tagged `read` — see
|
|
32157
|
+
* {@link CameraOccupancySnapshotForDeviceSchema}. A camera the owner could
|
|
32158
|
+
* not answer for is `'unreadable'`, never an empty reading.
|
|
32159
|
+
*/
|
|
32160
|
+
getCurrentSnapshotBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()),
|
|
31961
32161
|
/** Time-series object count inside one zone. `className` optional —
|
|
31962
32162
|
* omit to count every class in the zone. */
|
|
31963
32163
|
getZoneHistory: method(object({
|
|
@@ -36546,6 +36746,12 @@ Object.freeze({
|
|
|
36546
36746
|
addonId: null,
|
|
36547
36747
|
access: "view"
|
|
36548
36748
|
},
|
|
36749
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
36750
|
+
capName: "pipeline-analytics",
|
|
36751
|
+
capScope: "device",
|
|
36752
|
+
addonId: null,
|
|
36753
|
+
access: "view"
|
|
36754
|
+
},
|
|
36549
36755
|
"pipelineAnalytics.getMotionEvents": {
|
|
36550
36756
|
capName: "pipeline-analytics",
|
|
36551
36757
|
capScope: "device",
|
|
@@ -37722,6 +37928,12 @@ Object.freeze({
|
|
|
37722
37928
|
addonId: null,
|
|
37723
37929
|
access: "view"
|
|
37724
37930
|
},
|
|
37931
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
37932
|
+
capName: "recording",
|
|
37933
|
+
capScope: "system",
|
|
37934
|
+
addonId: null,
|
|
37935
|
+
access: "create"
|
|
37936
|
+
},
|
|
37725
37937
|
"recording.refreshStorageLocationsForMigration": {
|
|
37726
37938
|
capName: "recording",
|
|
37727
37939
|
capScope: "system",
|
|
@@ -37848,6 +38060,12 @@ Object.freeze({
|
|
|
37848
38060
|
addonId: null,
|
|
37849
38061
|
access: "view"
|
|
37850
38062
|
},
|
|
38063
|
+
"sceneMonitor.listScenesBatch": {
|
|
38064
|
+
capName: "scene-monitor",
|
|
38065
|
+
capScope: "device",
|
|
38066
|
+
addonId: null,
|
|
38067
|
+
access: "view"
|
|
38068
|
+
},
|
|
37851
38069
|
"sceneMonitor.recheckNow": {
|
|
37852
38070
|
capName: "scene-monitor",
|
|
37853
38071
|
capScope: "device",
|
|
@@ -39204,6 +39422,12 @@ Object.freeze({
|
|
|
39204
39422
|
addonId: null,
|
|
39205
39423
|
access: "view"
|
|
39206
39424
|
},
|
|
39425
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
39426
|
+
capName: "zone-analytics",
|
|
39427
|
+
capScope: "device",
|
|
39428
|
+
addonId: null,
|
|
39429
|
+
access: "view"
|
|
39430
|
+
},
|
|
39207
39431
|
"zoneAnalytics.getUnzonedHistory": {
|
|
39208
39432
|
capName: "zone-analytics",
|
|
39209
39433
|
capScope: "device",
|
|
@@ -40208,6 +40432,11 @@ Object.freeze({
|
|
|
40208
40432
|
form: "single",
|
|
40209
40433
|
optional: false
|
|
40210
40434
|
}],
|
|
40435
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
40436
|
+
name: "deviceIds",
|
|
40437
|
+
form: "array",
|
|
40438
|
+
optional: false
|
|
40439
|
+
}],
|
|
40211
40440
|
"pipelineAnalytics.getMotionEvents": [{
|
|
40212
40441
|
name: "deviceId",
|
|
40213
40442
|
form: "single",
|
|
@@ -40648,6 +40877,11 @@ Object.freeze({
|
|
|
40648
40877
|
form: "single",
|
|
40649
40878
|
optional: false
|
|
40650
40879
|
}],
|
|
40880
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
40881
|
+
name: "deviceId",
|
|
40882
|
+
form: "single",
|
|
40883
|
+
optional: true
|
|
40884
|
+
}],
|
|
40651
40885
|
"recording.relocateFootage": [{
|
|
40652
40886
|
name: "deviceId",
|
|
40653
40887
|
form: "single",
|
|
@@ -40713,6 +40947,11 @@ Object.freeze({
|
|
|
40713
40947
|
form: "single",
|
|
40714
40948
|
optional: false
|
|
40715
40949
|
}],
|
|
40950
|
+
"sceneMonitor.listScenesBatch": [{
|
|
40951
|
+
name: "deviceIds",
|
|
40952
|
+
form: "array",
|
|
40953
|
+
optional: false
|
|
40954
|
+
}],
|
|
40716
40955
|
"sceneMonitor.recheckNow": [{
|
|
40717
40956
|
name: "deviceId",
|
|
40718
40957
|
form: "single",
|
|
@@ -40974,6 +41213,11 @@ Object.freeze({
|
|
|
40974
41213
|
form: "single",
|
|
40975
41214
|
optional: false
|
|
40976
41215
|
}],
|
|
41216
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
41217
|
+
name: "deviceIds",
|
|
41218
|
+
form: "array",
|
|
41219
|
+
optional: false
|
|
41220
|
+
}],
|
|
40977
41221
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
40978
41222
|
name: "deviceId",
|
|
40979
41223
|
form: "single",
|