@camstack/addon-export-google 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/export-google.addon.js +290 -4
- package/dist/export-google.addon.mjs +290 -4
- package/package.json +1 -1
|
@@ -8211,6 +8211,20 @@ var RelocateJobSchema = object({
|
|
|
8211
8211
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8212
8212
|
*/
|
|
8213
8213
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8214
|
+
/**
|
|
8215
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8216
|
+
*
|
|
8217
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8218
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8219
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8220
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8221
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8222
|
+
* the same failure as one that quietly skips them (D295).
|
|
8223
|
+
*
|
|
8224
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8225
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8226
|
+
*/
|
|
8227
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8214
8228
|
startedAt: number(),
|
|
8215
8229
|
finishedAt: number().nullable(),
|
|
8216
8230
|
error: string().nullable()
|
|
@@ -8574,6 +8588,91 @@ var RelocateResidueSchema = object({
|
|
|
8574
8588
|
segments: number().int().nonnegative(),
|
|
8575
8589
|
bytes: number().int().nonnegative()
|
|
8576
8590
|
}).nullable();
|
|
8591
|
+
/**
|
|
8592
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8593
|
+
* (D319).
|
|
8594
|
+
*
|
|
8595
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8596
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8597
|
+
* destructive run before authorising it.
|
|
8598
|
+
*/
|
|
8599
|
+
var LedgerWalkInputSchema = object({
|
|
8600
|
+
locationId: string().min(1),
|
|
8601
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8602
|
+
apply: boolean().optional(),
|
|
8603
|
+
/** Narrow to one camera. */
|
|
8604
|
+
deviceId: number().int().positive().optional(),
|
|
8605
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8606
|
+
profiles: array(string().min(1)).optional()
|
|
8607
|
+
});
|
|
8608
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8609
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8610
|
+
"location-unknown",
|
|
8611
|
+
"source-writable",
|
|
8612
|
+
"no-ledger",
|
|
8613
|
+
"archive-unreadable",
|
|
8614
|
+
"anchor-absent",
|
|
8615
|
+
"anchor-unreadable",
|
|
8616
|
+
"anchor-moved"
|
|
8617
|
+
]);
|
|
8618
|
+
_enum([
|
|
8619
|
+
"live-tail",
|
|
8620
|
+
"listing-error",
|
|
8621
|
+
"path-mismatch",
|
|
8622
|
+
"durable-refused"
|
|
8623
|
+
]);
|
|
8624
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8625
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8626
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8627
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8628
|
+
"live-tail": number().int().nonnegative(),
|
|
8629
|
+
"listing-error": number().int().nonnegative(),
|
|
8630
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8631
|
+
"durable-refused": number().int().nonnegative()
|
|
8632
|
+
});
|
|
8633
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8634
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8635
|
+
deviceId: number().int(),
|
|
8636
|
+
hoursWalked: number().int().nonnegative(),
|
|
8637
|
+
hoursMissing: number().int().nonnegative(),
|
|
8638
|
+
ghostSegments: number().int().nonnegative(),
|
|
8639
|
+
ghostBytes: number().int().nonnegative(),
|
|
8640
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8641
|
+
orphanFiles: number().int().nonnegative()
|
|
8642
|
+
});
|
|
8643
|
+
/**
|
|
8644
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8645
|
+
*
|
|
8646
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8647
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8648
|
+
* than in the absence of one.
|
|
8649
|
+
*/
|
|
8650
|
+
var LedgerWalkReportSchema = object({
|
|
8651
|
+
locationId: string(),
|
|
8652
|
+
applied: boolean(),
|
|
8653
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8654
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8655
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8656
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8657
|
+
hoursWalked: number().int().nonnegative(),
|
|
8658
|
+
hoursMissing: number().int().nonnegative(),
|
|
8659
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8660
|
+
listings: number().int().nonnegative(),
|
|
8661
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8662
|
+
ghostSegments: number().int().nonnegative(),
|
|
8663
|
+
ghostBytes: number().int().nonnegative(),
|
|
8664
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8665
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8666
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8667
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8668
|
+
orphanFiles: number().int().nonnegative(),
|
|
8669
|
+
orphanSample: array(string()).readonly(),
|
|
8670
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8671
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8672
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8673
|
+
bounded: boolean(),
|
|
8674
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8675
|
+
});
|
|
8577
8676
|
/** How many rows a media pass would still act on against a given target — the
|
|
8578
8677
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8579
8678
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18936,13 +19035,15 @@ var ListGroupsPageSchema = object({
|
|
|
18936
19035
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18937
19036
|
nextCursor: string().nullable()
|
|
18938
19037
|
});
|
|
19038
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19039
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18939
19040
|
var KeyEventQueryInput = object({
|
|
18940
19041
|
deviceId: number(),
|
|
18941
19042
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18942
19043
|
since: number(),
|
|
18943
19044
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18944
19045
|
until: number(),
|
|
18945
|
-
limit: number().int().min(1).max(
|
|
19046
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18946
19047
|
/** Drop tracks scoring below this importance. */
|
|
18947
19048
|
minImportance: number().min(0).max(1).optional(),
|
|
18948
19049
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18964,6 +19065,32 @@ var KeyEventSchema = object({
|
|
|
18964
19065
|
...TrackFlagFields,
|
|
18965
19066
|
...TrackRetrainFields
|
|
18966
19067
|
});
|
|
19068
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19069
|
+
var KeyEventBatchQueryInput = object({
|
|
19070
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19071
|
+
since: number(),
|
|
19072
|
+
until: number(),
|
|
19073
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19074
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19075
|
+
* rows and change what the merged feed contains. */
|
|
19076
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19077
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19078
|
+
classFilter: string().optional()
|
|
19079
|
+
});
|
|
19080
|
+
/**
|
|
19081
|
+
* One camera's key events in a batch answer.
|
|
19082
|
+
*
|
|
19083
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19084
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19085
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19086
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19087
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19088
|
+
* key, which only worked because there was one query per camera).
|
|
19089
|
+
*/
|
|
19090
|
+
var KeyEventsForDeviceSchema = object({
|
|
19091
|
+
deviceId: number(),
|
|
19092
|
+
events: array(KeyEventSchema).readonly()
|
|
19093
|
+
});
|
|
18967
19094
|
object({
|
|
18968
19095
|
trackId: string(),
|
|
18969
19096
|
className: string(),
|
|
@@ -19035,6 +19162,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19035
19162
|
totalBytes: number().int(),
|
|
19036
19163
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19037
19164
|
});
|
|
19165
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19166
|
+
var EventMediaKindFootprintSchema = object({
|
|
19167
|
+
kind: MediaFileKindEnum,
|
|
19168
|
+
/** Media rows of this kind. */
|
|
19169
|
+
rows: number().int(),
|
|
19170
|
+
/** Bytes on disk held by those rows. */
|
|
19171
|
+
bytes: number().int()
|
|
19172
|
+
});
|
|
19173
|
+
/**
|
|
19174
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19175
|
+
* actually turns on.
|
|
19176
|
+
*
|
|
19177
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19178
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19179
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19180
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19181
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19182
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19183
|
+
*
|
|
19184
|
+
* ## Why `unaccounted*` exists
|
|
19185
|
+
*
|
|
19186
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19187
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19188
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19189
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19190
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19191
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19192
|
+
* against a denominator smaller than the disk.
|
|
19193
|
+
*
|
|
19194
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19195
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19196
|
+
*/
|
|
19197
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19198
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19199
|
+
totalRows: number().int(),
|
|
19200
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19201
|
+
totalBytes: number().int(),
|
|
19202
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19203
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19204
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19205
|
+
unaccountedRows: number().int(),
|
|
19206
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19207
|
+
unaccountedBytes: number().int()
|
|
19208
|
+
});
|
|
19038
19209
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19039
19210
|
var EventPruneCountsSchema = object({
|
|
19040
19211
|
motion: number().int(),
|
|
@@ -19189,7 +19360,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19189
19360
|
until: number().optional(),
|
|
19190
19361
|
kinds: array(string()).optional(),
|
|
19191
19362
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19192
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19363
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19193
19364
|
deviceId: number(),
|
|
19194
19365
|
since: number(),
|
|
19195
19366
|
until: number(),
|
|
@@ -19238,6 +19409,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19238
19409
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19239
19410
|
kind: "query",
|
|
19240
19411
|
auth: "admin"
|
|
19412
|
+
}), method(object({ deviceId: number().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19413
|
+
kind: "query",
|
|
19414
|
+
auth: "admin"
|
|
19241
19415
|
}), method(object({
|
|
19242
19416
|
olderThanMs: number(),
|
|
19243
19417
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21189,6 +21363,20 @@ method(object({
|
|
|
21189
21363
|
error: string().optional()
|
|
21190
21364
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21191
21365
|
providerId: string(),
|
|
21366
|
+
/**
|
|
21367
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21368
|
+
*
|
|
21369
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21370
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21371
|
+
* credential the operator did not retype — and posting that here
|
|
21372
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21373
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21374
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21375
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21376
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21377
|
+
* every value was typed just now and nothing is stored yet.
|
|
21378
|
+
*/
|
|
21379
|
+
locationId: string().optional(),
|
|
21192
21380
|
config: record(string(), unknown())
|
|
21193
21381
|
}), object({
|
|
21194
21382
|
ok: boolean(),
|
|
@@ -26836,6 +27024,9 @@ method(object({
|
|
|
26836
27024
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26837
27025
|
kind: "query",
|
|
26838
27026
|
auth: "admin"
|
|
27027
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27028
|
+
kind: "mutation",
|
|
27029
|
+
auth: "admin"
|
|
26839
27030
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26840
27031
|
kind: "mutation",
|
|
26841
27032
|
auth: "admin"
|
|
@@ -27227,7 +27418,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27227
27418
|
monitors: array(SceneMonitorSchema),
|
|
27228
27419
|
lastFetchedAt: number()
|
|
27229
27420
|
});
|
|
27230
|
-
|
|
27421
|
+
/**
|
|
27422
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27423
|
+
*
|
|
27424
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27425
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27426
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27427
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27428
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27429
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27430
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27431
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27432
|
+
*
|
|
27433
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27434
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27435
|
+
*/
|
|
27436
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27437
|
+
deviceId: number(),
|
|
27438
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27439
|
+
});
|
|
27440
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27231
27441
|
deviceId: number(),
|
|
27232
27442
|
label: string(),
|
|
27233
27443
|
roi: MaskRectShapeSchema,
|
|
@@ -28558,6 +28768,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28558
28768
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28559
28769
|
});
|
|
28560
28770
|
/**
|
|
28771
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28772
|
+
*
|
|
28773
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28774
|
+
* because `snapshot: null` was already spoken for:
|
|
28775
|
+
*
|
|
28776
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28777
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28778
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28779
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28780
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28781
|
+
*
|
|
28782
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28783
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28784
|
+
* which is a definite claim about a camera nobody could read.
|
|
28785
|
+
*/
|
|
28786
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28787
|
+
deviceId: number(),
|
|
28788
|
+
read: _enum(["read", "unreadable"]),
|
|
28789
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28790
|
+
});
|
|
28791
|
+
/**
|
|
28561
28792
|
* Time-series resolution. The history methods return one bucket per
|
|
28562
28793
|
* step over the requested range. Smaller resolutions cost more
|
|
28563
28794
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28581,7 +28812,7 @@ var HistoryPointSchema = object({
|
|
|
28581
28812
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28582
28813
|
count: number().int().nonnegative()
|
|
28583
28814
|
});
|
|
28584
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28815
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28585
28816
|
deviceId: number(),
|
|
28586
28817
|
zoneId: string(),
|
|
28587
28818
|
className: string().optional()
|
|
@@ -31862,6 +32093,12 @@ Object.freeze({
|
|
|
31862
32093
|
addonId: null,
|
|
31863
32094
|
access: "view"
|
|
31864
32095
|
},
|
|
32096
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": {
|
|
32097
|
+
capName: "pipeline-analytics",
|
|
32098
|
+
capScope: "device",
|
|
32099
|
+
addonId: null,
|
|
32100
|
+
access: "view"
|
|
32101
|
+
},
|
|
31865
32102
|
"pipelineAnalytics.getEventStoreFootprint": {
|
|
31866
32103
|
capName: "pipeline-analytics",
|
|
31867
32104
|
capScope: "device",
|
|
@@ -31880,6 +32117,12 @@ Object.freeze({
|
|
|
31880
32117
|
addonId: null,
|
|
31881
32118
|
access: "view"
|
|
31882
32119
|
},
|
|
32120
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32121
|
+
capName: "pipeline-analytics",
|
|
32122
|
+
capScope: "device",
|
|
32123
|
+
addonId: null,
|
|
32124
|
+
access: "view"
|
|
32125
|
+
},
|
|
31883
32126
|
"pipelineAnalytics.getMotionEvents": {
|
|
31884
32127
|
capName: "pipeline-analytics",
|
|
31885
32128
|
capScope: "device",
|
|
@@ -33056,6 +33299,12 @@ Object.freeze({
|
|
|
33056
33299
|
addonId: null,
|
|
33057
33300
|
access: "view"
|
|
33058
33301
|
},
|
|
33302
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33303
|
+
capName: "recording",
|
|
33304
|
+
capScope: "system",
|
|
33305
|
+
addonId: null,
|
|
33306
|
+
access: "create"
|
|
33307
|
+
},
|
|
33059
33308
|
"recording.refreshStorageLocationsForMigration": {
|
|
33060
33309
|
capName: "recording",
|
|
33061
33310
|
capScope: "system",
|
|
@@ -33182,6 +33431,12 @@ Object.freeze({
|
|
|
33182
33431
|
addonId: null,
|
|
33183
33432
|
access: "view"
|
|
33184
33433
|
},
|
|
33434
|
+
"sceneMonitor.listScenesBatch": {
|
|
33435
|
+
capName: "scene-monitor",
|
|
33436
|
+
capScope: "device",
|
|
33437
|
+
addonId: null,
|
|
33438
|
+
access: "view"
|
|
33439
|
+
},
|
|
33185
33440
|
"sceneMonitor.recheckNow": {
|
|
33186
33441
|
capName: "scene-monitor",
|
|
33187
33442
|
capScope: "device",
|
|
@@ -34538,6 +34793,12 @@ Object.freeze({
|
|
|
34538
34793
|
addonId: null,
|
|
34539
34794
|
access: "view"
|
|
34540
34795
|
},
|
|
34796
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34797
|
+
capName: "zone-analytics",
|
|
34798
|
+
capScope: "device",
|
|
34799
|
+
addonId: null,
|
|
34800
|
+
access: "view"
|
|
34801
|
+
},
|
|
34541
34802
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34542
34803
|
capName: "zone-analytics",
|
|
34543
34804
|
capScope: "device",
|
|
@@ -35527,6 +35788,11 @@ Object.freeze({
|
|
|
35527
35788
|
form: "single",
|
|
35528
35789
|
optional: false
|
|
35529
35790
|
}],
|
|
35791
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": [{
|
|
35792
|
+
name: "deviceId",
|
|
35793
|
+
form: "single",
|
|
35794
|
+
optional: true
|
|
35795
|
+
}],
|
|
35530
35796
|
"pipelineAnalytics.getGroup": [{
|
|
35531
35797
|
name: "deviceId",
|
|
35532
35798
|
form: "single",
|
|
@@ -35537,6 +35803,11 @@ Object.freeze({
|
|
|
35537
35803
|
form: "single",
|
|
35538
35804
|
optional: false
|
|
35539
35805
|
}],
|
|
35806
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35807
|
+
name: "deviceIds",
|
|
35808
|
+
form: "array",
|
|
35809
|
+
optional: false
|
|
35810
|
+
}],
|
|
35540
35811
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35541
35812
|
name: "deviceId",
|
|
35542
35813
|
form: "single",
|
|
@@ -35977,6 +36248,11 @@ Object.freeze({
|
|
|
35977
36248
|
form: "single",
|
|
35978
36249
|
optional: false
|
|
35979
36250
|
}],
|
|
36251
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36252
|
+
name: "deviceId",
|
|
36253
|
+
form: "single",
|
|
36254
|
+
optional: true
|
|
36255
|
+
}],
|
|
35980
36256
|
"recording.relocateFootage": [{
|
|
35981
36257
|
name: "deviceId",
|
|
35982
36258
|
form: "single",
|
|
@@ -36042,6 +36318,11 @@ Object.freeze({
|
|
|
36042
36318
|
form: "single",
|
|
36043
36319
|
optional: false
|
|
36044
36320
|
}],
|
|
36321
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36322
|
+
name: "deviceIds",
|
|
36323
|
+
form: "array",
|
|
36324
|
+
optional: false
|
|
36325
|
+
}],
|
|
36045
36326
|
"sceneMonitor.recheckNow": [{
|
|
36046
36327
|
name: "deviceId",
|
|
36047
36328
|
form: "single",
|
|
@@ -36303,6 +36584,11 @@ Object.freeze({
|
|
|
36303
36584
|
form: "single",
|
|
36304
36585
|
optional: false
|
|
36305
36586
|
}],
|
|
36587
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36588
|
+
name: "deviceIds",
|
|
36589
|
+
form: "array",
|
|
36590
|
+
optional: false
|
|
36591
|
+
}],
|
|
36306
36592
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36307
36593
|
name: "deviceId",
|
|
36308
36594
|
form: "single",
|
|
@@ -8207,6 +8207,20 @@ var RelocateJobSchema = object({
|
|
|
8207
8207
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8208
8208
|
*/
|
|
8209
8209
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8210
|
+
/**
|
|
8211
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8212
|
+
*
|
|
8213
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8214
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8215
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8216
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8217
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8218
|
+
* the same failure as one that quietly skips them (D295).
|
|
8219
|
+
*
|
|
8220
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8221
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8222
|
+
*/
|
|
8223
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8210
8224
|
startedAt: number(),
|
|
8211
8225
|
finishedAt: number().nullable(),
|
|
8212
8226
|
error: string().nullable()
|
|
@@ -8570,6 +8584,91 @@ var RelocateResidueSchema = object({
|
|
|
8570
8584
|
segments: number().int().nonnegative(),
|
|
8571
8585
|
bytes: number().int().nonnegative()
|
|
8572
8586
|
}).nullable();
|
|
8587
|
+
/**
|
|
8588
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8589
|
+
* (D319).
|
|
8590
|
+
*
|
|
8591
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8592
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8593
|
+
* destructive run before authorising it.
|
|
8594
|
+
*/
|
|
8595
|
+
var LedgerWalkInputSchema = object({
|
|
8596
|
+
locationId: string().min(1),
|
|
8597
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8598
|
+
apply: boolean().optional(),
|
|
8599
|
+
/** Narrow to one camera. */
|
|
8600
|
+
deviceId: number().int().positive().optional(),
|
|
8601
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8602
|
+
profiles: array(string().min(1)).optional()
|
|
8603
|
+
});
|
|
8604
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8605
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8606
|
+
"location-unknown",
|
|
8607
|
+
"source-writable",
|
|
8608
|
+
"no-ledger",
|
|
8609
|
+
"archive-unreadable",
|
|
8610
|
+
"anchor-absent",
|
|
8611
|
+
"anchor-unreadable",
|
|
8612
|
+
"anchor-moved"
|
|
8613
|
+
]);
|
|
8614
|
+
_enum([
|
|
8615
|
+
"live-tail",
|
|
8616
|
+
"listing-error",
|
|
8617
|
+
"path-mismatch",
|
|
8618
|
+
"durable-refused"
|
|
8619
|
+
]);
|
|
8620
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8621
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8622
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8623
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8624
|
+
"live-tail": number().int().nonnegative(),
|
|
8625
|
+
"listing-error": number().int().nonnegative(),
|
|
8626
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8627
|
+
"durable-refused": number().int().nonnegative()
|
|
8628
|
+
});
|
|
8629
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8630
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8631
|
+
deviceId: number().int(),
|
|
8632
|
+
hoursWalked: number().int().nonnegative(),
|
|
8633
|
+
hoursMissing: number().int().nonnegative(),
|
|
8634
|
+
ghostSegments: number().int().nonnegative(),
|
|
8635
|
+
ghostBytes: number().int().nonnegative(),
|
|
8636
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8637
|
+
orphanFiles: number().int().nonnegative()
|
|
8638
|
+
});
|
|
8639
|
+
/**
|
|
8640
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8641
|
+
*
|
|
8642
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8643
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8644
|
+
* than in the absence of one.
|
|
8645
|
+
*/
|
|
8646
|
+
var LedgerWalkReportSchema = object({
|
|
8647
|
+
locationId: string(),
|
|
8648
|
+
applied: boolean(),
|
|
8649
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8650
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8651
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8652
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8653
|
+
hoursWalked: number().int().nonnegative(),
|
|
8654
|
+
hoursMissing: number().int().nonnegative(),
|
|
8655
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8656
|
+
listings: number().int().nonnegative(),
|
|
8657
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8658
|
+
ghostSegments: number().int().nonnegative(),
|
|
8659
|
+
ghostBytes: number().int().nonnegative(),
|
|
8660
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8661
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8662
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8663
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8664
|
+
orphanFiles: number().int().nonnegative(),
|
|
8665
|
+
orphanSample: array(string()).readonly(),
|
|
8666
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8667
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8668
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8669
|
+
bounded: boolean(),
|
|
8670
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8671
|
+
});
|
|
8573
8672
|
/** How many rows a media pass would still act on against a given target — the
|
|
8574
8673
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8575
8674
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18932,13 +19031,15 @@ var ListGroupsPageSchema = object({
|
|
|
18932
19031
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18933
19032
|
nextCursor: string().nullable()
|
|
18934
19033
|
});
|
|
19034
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19035
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18935
19036
|
var KeyEventQueryInput = object({
|
|
18936
19037
|
deviceId: number(),
|
|
18937
19038
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18938
19039
|
since: number(),
|
|
18939
19040
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18940
19041
|
until: number(),
|
|
18941
|
-
limit: number().int().min(1).max(
|
|
19042
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18942
19043
|
/** Drop tracks scoring below this importance. */
|
|
18943
19044
|
minImportance: number().min(0).max(1).optional(),
|
|
18944
19045
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18960,6 +19061,32 @@ var KeyEventSchema = object({
|
|
|
18960
19061
|
...TrackFlagFields,
|
|
18961
19062
|
...TrackRetrainFields
|
|
18962
19063
|
});
|
|
19064
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19065
|
+
var KeyEventBatchQueryInput = object({
|
|
19066
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19067
|
+
since: number(),
|
|
19068
|
+
until: number(),
|
|
19069
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19070
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19071
|
+
* rows and change what the merged feed contains. */
|
|
19072
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19073
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19074
|
+
classFilter: string().optional()
|
|
19075
|
+
});
|
|
19076
|
+
/**
|
|
19077
|
+
* One camera's key events in a batch answer.
|
|
19078
|
+
*
|
|
19079
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19080
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19081
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19082
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19083
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19084
|
+
* key, which only worked because there was one query per camera).
|
|
19085
|
+
*/
|
|
19086
|
+
var KeyEventsForDeviceSchema = object({
|
|
19087
|
+
deviceId: number(),
|
|
19088
|
+
events: array(KeyEventSchema).readonly()
|
|
19089
|
+
});
|
|
18963
19090
|
object({
|
|
18964
19091
|
trackId: string(),
|
|
18965
19092
|
className: string(),
|
|
@@ -19031,6 +19158,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19031
19158
|
totalBytes: number().int(),
|
|
19032
19159
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19033
19160
|
});
|
|
19161
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19162
|
+
var EventMediaKindFootprintSchema = object({
|
|
19163
|
+
kind: MediaFileKindEnum,
|
|
19164
|
+
/** Media rows of this kind. */
|
|
19165
|
+
rows: number().int(),
|
|
19166
|
+
/** Bytes on disk held by those rows. */
|
|
19167
|
+
bytes: number().int()
|
|
19168
|
+
});
|
|
19169
|
+
/**
|
|
19170
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19171
|
+
* actually turns on.
|
|
19172
|
+
*
|
|
19173
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19174
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19175
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19176
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19177
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19178
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19179
|
+
*
|
|
19180
|
+
* ## Why `unaccounted*` exists
|
|
19181
|
+
*
|
|
19182
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19183
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19184
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19185
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19186
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19187
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19188
|
+
* against a denominator smaller than the disk.
|
|
19189
|
+
*
|
|
19190
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19191
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19192
|
+
*/
|
|
19193
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19194
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19195
|
+
totalRows: number().int(),
|
|
19196
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19197
|
+
totalBytes: number().int(),
|
|
19198
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19199
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19200
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19201
|
+
unaccountedRows: number().int(),
|
|
19202
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19203
|
+
unaccountedBytes: number().int()
|
|
19204
|
+
});
|
|
19034
19205
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19035
19206
|
var EventPruneCountsSchema = object({
|
|
19036
19207
|
motion: number().int(),
|
|
@@ -19185,7 +19356,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19185
19356
|
until: number().optional(),
|
|
19186
19357
|
kinds: array(string()).optional(),
|
|
19187
19358
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19188
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19359
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19189
19360
|
deviceId: number(),
|
|
19190
19361
|
since: number(),
|
|
19191
19362
|
until: number(),
|
|
@@ -19234,6 +19405,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19234
19405
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19235
19406
|
kind: "query",
|
|
19236
19407
|
auth: "admin"
|
|
19408
|
+
}), method(object({ deviceId: number().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19409
|
+
kind: "query",
|
|
19410
|
+
auth: "admin"
|
|
19237
19411
|
}), method(object({
|
|
19238
19412
|
olderThanMs: number(),
|
|
19239
19413
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21185,6 +21359,20 @@ method(object({
|
|
|
21185
21359
|
error: string().optional()
|
|
21186
21360
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21187
21361
|
providerId: string(),
|
|
21362
|
+
/**
|
|
21363
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21364
|
+
*
|
|
21365
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21366
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21367
|
+
* credential the operator did not retype — and posting that here
|
|
21368
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21369
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21370
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21371
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21372
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21373
|
+
* every value was typed just now and nothing is stored yet.
|
|
21374
|
+
*/
|
|
21375
|
+
locationId: string().optional(),
|
|
21188
21376
|
config: record(string(), unknown())
|
|
21189
21377
|
}), object({
|
|
21190
21378
|
ok: boolean(),
|
|
@@ -26832,6 +27020,9 @@ method(object({
|
|
|
26832
27020
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26833
27021
|
kind: "query",
|
|
26834
27022
|
auth: "admin"
|
|
27023
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27024
|
+
kind: "mutation",
|
|
27025
|
+
auth: "admin"
|
|
26835
27026
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26836
27027
|
kind: "mutation",
|
|
26837
27028
|
auth: "admin"
|
|
@@ -27223,7 +27414,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27223
27414
|
monitors: array(SceneMonitorSchema),
|
|
27224
27415
|
lastFetchedAt: number()
|
|
27225
27416
|
});
|
|
27226
|
-
|
|
27417
|
+
/**
|
|
27418
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27419
|
+
*
|
|
27420
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27421
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27422
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27423
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27424
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27425
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27426
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27427
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27428
|
+
*
|
|
27429
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27430
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27431
|
+
*/
|
|
27432
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27433
|
+
deviceId: number(),
|
|
27434
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27435
|
+
});
|
|
27436
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27227
27437
|
deviceId: number(),
|
|
27228
27438
|
label: string(),
|
|
27229
27439
|
roi: MaskRectShapeSchema,
|
|
@@ -28554,6 +28764,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28554
28764
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28555
28765
|
});
|
|
28556
28766
|
/**
|
|
28767
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28768
|
+
*
|
|
28769
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28770
|
+
* because `snapshot: null` was already spoken for:
|
|
28771
|
+
*
|
|
28772
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28773
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28774
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28775
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28776
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28777
|
+
*
|
|
28778
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28779
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28780
|
+
* which is a definite claim about a camera nobody could read.
|
|
28781
|
+
*/
|
|
28782
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28783
|
+
deviceId: number(),
|
|
28784
|
+
read: _enum(["read", "unreadable"]),
|
|
28785
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28786
|
+
});
|
|
28787
|
+
/**
|
|
28557
28788
|
* Time-series resolution. The history methods return one bucket per
|
|
28558
28789
|
* step over the requested range. Smaller resolutions cost more
|
|
28559
28790
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28577,7 +28808,7 @@ var HistoryPointSchema = object({
|
|
|
28577
28808
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28578
28809
|
count: number().int().nonnegative()
|
|
28579
28810
|
});
|
|
28580
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28811
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28581
28812
|
deviceId: number(),
|
|
28582
28813
|
zoneId: string(),
|
|
28583
28814
|
className: string().optional()
|
|
@@ -31858,6 +32089,12 @@ Object.freeze({
|
|
|
31858
32089
|
addonId: null,
|
|
31859
32090
|
access: "view"
|
|
31860
32091
|
},
|
|
32092
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": {
|
|
32093
|
+
capName: "pipeline-analytics",
|
|
32094
|
+
capScope: "device",
|
|
32095
|
+
addonId: null,
|
|
32096
|
+
access: "view"
|
|
32097
|
+
},
|
|
31861
32098
|
"pipelineAnalytics.getEventStoreFootprint": {
|
|
31862
32099
|
capName: "pipeline-analytics",
|
|
31863
32100
|
capScope: "device",
|
|
@@ -31876,6 +32113,12 @@ Object.freeze({
|
|
|
31876
32113
|
addonId: null,
|
|
31877
32114
|
access: "view"
|
|
31878
32115
|
},
|
|
32116
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32117
|
+
capName: "pipeline-analytics",
|
|
32118
|
+
capScope: "device",
|
|
32119
|
+
addonId: null,
|
|
32120
|
+
access: "view"
|
|
32121
|
+
},
|
|
31879
32122
|
"pipelineAnalytics.getMotionEvents": {
|
|
31880
32123
|
capName: "pipeline-analytics",
|
|
31881
32124
|
capScope: "device",
|
|
@@ -33052,6 +33295,12 @@ Object.freeze({
|
|
|
33052
33295
|
addonId: null,
|
|
33053
33296
|
access: "view"
|
|
33054
33297
|
},
|
|
33298
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33299
|
+
capName: "recording",
|
|
33300
|
+
capScope: "system",
|
|
33301
|
+
addonId: null,
|
|
33302
|
+
access: "create"
|
|
33303
|
+
},
|
|
33055
33304
|
"recording.refreshStorageLocationsForMigration": {
|
|
33056
33305
|
capName: "recording",
|
|
33057
33306
|
capScope: "system",
|
|
@@ -33178,6 +33427,12 @@ Object.freeze({
|
|
|
33178
33427
|
addonId: null,
|
|
33179
33428
|
access: "view"
|
|
33180
33429
|
},
|
|
33430
|
+
"sceneMonitor.listScenesBatch": {
|
|
33431
|
+
capName: "scene-monitor",
|
|
33432
|
+
capScope: "device",
|
|
33433
|
+
addonId: null,
|
|
33434
|
+
access: "view"
|
|
33435
|
+
},
|
|
33181
33436
|
"sceneMonitor.recheckNow": {
|
|
33182
33437
|
capName: "scene-monitor",
|
|
33183
33438
|
capScope: "device",
|
|
@@ -34534,6 +34789,12 @@ Object.freeze({
|
|
|
34534
34789
|
addonId: null,
|
|
34535
34790
|
access: "view"
|
|
34536
34791
|
},
|
|
34792
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34793
|
+
capName: "zone-analytics",
|
|
34794
|
+
capScope: "device",
|
|
34795
|
+
addonId: null,
|
|
34796
|
+
access: "view"
|
|
34797
|
+
},
|
|
34537
34798
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34538
34799
|
capName: "zone-analytics",
|
|
34539
34800
|
capScope: "device",
|
|
@@ -35523,6 +35784,11 @@ Object.freeze({
|
|
|
35523
35784
|
form: "single",
|
|
35524
35785
|
optional: false
|
|
35525
35786
|
}],
|
|
35787
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": [{
|
|
35788
|
+
name: "deviceId",
|
|
35789
|
+
form: "single",
|
|
35790
|
+
optional: true
|
|
35791
|
+
}],
|
|
35526
35792
|
"pipelineAnalytics.getGroup": [{
|
|
35527
35793
|
name: "deviceId",
|
|
35528
35794
|
form: "single",
|
|
@@ -35533,6 +35799,11 @@ Object.freeze({
|
|
|
35533
35799
|
form: "single",
|
|
35534
35800
|
optional: false
|
|
35535
35801
|
}],
|
|
35802
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35803
|
+
name: "deviceIds",
|
|
35804
|
+
form: "array",
|
|
35805
|
+
optional: false
|
|
35806
|
+
}],
|
|
35536
35807
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35537
35808
|
name: "deviceId",
|
|
35538
35809
|
form: "single",
|
|
@@ -35973,6 +36244,11 @@ Object.freeze({
|
|
|
35973
36244
|
form: "single",
|
|
35974
36245
|
optional: false
|
|
35975
36246
|
}],
|
|
36247
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36248
|
+
name: "deviceId",
|
|
36249
|
+
form: "single",
|
|
36250
|
+
optional: true
|
|
36251
|
+
}],
|
|
35976
36252
|
"recording.relocateFootage": [{
|
|
35977
36253
|
name: "deviceId",
|
|
35978
36254
|
form: "single",
|
|
@@ -36038,6 +36314,11 @@ Object.freeze({
|
|
|
36038
36314
|
form: "single",
|
|
36039
36315
|
optional: false
|
|
36040
36316
|
}],
|
|
36317
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36318
|
+
name: "deviceIds",
|
|
36319
|
+
form: "array",
|
|
36320
|
+
optional: false
|
|
36321
|
+
}],
|
|
36041
36322
|
"sceneMonitor.recheckNow": [{
|
|
36042
36323
|
name: "deviceId",
|
|
36043
36324
|
form: "single",
|
|
@@ -36299,6 +36580,11 @@ Object.freeze({
|
|
|
36299
36580
|
form: "single",
|
|
36300
36581
|
optional: false
|
|
36301
36582
|
}],
|
|
36583
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36584
|
+
name: "deviceIds",
|
|
36585
|
+
form: "array",
|
|
36586
|
+
optional: false
|
|
36587
|
+
}],
|
|
36302
36588
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36303
36589
|
name: "deviceId",
|
|
36304
36590
|
form: "single",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-google",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Google Home export — hub-side smart-home fulfillment (SYNC / QUERY / EXECUTE / DISCONNECT) for the non-camera fleet, served over the hub's own OAuth account link. No Google credential is stored, sent or required.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|