@camstack/addon-provider-rtsp 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/addon.js +246 -2
- package/dist/addon.mjs +246 -2
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8074,6 +8074,20 @@ var RelocateJobSchema = object({
|
|
|
8074
8074
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8075
8075
|
*/
|
|
8076
8076
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8077
|
+
/**
|
|
8078
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8079
|
+
*
|
|
8080
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8081
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8082
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8083
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8084
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8085
|
+
* the same failure as one that quietly skips them (D295).
|
|
8086
|
+
*
|
|
8087
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8088
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8089
|
+
*/
|
|
8090
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8077
8091
|
startedAt: number(),
|
|
8078
8092
|
finishedAt: number().nullable(),
|
|
8079
8093
|
error: string().nullable()
|
|
@@ -8437,6 +8451,91 @@ var RelocateResidueSchema = object({
|
|
|
8437
8451
|
segments: number().int().nonnegative(),
|
|
8438
8452
|
bytes: number().int().nonnegative()
|
|
8439
8453
|
}).nullable();
|
|
8454
|
+
/**
|
|
8455
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8456
|
+
* (D319).
|
|
8457
|
+
*
|
|
8458
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8459
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8460
|
+
* destructive run before authorising it.
|
|
8461
|
+
*/
|
|
8462
|
+
var LedgerWalkInputSchema = object({
|
|
8463
|
+
locationId: string().min(1),
|
|
8464
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8465
|
+
apply: boolean().optional(),
|
|
8466
|
+
/** Narrow to one camera. */
|
|
8467
|
+
deviceId: number().int().positive().optional(),
|
|
8468
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8469
|
+
profiles: array(string().min(1)).optional()
|
|
8470
|
+
});
|
|
8471
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8472
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8473
|
+
"location-unknown",
|
|
8474
|
+
"source-writable",
|
|
8475
|
+
"no-ledger",
|
|
8476
|
+
"archive-unreadable",
|
|
8477
|
+
"anchor-absent",
|
|
8478
|
+
"anchor-unreadable",
|
|
8479
|
+
"anchor-moved"
|
|
8480
|
+
]);
|
|
8481
|
+
_enum([
|
|
8482
|
+
"live-tail",
|
|
8483
|
+
"listing-error",
|
|
8484
|
+
"path-mismatch",
|
|
8485
|
+
"durable-refused"
|
|
8486
|
+
]);
|
|
8487
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8488
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8489
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8490
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8491
|
+
"live-tail": number().int().nonnegative(),
|
|
8492
|
+
"listing-error": number().int().nonnegative(),
|
|
8493
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8494
|
+
"durable-refused": number().int().nonnegative()
|
|
8495
|
+
});
|
|
8496
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8497
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8498
|
+
deviceId: number().int(),
|
|
8499
|
+
hoursWalked: number().int().nonnegative(),
|
|
8500
|
+
hoursMissing: number().int().nonnegative(),
|
|
8501
|
+
ghostSegments: number().int().nonnegative(),
|
|
8502
|
+
ghostBytes: number().int().nonnegative(),
|
|
8503
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8504
|
+
orphanFiles: number().int().nonnegative()
|
|
8505
|
+
});
|
|
8506
|
+
/**
|
|
8507
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8508
|
+
*
|
|
8509
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8510
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8511
|
+
* than in the absence of one.
|
|
8512
|
+
*/
|
|
8513
|
+
var LedgerWalkReportSchema = object({
|
|
8514
|
+
locationId: string(),
|
|
8515
|
+
applied: boolean(),
|
|
8516
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8517
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8518
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8519
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8520
|
+
hoursWalked: number().int().nonnegative(),
|
|
8521
|
+
hoursMissing: number().int().nonnegative(),
|
|
8522
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8523
|
+
listings: number().int().nonnegative(),
|
|
8524
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8525
|
+
ghostSegments: number().int().nonnegative(),
|
|
8526
|
+
ghostBytes: number().int().nonnegative(),
|
|
8527
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8528
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8529
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8530
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8531
|
+
orphanFiles: number().int().nonnegative(),
|
|
8532
|
+
orphanSample: array(string()).readonly(),
|
|
8533
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8534
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8535
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8536
|
+
bounded: boolean(),
|
|
8537
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8538
|
+
});
|
|
8440
8539
|
/** How many rows a media pass would still act on against a given target — the
|
|
8441
8540
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8442
8541
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -19052,13 +19151,15 @@ var ListGroupsPageSchema = object({
|
|
|
19052
19151
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
19053
19152
|
nextCursor: string().nullable()
|
|
19054
19153
|
});
|
|
19154
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19155
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
19055
19156
|
var KeyEventQueryInput = object({
|
|
19056
19157
|
deviceId: number(),
|
|
19057
19158
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
19058
19159
|
since: number(),
|
|
19059
19160
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
19060
19161
|
until: number(),
|
|
19061
|
-
limit: number().int().min(1).max(
|
|
19162
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19062
19163
|
/** Drop tracks scoring below this importance. */
|
|
19063
19164
|
minImportance: number().min(0).max(1).optional(),
|
|
19064
19165
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -19080,6 +19181,32 @@ var KeyEventSchema = object({
|
|
|
19080
19181
|
...TrackFlagFields,
|
|
19081
19182
|
...TrackRetrainFields
|
|
19082
19183
|
});
|
|
19184
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19185
|
+
var KeyEventBatchQueryInput = object({
|
|
19186
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19187
|
+
since: number(),
|
|
19188
|
+
until: number(),
|
|
19189
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19190
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19191
|
+
* rows and change what the merged feed contains. */
|
|
19192
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19193
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19194
|
+
classFilter: string().optional()
|
|
19195
|
+
});
|
|
19196
|
+
/**
|
|
19197
|
+
* One camera's key events in a batch answer.
|
|
19198
|
+
*
|
|
19199
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19200
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19201
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19202
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19203
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19204
|
+
* key, which only worked because there was one query per camera).
|
|
19205
|
+
*/
|
|
19206
|
+
var KeyEventsForDeviceSchema = object({
|
|
19207
|
+
deviceId: number(),
|
|
19208
|
+
events: array(KeyEventSchema).readonly()
|
|
19209
|
+
});
|
|
19083
19210
|
object({
|
|
19084
19211
|
trackId: string(),
|
|
19085
19212
|
className: string(),
|
|
@@ -19349,7 +19476,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19349
19476
|
until: number().optional(),
|
|
19350
19477
|
kinds: array(string()).optional(),
|
|
19351
19478
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19352
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19479
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19353
19480
|
deviceId: number(),
|
|
19354
19481
|
since: number(),
|
|
19355
19482
|
until: number(),
|
|
@@ -28828,6 +28955,9 @@ method(object({
|
|
|
28828
28955
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
28829
28956
|
kind: "query",
|
|
28830
28957
|
auth: "admin"
|
|
28958
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
28959
|
+
kind: "mutation",
|
|
28960
|
+
auth: "admin"
|
|
28831
28961
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
28832
28962
|
kind: "mutation",
|
|
28833
28963
|
auth: "admin"
|
|
@@ -29219,6 +29349,25 @@ var SceneMonitorStatusSchema = object({
|
|
|
29219
29349
|
monitors: array(SceneMonitorSchema),
|
|
29220
29350
|
lastFetchedAt: number()
|
|
29221
29351
|
});
|
|
29352
|
+
/**
|
|
29353
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
29354
|
+
*
|
|
29355
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
29356
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
29357
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
29358
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
29359
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
29360
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
29361
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
29362
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
29363
|
+
*
|
|
29364
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
29365
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
29366
|
+
*/
|
|
29367
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
29368
|
+
deviceId: number(),
|
|
29369
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
29370
|
+
});
|
|
29222
29371
|
var sceneMonitorCapability = {
|
|
29223
29372
|
name: "scene-monitor",
|
|
29224
29373
|
scope: "device",
|
|
@@ -29228,6 +29377,22 @@ var sceneMonitorCapability = {
|
|
|
29228
29377
|
deviceTypes: [DeviceType.Camera],
|
|
29229
29378
|
methods: {
|
|
29230
29379
|
listScenes: method(object({ deviceId: number() }), SceneMonitorStatusSchema),
|
|
29380
|
+
/**
|
|
29381
|
+
* The same answer, for a SET of cameras, in one round trip.
|
|
29382
|
+
*
|
|
29383
|
+
* `/scenes` renders every camera and re-reads them on a 30s safety-net
|
|
29384
|
+
* poll behind the push slice. Fanned out client-side that was one query
|
|
29385
|
+
* per camera — 29 round trips through the browser, the hub and the
|
|
29386
|
+
* post-analysis runner every 30 seconds to read an in-memory map the
|
|
29387
|
+
* owner had already merged. The work is unchanged (`statusFor` per
|
|
29388
|
+
* device, all in-process at the owner); what collapses is the transport.
|
|
29389
|
+
*
|
|
29390
|
+
* A camera that cannot answer still gets a row, with `status: null` —
|
|
29391
|
+
* see {@link SceneMonitorStatusForDeviceSchema}. Never fewer rows than
|
|
29392
|
+
* ids: a caller that asked for twenty-nine and got twenty-seven cannot
|
|
29393
|
+
* tell which two are missing, or that any are.
|
|
29394
|
+
*/
|
|
29395
|
+
listScenesBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()),
|
|
29231
29396
|
createScene: method(object({
|
|
29232
29397
|
deviceId: number(),
|
|
29233
29398
|
label: string(),
|
|
@@ -31063,6 +31228,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
31063
31228
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
31064
31229
|
});
|
|
31065
31230
|
/**
|
|
31231
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
31232
|
+
*
|
|
31233
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
31234
|
+
* because `snapshot: null` was already spoken for:
|
|
31235
|
+
*
|
|
31236
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
31237
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
31238
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
31239
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
31240
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
31241
|
+
*
|
|
31242
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
31243
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
31244
|
+
* which is a definite claim about a camera nobody could read.
|
|
31245
|
+
*/
|
|
31246
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
31247
|
+
deviceId: number(),
|
|
31248
|
+
read: _enum(["read", "unreadable"]),
|
|
31249
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
31250
|
+
});
|
|
31251
|
+
/**
|
|
31066
31252
|
* Time-series resolution. The history methods return one bucket per
|
|
31067
31253
|
* step over the requested range. Smaller resolutions cost more
|
|
31068
31254
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -31119,6 +31305,20 @@ var zoneAnalyticsCapability = {
|
|
|
31119
31305
|
* (no inference result emitted since boot or since binding was
|
|
31120
31306
|
* activated). */
|
|
31121
31307
|
getCurrentSnapshot: method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()),
|
|
31308
|
+
/**
|
|
31309
|
+
* The same snapshot, for a SET of cameras, in one round trip.
|
|
31310
|
+
*
|
|
31311
|
+
* The Events page's Stationary section polls this every 15s for every
|
|
31312
|
+
* selected camera. Fanned out client-side that is one query per camera to
|
|
31313
|
+
* read a `Map.get` at the owner — the answer costs nothing, the round trip
|
|
31314
|
+
* costs everything. Batched, N transports become one and the per-device
|
|
31315
|
+
* work is unchanged.
|
|
31316
|
+
*
|
|
31317
|
+
* Every requested deviceId gets a row, tagged `read` — see
|
|
31318
|
+
* {@link CameraOccupancySnapshotForDeviceSchema}. A camera the owner could
|
|
31319
|
+
* not answer for is `'unreadable'`, never an empty reading.
|
|
31320
|
+
*/
|
|
31321
|
+
getCurrentSnapshotBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()),
|
|
31122
31322
|
/** Time-series object count inside one zone. `className` optional —
|
|
31123
31323
|
* omit to count every class in the zone. */
|
|
31124
31324
|
getZoneHistory: method(object({
|
|
@@ -35606,6 +35806,12 @@ Object.freeze({
|
|
|
35606
35806
|
addonId: null,
|
|
35607
35807
|
access: "view"
|
|
35608
35808
|
},
|
|
35809
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
35810
|
+
capName: "pipeline-analytics",
|
|
35811
|
+
capScope: "device",
|
|
35812
|
+
addonId: null,
|
|
35813
|
+
access: "view"
|
|
35814
|
+
},
|
|
35609
35815
|
"pipelineAnalytics.getMotionEvents": {
|
|
35610
35816
|
capName: "pipeline-analytics",
|
|
35611
35817
|
capScope: "device",
|
|
@@ -36782,6 +36988,12 @@ Object.freeze({
|
|
|
36782
36988
|
addonId: null,
|
|
36783
36989
|
access: "view"
|
|
36784
36990
|
},
|
|
36991
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
36992
|
+
capName: "recording",
|
|
36993
|
+
capScope: "system",
|
|
36994
|
+
addonId: null,
|
|
36995
|
+
access: "create"
|
|
36996
|
+
},
|
|
36785
36997
|
"recording.refreshStorageLocationsForMigration": {
|
|
36786
36998
|
capName: "recording",
|
|
36787
36999
|
capScope: "system",
|
|
@@ -36908,6 +37120,12 @@ Object.freeze({
|
|
|
36908
37120
|
addonId: null,
|
|
36909
37121
|
access: "view"
|
|
36910
37122
|
},
|
|
37123
|
+
"sceneMonitor.listScenesBatch": {
|
|
37124
|
+
capName: "scene-monitor",
|
|
37125
|
+
capScope: "device",
|
|
37126
|
+
addonId: null,
|
|
37127
|
+
access: "view"
|
|
37128
|
+
},
|
|
36911
37129
|
"sceneMonitor.recheckNow": {
|
|
36912
37130
|
capName: "scene-monitor",
|
|
36913
37131
|
capScope: "device",
|
|
@@ -38264,6 +38482,12 @@ Object.freeze({
|
|
|
38264
38482
|
addonId: null,
|
|
38265
38483
|
access: "view"
|
|
38266
38484
|
},
|
|
38485
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
38486
|
+
capName: "zone-analytics",
|
|
38487
|
+
capScope: "device",
|
|
38488
|
+
addonId: null,
|
|
38489
|
+
access: "view"
|
|
38490
|
+
},
|
|
38267
38491
|
"zoneAnalytics.getUnzonedHistory": {
|
|
38268
38492
|
capName: "zone-analytics",
|
|
38269
38493
|
capScope: "device",
|
|
@@ -39268,6 +39492,11 @@ Object.freeze({
|
|
|
39268
39492
|
form: "single",
|
|
39269
39493
|
optional: false
|
|
39270
39494
|
}],
|
|
39495
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
39496
|
+
name: "deviceIds",
|
|
39497
|
+
form: "array",
|
|
39498
|
+
optional: false
|
|
39499
|
+
}],
|
|
39271
39500
|
"pipelineAnalytics.getMotionEvents": [{
|
|
39272
39501
|
name: "deviceId",
|
|
39273
39502
|
form: "single",
|
|
@@ -39708,6 +39937,11 @@ Object.freeze({
|
|
|
39708
39937
|
form: "single",
|
|
39709
39938
|
optional: false
|
|
39710
39939
|
}],
|
|
39940
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
39941
|
+
name: "deviceId",
|
|
39942
|
+
form: "single",
|
|
39943
|
+
optional: true
|
|
39944
|
+
}],
|
|
39711
39945
|
"recording.relocateFootage": [{
|
|
39712
39946
|
name: "deviceId",
|
|
39713
39947
|
form: "single",
|
|
@@ -39773,6 +40007,11 @@ Object.freeze({
|
|
|
39773
40007
|
form: "single",
|
|
39774
40008
|
optional: false
|
|
39775
40009
|
}],
|
|
40010
|
+
"sceneMonitor.listScenesBatch": [{
|
|
40011
|
+
name: "deviceIds",
|
|
40012
|
+
form: "array",
|
|
40013
|
+
optional: false
|
|
40014
|
+
}],
|
|
39776
40015
|
"sceneMonitor.recheckNow": [{
|
|
39777
40016
|
name: "deviceId",
|
|
39778
40017
|
form: "single",
|
|
@@ -40034,6 +40273,11 @@ Object.freeze({
|
|
|
40034
40273
|
form: "single",
|
|
40035
40274
|
optional: false
|
|
40036
40275
|
}],
|
|
40276
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
40277
|
+
name: "deviceIds",
|
|
40278
|
+
form: "array",
|
|
40279
|
+
optional: false
|
|
40280
|
+
}],
|
|
40037
40281
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
40038
40282
|
name: "deviceId",
|
|
40039
40283
|
form: "single",
|
package/dist/addon.mjs
CHANGED
|
@@ -8050,6 +8050,20 @@ var RelocateJobSchema = object({
|
|
|
8050
8050
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8051
8051
|
*/
|
|
8052
8052
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8053
|
+
/**
|
|
8054
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8055
|
+
*
|
|
8056
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8057
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8058
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8059
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8060
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8061
|
+
* the same failure as one that quietly skips them (D295).
|
|
8062
|
+
*
|
|
8063
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8064
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8065
|
+
*/
|
|
8066
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8053
8067
|
startedAt: number(),
|
|
8054
8068
|
finishedAt: number().nullable(),
|
|
8055
8069
|
error: string().nullable()
|
|
@@ -8413,6 +8427,91 @@ var RelocateResidueSchema = object({
|
|
|
8413
8427
|
segments: number().int().nonnegative(),
|
|
8414
8428
|
bytes: number().int().nonnegative()
|
|
8415
8429
|
}).nullable();
|
|
8430
|
+
/**
|
|
8431
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8432
|
+
* (D319).
|
|
8433
|
+
*
|
|
8434
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8435
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8436
|
+
* destructive run before authorising it.
|
|
8437
|
+
*/
|
|
8438
|
+
var LedgerWalkInputSchema = object({
|
|
8439
|
+
locationId: string().min(1),
|
|
8440
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8441
|
+
apply: boolean().optional(),
|
|
8442
|
+
/** Narrow to one camera. */
|
|
8443
|
+
deviceId: number().int().positive().optional(),
|
|
8444
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8445
|
+
profiles: array(string().min(1)).optional()
|
|
8446
|
+
});
|
|
8447
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8448
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8449
|
+
"location-unknown",
|
|
8450
|
+
"source-writable",
|
|
8451
|
+
"no-ledger",
|
|
8452
|
+
"archive-unreadable",
|
|
8453
|
+
"anchor-absent",
|
|
8454
|
+
"anchor-unreadable",
|
|
8455
|
+
"anchor-moved"
|
|
8456
|
+
]);
|
|
8457
|
+
_enum([
|
|
8458
|
+
"live-tail",
|
|
8459
|
+
"listing-error",
|
|
8460
|
+
"path-mismatch",
|
|
8461
|
+
"durable-refused"
|
|
8462
|
+
]);
|
|
8463
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8464
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8465
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8466
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8467
|
+
"live-tail": number().int().nonnegative(),
|
|
8468
|
+
"listing-error": number().int().nonnegative(),
|
|
8469
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8470
|
+
"durable-refused": number().int().nonnegative()
|
|
8471
|
+
});
|
|
8472
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8473
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8474
|
+
deviceId: number().int(),
|
|
8475
|
+
hoursWalked: number().int().nonnegative(),
|
|
8476
|
+
hoursMissing: number().int().nonnegative(),
|
|
8477
|
+
ghostSegments: number().int().nonnegative(),
|
|
8478
|
+
ghostBytes: number().int().nonnegative(),
|
|
8479
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8480
|
+
orphanFiles: number().int().nonnegative()
|
|
8481
|
+
});
|
|
8482
|
+
/**
|
|
8483
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8484
|
+
*
|
|
8485
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8486
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8487
|
+
* than in the absence of one.
|
|
8488
|
+
*/
|
|
8489
|
+
var LedgerWalkReportSchema = object({
|
|
8490
|
+
locationId: string(),
|
|
8491
|
+
applied: boolean(),
|
|
8492
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8493
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8494
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8495
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8496
|
+
hoursWalked: number().int().nonnegative(),
|
|
8497
|
+
hoursMissing: number().int().nonnegative(),
|
|
8498
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8499
|
+
listings: number().int().nonnegative(),
|
|
8500
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8501
|
+
ghostSegments: number().int().nonnegative(),
|
|
8502
|
+
ghostBytes: number().int().nonnegative(),
|
|
8503
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8504
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8505
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8506
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8507
|
+
orphanFiles: number().int().nonnegative(),
|
|
8508
|
+
orphanSample: array(string()).readonly(),
|
|
8509
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8510
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8511
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8512
|
+
bounded: boolean(),
|
|
8513
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8514
|
+
});
|
|
8416
8515
|
/** How many rows a media pass would still act on against a given target — the
|
|
8417
8516
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8418
8517
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -19028,13 +19127,15 @@ var ListGroupsPageSchema = object({
|
|
|
19028
19127
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
19029
19128
|
nextCursor: string().nullable()
|
|
19030
19129
|
});
|
|
19130
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19131
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
19031
19132
|
var KeyEventQueryInput = object({
|
|
19032
19133
|
deviceId: number(),
|
|
19033
19134
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
19034
19135
|
since: number(),
|
|
19035
19136
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
19036
19137
|
until: number(),
|
|
19037
|
-
limit: number().int().min(1).max(
|
|
19138
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19038
19139
|
/** Drop tracks scoring below this importance. */
|
|
19039
19140
|
minImportance: number().min(0).max(1).optional(),
|
|
19040
19141
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -19056,6 +19157,32 @@ var KeyEventSchema = object({
|
|
|
19056
19157
|
...TrackFlagFields,
|
|
19057
19158
|
...TrackRetrainFields
|
|
19058
19159
|
});
|
|
19160
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19161
|
+
var KeyEventBatchQueryInput = object({
|
|
19162
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19163
|
+
since: number(),
|
|
19164
|
+
until: number(),
|
|
19165
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19166
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19167
|
+
* rows and change what the merged feed contains. */
|
|
19168
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19169
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19170
|
+
classFilter: string().optional()
|
|
19171
|
+
});
|
|
19172
|
+
/**
|
|
19173
|
+
* One camera's key events in a batch answer.
|
|
19174
|
+
*
|
|
19175
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19176
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19177
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19178
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19179
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19180
|
+
* key, which only worked because there was one query per camera).
|
|
19181
|
+
*/
|
|
19182
|
+
var KeyEventsForDeviceSchema = object({
|
|
19183
|
+
deviceId: number(),
|
|
19184
|
+
events: array(KeyEventSchema).readonly()
|
|
19185
|
+
});
|
|
19059
19186
|
object({
|
|
19060
19187
|
trackId: string(),
|
|
19061
19188
|
className: string(),
|
|
@@ -19325,7 +19452,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19325
19452
|
until: number().optional(),
|
|
19326
19453
|
kinds: array(string()).optional(),
|
|
19327
19454
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19328
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19455
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19329
19456
|
deviceId: number(),
|
|
19330
19457
|
since: number(),
|
|
19331
19458
|
until: number(),
|
|
@@ -28804,6 +28931,9 @@ method(object({
|
|
|
28804
28931
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
28805
28932
|
kind: "query",
|
|
28806
28933
|
auth: "admin"
|
|
28934
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
28935
|
+
kind: "mutation",
|
|
28936
|
+
auth: "admin"
|
|
28807
28937
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
28808
28938
|
kind: "mutation",
|
|
28809
28939
|
auth: "admin"
|
|
@@ -29195,6 +29325,25 @@ var SceneMonitorStatusSchema = object({
|
|
|
29195
29325
|
monitors: array(SceneMonitorSchema),
|
|
29196
29326
|
lastFetchedAt: number()
|
|
29197
29327
|
});
|
|
29328
|
+
/**
|
|
29329
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
29330
|
+
*
|
|
29331
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
29332
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
29333
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
29334
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
29335
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
29336
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
29337
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
29338
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
29339
|
+
*
|
|
29340
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
29341
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
29342
|
+
*/
|
|
29343
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
29344
|
+
deviceId: number(),
|
|
29345
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
29346
|
+
});
|
|
29198
29347
|
var sceneMonitorCapability = {
|
|
29199
29348
|
name: "scene-monitor",
|
|
29200
29349
|
scope: "device",
|
|
@@ -29204,6 +29353,22 @@ var sceneMonitorCapability = {
|
|
|
29204
29353
|
deviceTypes: [DeviceType.Camera],
|
|
29205
29354
|
methods: {
|
|
29206
29355
|
listScenes: method(object({ deviceId: number() }), SceneMonitorStatusSchema),
|
|
29356
|
+
/**
|
|
29357
|
+
* The same answer, for a SET of cameras, in one round trip.
|
|
29358
|
+
*
|
|
29359
|
+
* `/scenes` renders every camera and re-reads them on a 30s safety-net
|
|
29360
|
+
* poll behind the push slice. Fanned out client-side that was one query
|
|
29361
|
+
* per camera — 29 round trips through the browser, the hub and the
|
|
29362
|
+
* post-analysis runner every 30 seconds to read an in-memory map the
|
|
29363
|
+
* owner had already merged. The work is unchanged (`statusFor` per
|
|
29364
|
+
* device, all in-process at the owner); what collapses is the transport.
|
|
29365
|
+
*
|
|
29366
|
+
* A camera that cannot answer still gets a row, with `status: null` —
|
|
29367
|
+
* see {@link SceneMonitorStatusForDeviceSchema}. Never fewer rows than
|
|
29368
|
+
* ids: a caller that asked for twenty-nine and got twenty-seven cannot
|
|
29369
|
+
* tell which two are missing, or that any are.
|
|
29370
|
+
*/
|
|
29371
|
+
listScenesBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()),
|
|
29207
29372
|
createScene: method(object({
|
|
29208
29373
|
deviceId: number(),
|
|
29209
29374
|
label: string(),
|
|
@@ -31039,6 +31204,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
31039
31204
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
31040
31205
|
});
|
|
31041
31206
|
/**
|
|
31207
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
31208
|
+
*
|
|
31209
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
31210
|
+
* because `snapshot: null` was already spoken for:
|
|
31211
|
+
*
|
|
31212
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
31213
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
31214
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
31215
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
31216
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
31217
|
+
*
|
|
31218
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
31219
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
31220
|
+
* which is a definite claim about a camera nobody could read.
|
|
31221
|
+
*/
|
|
31222
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
31223
|
+
deviceId: number(),
|
|
31224
|
+
read: _enum(["read", "unreadable"]),
|
|
31225
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
31226
|
+
});
|
|
31227
|
+
/**
|
|
31042
31228
|
* Time-series resolution. The history methods return one bucket per
|
|
31043
31229
|
* step over the requested range. Smaller resolutions cost more
|
|
31044
31230
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -31095,6 +31281,20 @@ var zoneAnalyticsCapability = {
|
|
|
31095
31281
|
* (no inference result emitted since boot or since binding was
|
|
31096
31282
|
* activated). */
|
|
31097
31283
|
getCurrentSnapshot: method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()),
|
|
31284
|
+
/**
|
|
31285
|
+
* The same snapshot, for a SET of cameras, in one round trip.
|
|
31286
|
+
*
|
|
31287
|
+
* The Events page's Stationary section polls this every 15s for every
|
|
31288
|
+
* selected camera. Fanned out client-side that is one query per camera to
|
|
31289
|
+
* read a `Map.get` at the owner — the answer costs nothing, the round trip
|
|
31290
|
+
* costs everything. Batched, N transports become one and the per-device
|
|
31291
|
+
* work is unchanged.
|
|
31292
|
+
*
|
|
31293
|
+
* Every requested deviceId gets a row, tagged `read` — see
|
|
31294
|
+
* {@link CameraOccupancySnapshotForDeviceSchema}. A camera the owner could
|
|
31295
|
+
* not answer for is `'unreadable'`, never an empty reading.
|
|
31296
|
+
*/
|
|
31297
|
+
getCurrentSnapshotBatch: method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()),
|
|
31098
31298
|
/** Time-series object count inside one zone. `className` optional —
|
|
31099
31299
|
* omit to count every class in the zone. */
|
|
31100
31300
|
getZoneHistory: method(object({
|
|
@@ -35582,6 +35782,12 @@ Object.freeze({
|
|
|
35582
35782
|
addonId: null,
|
|
35583
35783
|
access: "view"
|
|
35584
35784
|
},
|
|
35785
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
35786
|
+
capName: "pipeline-analytics",
|
|
35787
|
+
capScope: "device",
|
|
35788
|
+
addonId: null,
|
|
35789
|
+
access: "view"
|
|
35790
|
+
},
|
|
35585
35791
|
"pipelineAnalytics.getMotionEvents": {
|
|
35586
35792
|
capName: "pipeline-analytics",
|
|
35587
35793
|
capScope: "device",
|
|
@@ -36758,6 +36964,12 @@ Object.freeze({
|
|
|
36758
36964
|
addonId: null,
|
|
36759
36965
|
access: "view"
|
|
36760
36966
|
},
|
|
36967
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
36968
|
+
capName: "recording",
|
|
36969
|
+
capScope: "system",
|
|
36970
|
+
addonId: null,
|
|
36971
|
+
access: "create"
|
|
36972
|
+
},
|
|
36761
36973
|
"recording.refreshStorageLocationsForMigration": {
|
|
36762
36974
|
capName: "recording",
|
|
36763
36975
|
capScope: "system",
|
|
@@ -36884,6 +37096,12 @@ Object.freeze({
|
|
|
36884
37096
|
addonId: null,
|
|
36885
37097
|
access: "view"
|
|
36886
37098
|
},
|
|
37099
|
+
"sceneMonitor.listScenesBatch": {
|
|
37100
|
+
capName: "scene-monitor",
|
|
37101
|
+
capScope: "device",
|
|
37102
|
+
addonId: null,
|
|
37103
|
+
access: "view"
|
|
37104
|
+
},
|
|
36887
37105
|
"sceneMonitor.recheckNow": {
|
|
36888
37106
|
capName: "scene-monitor",
|
|
36889
37107
|
capScope: "device",
|
|
@@ -38240,6 +38458,12 @@ Object.freeze({
|
|
|
38240
38458
|
addonId: null,
|
|
38241
38459
|
access: "view"
|
|
38242
38460
|
},
|
|
38461
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
38462
|
+
capName: "zone-analytics",
|
|
38463
|
+
capScope: "device",
|
|
38464
|
+
addonId: null,
|
|
38465
|
+
access: "view"
|
|
38466
|
+
},
|
|
38243
38467
|
"zoneAnalytics.getUnzonedHistory": {
|
|
38244
38468
|
capName: "zone-analytics",
|
|
38245
38469
|
capScope: "device",
|
|
@@ -39244,6 +39468,11 @@ Object.freeze({
|
|
|
39244
39468
|
form: "single",
|
|
39245
39469
|
optional: false
|
|
39246
39470
|
}],
|
|
39471
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
39472
|
+
name: "deviceIds",
|
|
39473
|
+
form: "array",
|
|
39474
|
+
optional: false
|
|
39475
|
+
}],
|
|
39247
39476
|
"pipelineAnalytics.getMotionEvents": [{
|
|
39248
39477
|
name: "deviceId",
|
|
39249
39478
|
form: "single",
|
|
@@ -39684,6 +39913,11 @@ Object.freeze({
|
|
|
39684
39913
|
form: "single",
|
|
39685
39914
|
optional: false
|
|
39686
39915
|
}],
|
|
39916
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
39917
|
+
name: "deviceId",
|
|
39918
|
+
form: "single",
|
|
39919
|
+
optional: true
|
|
39920
|
+
}],
|
|
39687
39921
|
"recording.relocateFootage": [{
|
|
39688
39922
|
name: "deviceId",
|
|
39689
39923
|
form: "single",
|
|
@@ -39749,6 +39983,11 @@ Object.freeze({
|
|
|
39749
39983
|
form: "single",
|
|
39750
39984
|
optional: false
|
|
39751
39985
|
}],
|
|
39986
|
+
"sceneMonitor.listScenesBatch": [{
|
|
39987
|
+
name: "deviceIds",
|
|
39988
|
+
form: "array",
|
|
39989
|
+
optional: false
|
|
39990
|
+
}],
|
|
39752
39991
|
"sceneMonitor.recheckNow": [{
|
|
39753
39992
|
name: "deviceId",
|
|
39754
39993
|
form: "single",
|
|
@@ -40010,6 +40249,11 @@ Object.freeze({
|
|
|
40010
40249
|
form: "single",
|
|
40011
40250
|
optional: false
|
|
40012
40251
|
}],
|
|
40252
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
40253
|
+
name: "deviceIds",
|
|
40254
|
+
form: "array",
|
|
40255
|
+
optional: false
|
|
40256
|
+
}],
|
|
40013
40257
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
40014
40258
|
name: "deviceId",
|
|
40015
40259
|
form: "single",
|