@camstack/addon-export-alexa 1.2.53 → 1.2.55
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-alexa.addon.js +290 -4
- package/dist/export-alexa.addon.mjs +290 -4
- package/package.json +1 -1
|
@@ -8186,6 +8186,20 @@ var RelocateJobSchema = object({
|
|
|
8186
8186
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8187
8187
|
*/
|
|
8188
8188
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8189
|
+
/**
|
|
8190
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8191
|
+
*
|
|
8192
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8193
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8194
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8195
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8196
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8197
|
+
* the same failure as one that quietly skips them (D295).
|
|
8198
|
+
*
|
|
8199
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8200
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8201
|
+
*/
|
|
8202
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8189
8203
|
startedAt: number(),
|
|
8190
8204
|
finishedAt: number().nullable(),
|
|
8191
8205
|
error: string().nullable()
|
|
@@ -8549,6 +8563,91 @@ var RelocateResidueSchema = object({
|
|
|
8549
8563
|
segments: number().int().nonnegative(),
|
|
8550
8564
|
bytes: number().int().nonnegative()
|
|
8551
8565
|
}).nullable();
|
|
8566
|
+
/**
|
|
8567
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8568
|
+
* (D319).
|
|
8569
|
+
*
|
|
8570
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8571
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8572
|
+
* destructive run before authorising it.
|
|
8573
|
+
*/
|
|
8574
|
+
var LedgerWalkInputSchema = object({
|
|
8575
|
+
locationId: string().min(1),
|
|
8576
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8577
|
+
apply: boolean().optional(),
|
|
8578
|
+
/** Narrow to one camera. */
|
|
8579
|
+
deviceId: number().int().positive().optional(),
|
|
8580
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8581
|
+
profiles: array(string().min(1)).optional()
|
|
8582
|
+
});
|
|
8583
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8584
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8585
|
+
"location-unknown",
|
|
8586
|
+
"source-writable",
|
|
8587
|
+
"no-ledger",
|
|
8588
|
+
"archive-unreadable",
|
|
8589
|
+
"anchor-absent",
|
|
8590
|
+
"anchor-unreadable",
|
|
8591
|
+
"anchor-moved"
|
|
8592
|
+
]);
|
|
8593
|
+
_enum([
|
|
8594
|
+
"live-tail",
|
|
8595
|
+
"listing-error",
|
|
8596
|
+
"path-mismatch",
|
|
8597
|
+
"durable-refused"
|
|
8598
|
+
]);
|
|
8599
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8600
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8601
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8602
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8603
|
+
"live-tail": number().int().nonnegative(),
|
|
8604
|
+
"listing-error": number().int().nonnegative(),
|
|
8605
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8606
|
+
"durable-refused": number().int().nonnegative()
|
|
8607
|
+
});
|
|
8608
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8609
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8610
|
+
deviceId: number().int(),
|
|
8611
|
+
hoursWalked: number().int().nonnegative(),
|
|
8612
|
+
hoursMissing: number().int().nonnegative(),
|
|
8613
|
+
ghostSegments: number().int().nonnegative(),
|
|
8614
|
+
ghostBytes: number().int().nonnegative(),
|
|
8615
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8616
|
+
orphanFiles: number().int().nonnegative()
|
|
8617
|
+
});
|
|
8618
|
+
/**
|
|
8619
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8620
|
+
*
|
|
8621
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8622
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8623
|
+
* than in the absence of one.
|
|
8624
|
+
*/
|
|
8625
|
+
var LedgerWalkReportSchema = object({
|
|
8626
|
+
locationId: string(),
|
|
8627
|
+
applied: boolean(),
|
|
8628
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8629
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8630
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8631
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8632
|
+
hoursWalked: number().int().nonnegative(),
|
|
8633
|
+
hoursMissing: number().int().nonnegative(),
|
|
8634
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8635
|
+
listings: number().int().nonnegative(),
|
|
8636
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8637
|
+
ghostSegments: number().int().nonnegative(),
|
|
8638
|
+
ghostBytes: number().int().nonnegative(),
|
|
8639
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8640
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8641
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8642
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8643
|
+
orphanFiles: number().int().nonnegative(),
|
|
8644
|
+
orphanSample: array(string()).readonly(),
|
|
8645
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8646
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8647
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8648
|
+
bounded: boolean(),
|
|
8649
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8650
|
+
});
|
|
8552
8651
|
/** How many rows a media pass would still act on against a given target — the
|
|
8553
8652
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8554
8653
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18965,13 +19064,15 @@ var ListGroupsPageSchema = object({
|
|
|
18965
19064
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18966
19065
|
nextCursor: string().nullable()
|
|
18967
19066
|
});
|
|
19067
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19068
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18968
19069
|
var KeyEventQueryInput = object({
|
|
18969
19070
|
deviceId: number(),
|
|
18970
19071
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18971
19072
|
since: number(),
|
|
18972
19073
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18973
19074
|
until: number(),
|
|
18974
|
-
limit: number().int().min(1).max(
|
|
19075
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18975
19076
|
/** Drop tracks scoring below this importance. */
|
|
18976
19077
|
minImportance: number().min(0).max(1).optional(),
|
|
18977
19078
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18993,6 +19094,32 @@ var KeyEventSchema = object({
|
|
|
18993
19094
|
...TrackFlagFields,
|
|
18994
19095
|
...TrackRetrainFields
|
|
18995
19096
|
});
|
|
19097
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19098
|
+
var KeyEventBatchQueryInput = object({
|
|
19099
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19100
|
+
since: number(),
|
|
19101
|
+
until: number(),
|
|
19102
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19103
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19104
|
+
* rows and change what the merged feed contains. */
|
|
19105
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19106
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19107
|
+
classFilter: string().optional()
|
|
19108
|
+
});
|
|
19109
|
+
/**
|
|
19110
|
+
* One camera's key events in a batch answer.
|
|
19111
|
+
*
|
|
19112
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19113
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19114
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19115
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19116
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19117
|
+
* key, which only worked because there was one query per camera).
|
|
19118
|
+
*/
|
|
19119
|
+
var KeyEventsForDeviceSchema = object({
|
|
19120
|
+
deviceId: number(),
|
|
19121
|
+
events: array(KeyEventSchema).readonly()
|
|
19122
|
+
});
|
|
18996
19123
|
object({
|
|
18997
19124
|
trackId: string(),
|
|
18998
19125
|
className: string(),
|
|
@@ -19064,6 +19191,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19064
19191
|
totalBytes: number().int(),
|
|
19065
19192
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19066
19193
|
});
|
|
19194
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19195
|
+
var EventMediaKindFootprintSchema = object({
|
|
19196
|
+
kind: MediaFileKindEnum,
|
|
19197
|
+
/** Media rows of this kind. */
|
|
19198
|
+
rows: number().int(),
|
|
19199
|
+
/** Bytes on disk held by those rows. */
|
|
19200
|
+
bytes: number().int()
|
|
19201
|
+
});
|
|
19202
|
+
/**
|
|
19203
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19204
|
+
* actually turns on.
|
|
19205
|
+
*
|
|
19206
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19207
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19208
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19209
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19210
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19211
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19212
|
+
*
|
|
19213
|
+
* ## Why `unaccounted*` exists
|
|
19214
|
+
*
|
|
19215
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19216
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19217
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19218
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19219
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19220
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19221
|
+
* against a denominator smaller than the disk.
|
|
19222
|
+
*
|
|
19223
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19224
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19225
|
+
*/
|
|
19226
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19227
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19228
|
+
totalRows: number().int(),
|
|
19229
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19230
|
+
totalBytes: number().int(),
|
|
19231
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19232
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19233
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19234
|
+
unaccountedRows: number().int(),
|
|
19235
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19236
|
+
unaccountedBytes: number().int()
|
|
19237
|
+
});
|
|
19067
19238
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19068
19239
|
var EventPruneCountsSchema = object({
|
|
19069
19240
|
motion: number().int(),
|
|
@@ -19218,7 +19389,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19218
19389
|
until: number().optional(),
|
|
19219
19390
|
kinds: array(string()).optional(),
|
|
19220
19391
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19221
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19392
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19222
19393
|
deviceId: number(),
|
|
19223
19394
|
since: number(),
|
|
19224
19395
|
until: number(),
|
|
@@ -19267,6 +19438,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19267
19438
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19268
19439
|
kind: "query",
|
|
19269
19440
|
auth: "admin"
|
|
19441
|
+
}), method(object({ deviceId: number().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19442
|
+
kind: "query",
|
|
19443
|
+
auth: "admin"
|
|
19270
19444
|
}), method(object({
|
|
19271
19445
|
olderThanMs: number(),
|
|
19272
19446
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21218,6 +21392,20 @@ method(object({
|
|
|
21218
21392
|
error: string().optional()
|
|
21219
21393
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21220
21394
|
providerId: string(),
|
|
21395
|
+
/**
|
|
21396
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21397
|
+
*
|
|
21398
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21399
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21400
|
+
* credential the operator did not retype — and posting that here
|
|
21401
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21402
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21403
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21404
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21405
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21406
|
+
* every value was typed just now and nothing is stored yet.
|
|
21407
|
+
*/
|
|
21408
|
+
locationId: string().optional(),
|
|
21221
21409
|
config: record(string(), unknown())
|
|
21222
21410
|
}), object({
|
|
21223
21411
|
ok: boolean(),
|
|
@@ -26853,6 +27041,9 @@ method(object({
|
|
|
26853
27041
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26854
27042
|
kind: "query",
|
|
26855
27043
|
auth: "admin"
|
|
27044
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27045
|
+
kind: "mutation",
|
|
27046
|
+
auth: "admin"
|
|
26856
27047
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26857
27048
|
kind: "mutation",
|
|
26858
27049
|
auth: "admin"
|
|
@@ -27244,7 +27435,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27244
27435
|
monitors: array(SceneMonitorSchema),
|
|
27245
27436
|
lastFetchedAt: number()
|
|
27246
27437
|
});
|
|
27247
|
-
|
|
27438
|
+
/**
|
|
27439
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27440
|
+
*
|
|
27441
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27442
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27443
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27444
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27445
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27446
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27447
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27448
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27449
|
+
*
|
|
27450
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27451
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27452
|
+
*/
|
|
27453
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27454
|
+
deviceId: number(),
|
|
27455
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27456
|
+
});
|
|
27457
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27248
27458
|
deviceId: number(),
|
|
27249
27459
|
label: string(),
|
|
27250
27460
|
roi: MaskRectShapeSchema,
|
|
@@ -28568,6 +28778,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28568
28778
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28569
28779
|
});
|
|
28570
28780
|
/**
|
|
28781
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28782
|
+
*
|
|
28783
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28784
|
+
* because `snapshot: null` was already spoken for:
|
|
28785
|
+
*
|
|
28786
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28787
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28788
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28789
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28790
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28791
|
+
*
|
|
28792
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28793
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28794
|
+
* which is a definite claim about a camera nobody could read.
|
|
28795
|
+
*/
|
|
28796
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28797
|
+
deviceId: number(),
|
|
28798
|
+
read: _enum(["read", "unreadable"]),
|
|
28799
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28800
|
+
});
|
|
28801
|
+
/**
|
|
28571
28802
|
* Time-series resolution. The history methods return one bucket per
|
|
28572
28803
|
* step over the requested range. Smaller resolutions cost more
|
|
28573
28804
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28591,7 +28822,7 @@ var HistoryPointSchema = object({
|
|
|
28591
28822
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28592
28823
|
count: number().int().nonnegative()
|
|
28593
28824
|
});
|
|
28594
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28825
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28595
28826
|
deviceId: number(),
|
|
28596
28827
|
zoneId: string(),
|
|
28597
28828
|
className: string().optional()
|
|
@@ -31872,6 +32103,12 @@ Object.freeze({
|
|
|
31872
32103
|
addonId: null,
|
|
31873
32104
|
access: "view"
|
|
31874
32105
|
},
|
|
32106
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": {
|
|
32107
|
+
capName: "pipeline-analytics",
|
|
32108
|
+
capScope: "device",
|
|
32109
|
+
addonId: null,
|
|
32110
|
+
access: "view"
|
|
32111
|
+
},
|
|
31875
32112
|
"pipelineAnalytics.getEventStoreFootprint": {
|
|
31876
32113
|
capName: "pipeline-analytics",
|
|
31877
32114
|
capScope: "device",
|
|
@@ -31890,6 +32127,12 @@ Object.freeze({
|
|
|
31890
32127
|
addonId: null,
|
|
31891
32128
|
access: "view"
|
|
31892
32129
|
},
|
|
32130
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32131
|
+
capName: "pipeline-analytics",
|
|
32132
|
+
capScope: "device",
|
|
32133
|
+
addonId: null,
|
|
32134
|
+
access: "view"
|
|
32135
|
+
},
|
|
31893
32136
|
"pipelineAnalytics.getMotionEvents": {
|
|
31894
32137
|
capName: "pipeline-analytics",
|
|
31895
32138
|
capScope: "device",
|
|
@@ -33066,6 +33309,12 @@ Object.freeze({
|
|
|
33066
33309
|
addonId: null,
|
|
33067
33310
|
access: "view"
|
|
33068
33311
|
},
|
|
33312
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33313
|
+
capName: "recording",
|
|
33314
|
+
capScope: "system",
|
|
33315
|
+
addonId: null,
|
|
33316
|
+
access: "create"
|
|
33317
|
+
},
|
|
33069
33318
|
"recording.refreshStorageLocationsForMigration": {
|
|
33070
33319
|
capName: "recording",
|
|
33071
33320
|
capScope: "system",
|
|
@@ -33192,6 +33441,12 @@ Object.freeze({
|
|
|
33192
33441
|
addonId: null,
|
|
33193
33442
|
access: "view"
|
|
33194
33443
|
},
|
|
33444
|
+
"sceneMonitor.listScenesBatch": {
|
|
33445
|
+
capName: "scene-monitor",
|
|
33446
|
+
capScope: "device",
|
|
33447
|
+
addonId: null,
|
|
33448
|
+
access: "view"
|
|
33449
|
+
},
|
|
33195
33450
|
"sceneMonitor.recheckNow": {
|
|
33196
33451
|
capName: "scene-monitor",
|
|
33197
33452
|
capScope: "device",
|
|
@@ -34548,6 +34803,12 @@ Object.freeze({
|
|
|
34548
34803
|
addonId: null,
|
|
34549
34804
|
access: "view"
|
|
34550
34805
|
},
|
|
34806
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34807
|
+
capName: "zone-analytics",
|
|
34808
|
+
capScope: "device",
|
|
34809
|
+
addonId: null,
|
|
34810
|
+
access: "view"
|
|
34811
|
+
},
|
|
34551
34812
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34552
34813
|
capName: "zone-analytics",
|
|
34553
34814
|
capScope: "device",
|
|
@@ -35537,6 +35798,11 @@ Object.freeze({
|
|
|
35537
35798
|
form: "single",
|
|
35538
35799
|
optional: false
|
|
35539
35800
|
}],
|
|
35801
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": [{
|
|
35802
|
+
name: "deviceId",
|
|
35803
|
+
form: "single",
|
|
35804
|
+
optional: true
|
|
35805
|
+
}],
|
|
35540
35806
|
"pipelineAnalytics.getGroup": [{
|
|
35541
35807
|
name: "deviceId",
|
|
35542
35808
|
form: "single",
|
|
@@ -35547,6 +35813,11 @@ Object.freeze({
|
|
|
35547
35813
|
form: "single",
|
|
35548
35814
|
optional: false
|
|
35549
35815
|
}],
|
|
35816
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35817
|
+
name: "deviceIds",
|
|
35818
|
+
form: "array",
|
|
35819
|
+
optional: false
|
|
35820
|
+
}],
|
|
35550
35821
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35551
35822
|
name: "deviceId",
|
|
35552
35823
|
form: "single",
|
|
@@ -35987,6 +36258,11 @@ Object.freeze({
|
|
|
35987
36258
|
form: "single",
|
|
35988
36259
|
optional: false
|
|
35989
36260
|
}],
|
|
36261
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36262
|
+
name: "deviceId",
|
|
36263
|
+
form: "single",
|
|
36264
|
+
optional: true
|
|
36265
|
+
}],
|
|
35990
36266
|
"recording.relocateFootage": [{
|
|
35991
36267
|
name: "deviceId",
|
|
35992
36268
|
form: "single",
|
|
@@ -36052,6 +36328,11 @@ Object.freeze({
|
|
|
36052
36328
|
form: "single",
|
|
36053
36329
|
optional: false
|
|
36054
36330
|
}],
|
|
36331
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36332
|
+
name: "deviceIds",
|
|
36333
|
+
form: "array",
|
|
36334
|
+
optional: false
|
|
36335
|
+
}],
|
|
36055
36336
|
"sceneMonitor.recheckNow": [{
|
|
36056
36337
|
name: "deviceId",
|
|
36057
36338
|
form: "single",
|
|
@@ -36313,6 +36594,11 @@ Object.freeze({
|
|
|
36313
36594
|
form: "single",
|
|
36314
36595
|
optional: false
|
|
36315
36596
|
}],
|
|
36597
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36598
|
+
name: "deviceIds",
|
|
36599
|
+
form: "array",
|
|
36600
|
+
optional: false
|
|
36601
|
+
}],
|
|
36316
36602
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36317
36603
|
name: "deviceId",
|
|
36318
36604
|
form: "single",
|
|
@@ -8159,6 +8159,20 @@ var RelocateJobSchema = object({
|
|
|
8159
8159
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8160
8160
|
*/
|
|
8161
8161
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8162
|
+
/**
|
|
8163
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8164
|
+
*
|
|
8165
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8166
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8167
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8168
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8169
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8170
|
+
* the same failure as one that quietly skips them (D295).
|
|
8171
|
+
*
|
|
8172
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8173
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8174
|
+
*/
|
|
8175
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8162
8176
|
startedAt: number(),
|
|
8163
8177
|
finishedAt: number().nullable(),
|
|
8164
8178
|
error: string().nullable()
|
|
@@ -8522,6 +8536,91 @@ var RelocateResidueSchema = object({
|
|
|
8522
8536
|
segments: number().int().nonnegative(),
|
|
8523
8537
|
bytes: number().int().nonnegative()
|
|
8524
8538
|
}).nullable();
|
|
8539
|
+
/**
|
|
8540
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8541
|
+
* (D319).
|
|
8542
|
+
*
|
|
8543
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8544
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8545
|
+
* destructive run before authorising it.
|
|
8546
|
+
*/
|
|
8547
|
+
var LedgerWalkInputSchema = object({
|
|
8548
|
+
locationId: string().min(1),
|
|
8549
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8550
|
+
apply: boolean().optional(),
|
|
8551
|
+
/** Narrow to one camera. */
|
|
8552
|
+
deviceId: number().int().positive().optional(),
|
|
8553
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8554
|
+
profiles: array(string().min(1)).optional()
|
|
8555
|
+
});
|
|
8556
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8557
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8558
|
+
"location-unknown",
|
|
8559
|
+
"source-writable",
|
|
8560
|
+
"no-ledger",
|
|
8561
|
+
"archive-unreadable",
|
|
8562
|
+
"anchor-absent",
|
|
8563
|
+
"anchor-unreadable",
|
|
8564
|
+
"anchor-moved"
|
|
8565
|
+
]);
|
|
8566
|
+
_enum([
|
|
8567
|
+
"live-tail",
|
|
8568
|
+
"listing-error",
|
|
8569
|
+
"path-mismatch",
|
|
8570
|
+
"durable-refused"
|
|
8571
|
+
]);
|
|
8572
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8573
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8574
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8575
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8576
|
+
"live-tail": number().int().nonnegative(),
|
|
8577
|
+
"listing-error": number().int().nonnegative(),
|
|
8578
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8579
|
+
"durable-refused": number().int().nonnegative()
|
|
8580
|
+
});
|
|
8581
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8582
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8583
|
+
deviceId: number().int(),
|
|
8584
|
+
hoursWalked: number().int().nonnegative(),
|
|
8585
|
+
hoursMissing: number().int().nonnegative(),
|
|
8586
|
+
ghostSegments: number().int().nonnegative(),
|
|
8587
|
+
ghostBytes: number().int().nonnegative(),
|
|
8588
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8589
|
+
orphanFiles: number().int().nonnegative()
|
|
8590
|
+
});
|
|
8591
|
+
/**
|
|
8592
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8593
|
+
*
|
|
8594
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8595
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8596
|
+
* than in the absence of one.
|
|
8597
|
+
*/
|
|
8598
|
+
var LedgerWalkReportSchema = object({
|
|
8599
|
+
locationId: string(),
|
|
8600
|
+
applied: boolean(),
|
|
8601
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8602
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8603
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8604
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8605
|
+
hoursWalked: number().int().nonnegative(),
|
|
8606
|
+
hoursMissing: number().int().nonnegative(),
|
|
8607
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8608
|
+
listings: number().int().nonnegative(),
|
|
8609
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8610
|
+
ghostSegments: number().int().nonnegative(),
|
|
8611
|
+
ghostBytes: number().int().nonnegative(),
|
|
8612
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8613
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8614
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8615
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8616
|
+
orphanFiles: number().int().nonnegative(),
|
|
8617
|
+
orphanSample: array(string()).readonly(),
|
|
8618
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8619
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8620
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8621
|
+
bounded: boolean(),
|
|
8622
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8623
|
+
});
|
|
8525
8624
|
/** How many rows a media pass would still act on against a given target — the
|
|
8526
8625
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8527
8626
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18938,13 +19037,15 @@ var ListGroupsPageSchema = object({
|
|
|
18938
19037
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18939
19038
|
nextCursor: string().nullable()
|
|
18940
19039
|
});
|
|
19040
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19041
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18941
19042
|
var KeyEventQueryInput = object({
|
|
18942
19043
|
deviceId: number(),
|
|
18943
19044
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18944
19045
|
since: number(),
|
|
18945
19046
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18946
19047
|
until: number(),
|
|
18947
|
-
limit: number().int().min(1).max(
|
|
19048
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18948
19049
|
/** Drop tracks scoring below this importance. */
|
|
18949
19050
|
minImportance: number().min(0).max(1).optional(),
|
|
18950
19051
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18966,6 +19067,32 @@ var KeyEventSchema = object({
|
|
|
18966
19067
|
...TrackFlagFields,
|
|
18967
19068
|
...TrackRetrainFields
|
|
18968
19069
|
});
|
|
19070
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19071
|
+
var KeyEventBatchQueryInput = object({
|
|
19072
|
+
deviceIds: array(number()).min(1).max(200),
|
|
19073
|
+
since: number(),
|
|
19074
|
+
until: number(),
|
|
19075
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19076
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19077
|
+
* rows and change what the merged feed contains. */
|
|
19078
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19079
|
+
minImportance: number().min(0).max(1).optional(),
|
|
19080
|
+
classFilter: string().optional()
|
|
19081
|
+
});
|
|
19082
|
+
/**
|
|
19083
|
+
* One camera's key events in a batch answer.
|
|
19084
|
+
*
|
|
19085
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19086
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19087
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19088
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19089
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19090
|
+
* key, which only worked because there was one query per camera).
|
|
19091
|
+
*/
|
|
19092
|
+
var KeyEventsForDeviceSchema = object({
|
|
19093
|
+
deviceId: number(),
|
|
19094
|
+
events: array(KeyEventSchema).readonly()
|
|
19095
|
+
});
|
|
18969
19096
|
object({
|
|
18970
19097
|
trackId: string(),
|
|
18971
19098
|
className: string(),
|
|
@@ -19037,6 +19164,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19037
19164
|
totalBytes: number().int(),
|
|
19038
19165
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19039
19166
|
});
|
|
19167
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19168
|
+
var EventMediaKindFootprintSchema = object({
|
|
19169
|
+
kind: MediaFileKindEnum,
|
|
19170
|
+
/** Media rows of this kind. */
|
|
19171
|
+
rows: number().int(),
|
|
19172
|
+
/** Bytes on disk held by those rows. */
|
|
19173
|
+
bytes: number().int()
|
|
19174
|
+
});
|
|
19175
|
+
/**
|
|
19176
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19177
|
+
* actually turns on.
|
|
19178
|
+
*
|
|
19179
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19180
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19181
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19182
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19183
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19184
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19185
|
+
*
|
|
19186
|
+
* ## Why `unaccounted*` exists
|
|
19187
|
+
*
|
|
19188
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19189
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19190
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19191
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19192
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19193
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19194
|
+
* against a denominator smaller than the disk.
|
|
19195
|
+
*
|
|
19196
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19197
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19198
|
+
*/
|
|
19199
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19200
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19201
|
+
totalRows: number().int(),
|
|
19202
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19203
|
+
totalBytes: number().int(),
|
|
19204
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19205
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19206
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19207
|
+
unaccountedRows: number().int(),
|
|
19208
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19209
|
+
unaccountedBytes: number().int()
|
|
19210
|
+
});
|
|
19040
19211
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19041
19212
|
var EventPruneCountsSchema = object({
|
|
19042
19213
|
motion: number().int(),
|
|
@@ -19191,7 +19362,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19191
19362
|
until: number().optional(),
|
|
19192
19363
|
kinds: array(string()).optional(),
|
|
19193
19364
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19194
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19365
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19195
19366
|
deviceId: number(),
|
|
19196
19367
|
since: number(),
|
|
19197
19368
|
until: number(),
|
|
@@ -19240,6 +19411,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19240
19411
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19241
19412
|
kind: "query",
|
|
19242
19413
|
auth: "admin"
|
|
19414
|
+
}), method(object({ deviceId: number().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19415
|
+
kind: "query",
|
|
19416
|
+
auth: "admin"
|
|
19243
19417
|
}), method(object({
|
|
19244
19418
|
olderThanMs: number(),
|
|
19245
19419
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21191,6 +21365,20 @@ method(object({
|
|
|
21191
21365
|
error: string().optional()
|
|
21192
21366
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21193
21367
|
providerId: string(),
|
|
21368
|
+
/**
|
|
21369
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21370
|
+
*
|
|
21371
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21372
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21373
|
+
* credential the operator did not retype — and posting that here
|
|
21374
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21375
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21376
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21377
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21378
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21379
|
+
* every value was typed just now and nothing is stored yet.
|
|
21380
|
+
*/
|
|
21381
|
+
locationId: string().optional(),
|
|
21194
21382
|
config: record(string(), unknown())
|
|
21195
21383
|
}), object({
|
|
21196
21384
|
ok: boolean(),
|
|
@@ -26826,6 +27014,9 @@ method(object({
|
|
|
26826
27014
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26827
27015
|
kind: "query",
|
|
26828
27016
|
auth: "admin"
|
|
27017
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27018
|
+
kind: "mutation",
|
|
27019
|
+
auth: "admin"
|
|
26829
27020
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26830
27021
|
kind: "mutation",
|
|
26831
27022
|
auth: "admin"
|
|
@@ -27217,7 +27408,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27217
27408
|
monitors: array(SceneMonitorSchema),
|
|
27218
27409
|
lastFetchedAt: number()
|
|
27219
27410
|
});
|
|
27220
|
-
|
|
27411
|
+
/**
|
|
27412
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27413
|
+
*
|
|
27414
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27415
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27416
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27417
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27418
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27419
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27420
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27421
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27422
|
+
*
|
|
27423
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27424
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27425
|
+
*/
|
|
27426
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27427
|
+
deviceId: number(),
|
|
27428
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27429
|
+
});
|
|
27430
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27221
27431
|
deviceId: number(),
|
|
27222
27432
|
label: string(),
|
|
27223
27433
|
roi: MaskRectShapeSchema,
|
|
@@ -28541,6 +28751,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28541
28751
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28542
28752
|
});
|
|
28543
28753
|
/**
|
|
28754
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28755
|
+
*
|
|
28756
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28757
|
+
* because `snapshot: null` was already spoken for:
|
|
28758
|
+
*
|
|
28759
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28760
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28761
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28762
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28763
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28764
|
+
*
|
|
28765
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28766
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28767
|
+
* which is a definite claim about a camera nobody could read.
|
|
28768
|
+
*/
|
|
28769
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28770
|
+
deviceId: number(),
|
|
28771
|
+
read: _enum(["read", "unreadable"]),
|
|
28772
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28773
|
+
});
|
|
28774
|
+
/**
|
|
28544
28775
|
* Time-series resolution. The history methods return one bucket per
|
|
28545
28776
|
* step over the requested range. Smaller resolutions cost more
|
|
28546
28777
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28564,7 +28795,7 @@ var HistoryPointSchema = object({
|
|
|
28564
28795
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28565
28796
|
count: number().int().nonnegative()
|
|
28566
28797
|
});
|
|
28567
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28798
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28568
28799
|
deviceId: number(),
|
|
28569
28800
|
zoneId: string(),
|
|
28570
28801
|
className: string().optional()
|
|
@@ -31845,6 +32076,12 @@ Object.freeze({
|
|
|
31845
32076
|
addonId: null,
|
|
31846
32077
|
access: "view"
|
|
31847
32078
|
},
|
|
32079
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": {
|
|
32080
|
+
capName: "pipeline-analytics",
|
|
32081
|
+
capScope: "device",
|
|
32082
|
+
addonId: null,
|
|
32083
|
+
access: "view"
|
|
32084
|
+
},
|
|
31848
32085
|
"pipelineAnalytics.getEventStoreFootprint": {
|
|
31849
32086
|
capName: "pipeline-analytics",
|
|
31850
32087
|
capScope: "device",
|
|
@@ -31863,6 +32100,12 @@ Object.freeze({
|
|
|
31863
32100
|
addonId: null,
|
|
31864
32101
|
access: "view"
|
|
31865
32102
|
},
|
|
32103
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32104
|
+
capName: "pipeline-analytics",
|
|
32105
|
+
capScope: "device",
|
|
32106
|
+
addonId: null,
|
|
32107
|
+
access: "view"
|
|
32108
|
+
},
|
|
31866
32109
|
"pipelineAnalytics.getMotionEvents": {
|
|
31867
32110
|
capName: "pipeline-analytics",
|
|
31868
32111
|
capScope: "device",
|
|
@@ -33039,6 +33282,12 @@ Object.freeze({
|
|
|
33039
33282
|
addonId: null,
|
|
33040
33283
|
access: "view"
|
|
33041
33284
|
},
|
|
33285
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33286
|
+
capName: "recording",
|
|
33287
|
+
capScope: "system",
|
|
33288
|
+
addonId: null,
|
|
33289
|
+
access: "create"
|
|
33290
|
+
},
|
|
33042
33291
|
"recording.refreshStorageLocationsForMigration": {
|
|
33043
33292
|
capName: "recording",
|
|
33044
33293
|
capScope: "system",
|
|
@@ -33165,6 +33414,12 @@ Object.freeze({
|
|
|
33165
33414
|
addonId: null,
|
|
33166
33415
|
access: "view"
|
|
33167
33416
|
},
|
|
33417
|
+
"sceneMonitor.listScenesBatch": {
|
|
33418
|
+
capName: "scene-monitor",
|
|
33419
|
+
capScope: "device",
|
|
33420
|
+
addonId: null,
|
|
33421
|
+
access: "view"
|
|
33422
|
+
},
|
|
33168
33423
|
"sceneMonitor.recheckNow": {
|
|
33169
33424
|
capName: "scene-monitor",
|
|
33170
33425
|
capScope: "device",
|
|
@@ -34521,6 +34776,12 @@ Object.freeze({
|
|
|
34521
34776
|
addonId: null,
|
|
34522
34777
|
access: "view"
|
|
34523
34778
|
},
|
|
34779
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34780
|
+
capName: "zone-analytics",
|
|
34781
|
+
capScope: "device",
|
|
34782
|
+
addonId: null,
|
|
34783
|
+
access: "view"
|
|
34784
|
+
},
|
|
34524
34785
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34525
34786
|
capName: "zone-analytics",
|
|
34526
34787
|
capScope: "device",
|
|
@@ -35510,6 +35771,11 @@ Object.freeze({
|
|
|
35510
35771
|
form: "single",
|
|
35511
35772
|
optional: false
|
|
35512
35773
|
}],
|
|
35774
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": [{
|
|
35775
|
+
name: "deviceId",
|
|
35776
|
+
form: "single",
|
|
35777
|
+
optional: true
|
|
35778
|
+
}],
|
|
35513
35779
|
"pipelineAnalytics.getGroup": [{
|
|
35514
35780
|
name: "deviceId",
|
|
35515
35781
|
form: "single",
|
|
@@ -35520,6 +35786,11 @@ Object.freeze({
|
|
|
35520
35786
|
form: "single",
|
|
35521
35787
|
optional: false
|
|
35522
35788
|
}],
|
|
35789
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35790
|
+
name: "deviceIds",
|
|
35791
|
+
form: "array",
|
|
35792
|
+
optional: false
|
|
35793
|
+
}],
|
|
35523
35794
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35524
35795
|
name: "deviceId",
|
|
35525
35796
|
form: "single",
|
|
@@ -35960,6 +36231,11 @@ Object.freeze({
|
|
|
35960
36231
|
form: "single",
|
|
35961
36232
|
optional: false
|
|
35962
36233
|
}],
|
|
36234
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36235
|
+
name: "deviceId",
|
|
36236
|
+
form: "single",
|
|
36237
|
+
optional: true
|
|
36238
|
+
}],
|
|
35963
36239
|
"recording.relocateFootage": [{
|
|
35964
36240
|
name: "deviceId",
|
|
35965
36241
|
form: "single",
|
|
@@ -36025,6 +36301,11 @@ Object.freeze({
|
|
|
36025
36301
|
form: "single",
|
|
36026
36302
|
optional: false
|
|
36027
36303
|
}],
|
|
36304
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36305
|
+
name: "deviceIds",
|
|
36306
|
+
form: "array",
|
|
36307
|
+
optional: false
|
|
36308
|
+
}],
|
|
36028
36309
|
"sceneMonitor.recheckNow": [{
|
|
36029
36310
|
name: "deviceId",
|
|
36030
36311
|
form: "single",
|
|
@@ -36286,6 +36567,11 @@ Object.freeze({
|
|
|
36286
36567
|
form: "single",
|
|
36287
36568
|
optional: false
|
|
36288
36569
|
}],
|
|
36570
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36571
|
+
name: "deviceIds",
|
|
36572
|
+
form: "array",
|
|
36573
|
+
optional: false
|
|
36574
|
+
}],
|
|
36289
36575
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36290
36576
|
name: "deviceId",
|
|
36291
36577
|
form: "single",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-alexa",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.55",
|
|
4
4
|
"description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|