@camstack/addon-ai 0.4.43 → 0.4.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +290 -4
- package/dist/addon.mjs +290 -4
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8221,6 +8221,20 @@ var RelocateJobSchema = object({
|
|
|
8221
8221
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8222
8222
|
*/
|
|
8223
8223
|
rowsReconciled: number$1().int().nonnegative().optional(),
|
|
8224
|
+
/**
|
|
8225
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8226
|
+
*
|
|
8227
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8228
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8229
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8230
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8231
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8232
|
+
* the same failure as one that quietly skips them (D295).
|
|
8233
|
+
*
|
|
8234
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8235
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8236
|
+
*/
|
|
8237
|
+
rowsForgotten: number$1().int().nonnegative().optional(),
|
|
8224
8238
|
startedAt: number$1(),
|
|
8225
8239
|
finishedAt: number$1().nullable(),
|
|
8226
8240
|
error: string().nullable()
|
|
@@ -8584,6 +8598,91 @@ var RelocateResidueSchema = object({
|
|
|
8584
8598
|
segments: number$1().int().nonnegative(),
|
|
8585
8599
|
bytes: number$1().int().nonnegative()
|
|
8586
8600
|
}).nullable();
|
|
8601
|
+
/**
|
|
8602
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8603
|
+
* (D319).
|
|
8604
|
+
*
|
|
8605
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8606
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8607
|
+
* destructive run before authorising it.
|
|
8608
|
+
*/
|
|
8609
|
+
var LedgerWalkInputSchema = object({
|
|
8610
|
+
locationId: string().min(1),
|
|
8611
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8612
|
+
apply: boolean().optional(),
|
|
8613
|
+
/** Narrow to one camera. */
|
|
8614
|
+
deviceId: number$1().int().positive().optional(),
|
|
8615
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8616
|
+
profiles: array(string().min(1)).optional()
|
|
8617
|
+
});
|
|
8618
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8619
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8620
|
+
"location-unknown",
|
|
8621
|
+
"source-writable",
|
|
8622
|
+
"no-ledger",
|
|
8623
|
+
"archive-unreadable",
|
|
8624
|
+
"anchor-absent",
|
|
8625
|
+
"anchor-unreadable",
|
|
8626
|
+
"anchor-moved"
|
|
8627
|
+
]);
|
|
8628
|
+
_enum([
|
|
8629
|
+
"live-tail",
|
|
8630
|
+
"listing-error",
|
|
8631
|
+
"path-mismatch",
|
|
8632
|
+
"durable-refused"
|
|
8633
|
+
]);
|
|
8634
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8635
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8636
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8637
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8638
|
+
"live-tail": number$1().int().nonnegative(),
|
|
8639
|
+
"listing-error": number$1().int().nonnegative(),
|
|
8640
|
+
"path-mismatch": number$1().int().nonnegative(),
|
|
8641
|
+
"durable-refused": number$1().int().nonnegative()
|
|
8642
|
+
});
|
|
8643
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8644
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8645
|
+
deviceId: number$1().int(),
|
|
8646
|
+
hoursWalked: number$1().int().nonnegative(),
|
|
8647
|
+
hoursMissing: number$1().int().nonnegative(),
|
|
8648
|
+
ghostSegments: number$1().int().nonnegative(),
|
|
8649
|
+
ghostBytes: number$1().int().nonnegative(),
|
|
8650
|
+
forgottenSegments: number$1().int().nonnegative(),
|
|
8651
|
+
orphanFiles: number$1().int().nonnegative()
|
|
8652
|
+
});
|
|
8653
|
+
/**
|
|
8654
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8655
|
+
*
|
|
8656
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8657
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8658
|
+
* than in the absence of one.
|
|
8659
|
+
*/
|
|
8660
|
+
var LedgerWalkReportSchema = object({
|
|
8661
|
+
locationId: string(),
|
|
8662
|
+
applied: boolean(),
|
|
8663
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8664
|
+
archiveSegments: number$1().int().nonnegative().nullable(),
|
|
8665
|
+
archiveBytes: number$1().int().nonnegative().nullable(),
|
|
8666
|
+
hoursClaimed: number$1().int().nonnegative(),
|
|
8667
|
+
hoursWalked: number$1().int().nonnegative(),
|
|
8668
|
+
hoursMissing: number$1().int().nonnegative(),
|
|
8669
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8670
|
+
listings: number$1().int().nonnegative(),
|
|
8671
|
+
segmentsClaimed: number$1().int().nonnegative(),
|
|
8672
|
+
ghostSegments: number$1().int().nonnegative(),
|
|
8673
|
+
ghostBytes: number$1().int().nonnegative(),
|
|
8674
|
+
ghostHoursWhole: number$1().int().nonnegative(),
|
|
8675
|
+
forgottenSegments: number$1().int().nonnegative(),
|
|
8676
|
+
forgottenBytes: number$1().int().nonnegative(),
|
|
8677
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8678
|
+
orphanFiles: number$1().int().nonnegative(),
|
|
8679
|
+
orphanSample: array(string()).readonly(),
|
|
8680
|
+
hoursSkipped: number$1().int().nonnegative(),
|
|
8681
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8682
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8683
|
+
bounded: boolean(),
|
|
8684
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8685
|
+
});
|
|
8587
8686
|
/** How many rows a media pass would still act on against a given target — the
|
|
8588
8687
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8589
8688
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18951,13 +19050,15 @@ var ListGroupsPageSchema = object({
|
|
|
18951
19050
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18952
19051
|
nextCursor: string().nullable()
|
|
18953
19052
|
});
|
|
19053
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19054
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18954
19055
|
var KeyEventQueryInput = object({
|
|
18955
19056
|
deviceId: number$1(),
|
|
18956
19057
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18957
19058
|
since: number$1(),
|
|
18958
19059
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18959
19060
|
until: number$1(),
|
|
18960
|
-
limit: number$1().int().min(1).max(
|
|
19061
|
+
limit: number$1().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18961
19062
|
/** Drop tracks scoring below this importance. */
|
|
18962
19063
|
minImportance: number$1().min(0).max(1).optional(),
|
|
18963
19064
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18979,6 +19080,32 @@ var KeyEventSchema = object({
|
|
|
18979
19080
|
...TrackFlagFields,
|
|
18980
19081
|
...TrackRetrainFields
|
|
18981
19082
|
});
|
|
19083
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19084
|
+
var KeyEventBatchQueryInput = object({
|
|
19085
|
+
deviceIds: array(number$1()).min(1).max(200),
|
|
19086
|
+
since: number$1(),
|
|
19087
|
+
until: number$1(),
|
|
19088
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19089
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19090
|
+
* rows and change what the merged feed contains. */
|
|
19091
|
+
limit: number$1().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19092
|
+
minImportance: number$1().min(0).max(1).optional(),
|
|
19093
|
+
classFilter: string().optional()
|
|
19094
|
+
});
|
|
19095
|
+
/**
|
|
19096
|
+
* One camera's key events in a batch answer.
|
|
19097
|
+
*
|
|
19098
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19099
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19100
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19101
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19102
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19103
|
+
* key, which only worked because there was one query per camera).
|
|
19104
|
+
*/
|
|
19105
|
+
var KeyEventsForDeviceSchema = object({
|
|
19106
|
+
deviceId: number$1(),
|
|
19107
|
+
events: array(KeyEventSchema).readonly()
|
|
19108
|
+
});
|
|
18982
19109
|
object({
|
|
18983
19110
|
trackId: string(),
|
|
18984
19111
|
className: string(),
|
|
@@ -19050,6 +19177,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19050
19177
|
totalBytes: number$1().int(),
|
|
19051
19178
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19052
19179
|
});
|
|
19180
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19181
|
+
var EventMediaKindFootprintSchema = object({
|
|
19182
|
+
kind: MediaFileKindEnum,
|
|
19183
|
+
/** Media rows of this kind. */
|
|
19184
|
+
rows: number$1().int(),
|
|
19185
|
+
/** Bytes on disk held by those rows. */
|
|
19186
|
+
bytes: number$1().int()
|
|
19187
|
+
});
|
|
19188
|
+
/**
|
|
19189
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19190
|
+
* actually turns on.
|
|
19191
|
+
*
|
|
19192
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19193
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19194
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19195
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19196
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19197
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19198
|
+
*
|
|
19199
|
+
* ## Why `unaccounted*` exists
|
|
19200
|
+
*
|
|
19201
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19202
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19203
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19204
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19205
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19206
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19207
|
+
* against a denominator smaller than the disk.
|
|
19208
|
+
*
|
|
19209
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19210
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19211
|
+
*/
|
|
19212
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19213
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19214
|
+
totalRows: number$1().int(),
|
|
19215
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19216
|
+
totalBytes: number$1().int(),
|
|
19217
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19218
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19219
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19220
|
+
unaccountedRows: number$1().int(),
|
|
19221
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19222
|
+
unaccountedBytes: number$1().int()
|
|
19223
|
+
});
|
|
19053
19224
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19054
19225
|
var EventPruneCountsSchema = object({
|
|
19055
19226
|
motion: number$1().int(),
|
|
@@ -19204,7 +19375,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
19204
19375
|
until: number$1().optional(),
|
|
19205
19376
|
kinds: array(string()).optional(),
|
|
19206
19377
|
limit: number$1().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19207
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19378
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19208
19379
|
deviceId: number$1(),
|
|
19209
19380
|
since: number$1(),
|
|
19210
19381
|
until: number$1(),
|
|
@@ -19253,6 +19424,9 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
19253
19424
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19254
19425
|
kind: "query",
|
|
19255
19426
|
auth: "admin"
|
|
19427
|
+
}), method(object({ deviceId: number$1().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19428
|
+
kind: "query",
|
|
19429
|
+
auth: "admin"
|
|
19256
19430
|
}), method(object({
|
|
19257
19431
|
olderThanMs: number$1(),
|
|
19258
19432
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21204,6 +21378,20 @@ method(object({
|
|
|
21204
21378
|
error: string().optional()
|
|
21205
21379
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21206
21380
|
providerId: string(),
|
|
21381
|
+
/**
|
|
21382
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21383
|
+
*
|
|
21384
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21385
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21386
|
+
* credential the operator did not retype — and posting that here
|
|
21387
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21388
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21389
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21390
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21391
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21392
|
+
* every value was typed just now and nothing is stored yet.
|
|
21393
|
+
*/
|
|
21394
|
+
locationId: string().optional(),
|
|
21207
21395
|
config: record(string(), unknown())
|
|
21208
21396
|
}), object({
|
|
21209
21397
|
ok: boolean(),
|
|
@@ -26839,6 +27027,9 @@ method(object({
|
|
|
26839
27027
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26840
27028
|
kind: "query",
|
|
26841
27029
|
auth: "admin"
|
|
27030
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27031
|
+
kind: "mutation",
|
|
27032
|
+
auth: "admin"
|
|
26842
27033
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26843
27034
|
kind: "mutation",
|
|
26844
27035
|
auth: "admin"
|
|
@@ -27230,7 +27421,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27230
27421
|
monitors: array(SceneMonitorSchema),
|
|
27231
27422
|
lastFetchedAt: number$1()
|
|
27232
27423
|
});
|
|
27233
|
-
|
|
27424
|
+
/**
|
|
27425
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27426
|
+
*
|
|
27427
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27428
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27429
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27430
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27431
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27432
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27433
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27434
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27435
|
+
*
|
|
27436
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27437
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27438
|
+
*/
|
|
27439
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27440
|
+
deviceId: number$1(),
|
|
27441
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27442
|
+
});
|
|
27443
|
+
DeviceType.Camera, method(object({ deviceId: number$1() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27234
27444
|
deviceId: number$1(),
|
|
27235
27445
|
label: string(),
|
|
27236
27446
|
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$1(),
|
|
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$1().int().nonnegative()
|
|
28579
28810
|
});
|
|
28580
|
-
DeviceType.Camera, method(object({ deviceId: number$1() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28811
|
+
DeviceType.Camera, method(object({ deviceId: number$1() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28581
28812
|
deviceId: number$1(),
|
|
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/dist/addon.mjs
CHANGED
|
@@ -8248,6 +8248,20 @@ var RelocateJobSchema = object({
|
|
|
8248
8248
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8249
8249
|
*/
|
|
8250
8250
|
rowsReconciled: number$1().int().nonnegative().optional(),
|
|
8251
|
+
/**
|
|
8252
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8253
|
+
*
|
|
8254
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8255
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8256
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8257
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8258
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8259
|
+
* the same failure as one that quietly skips them (D295).
|
|
8260
|
+
*
|
|
8261
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8262
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8263
|
+
*/
|
|
8264
|
+
rowsForgotten: number$1().int().nonnegative().optional(),
|
|
8251
8265
|
startedAt: number$1(),
|
|
8252
8266
|
finishedAt: number$1().nullable(),
|
|
8253
8267
|
error: string().nullable()
|
|
@@ -8611,6 +8625,91 @@ var RelocateResidueSchema = object({
|
|
|
8611
8625
|
segments: number$1().int().nonnegative(),
|
|
8612
8626
|
bytes: number$1().int().nonnegative()
|
|
8613
8627
|
}).nullable();
|
|
8628
|
+
/**
|
|
8629
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8630
|
+
* (D319).
|
|
8631
|
+
*
|
|
8632
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8633
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8634
|
+
* destructive run before authorising it.
|
|
8635
|
+
*/
|
|
8636
|
+
var LedgerWalkInputSchema = object({
|
|
8637
|
+
locationId: string().min(1),
|
|
8638
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8639
|
+
apply: boolean().optional(),
|
|
8640
|
+
/** Narrow to one camera. */
|
|
8641
|
+
deviceId: number$1().int().positive().optional(),
|
|
8642
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8643
|
+
profiles: array(string().min(1)).optional()
|
|
8644
|
+
});
|
|
8645
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8646
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8647
|
+
"location-unknown",
|
|
8648
|
+
"source-writable",
|
|
8649
|
+
"no-ledger",
|
|
8650
|
+
"archive-unreadable",
|
|
8651
|
+
"anchor-absent",
|
|
8652
|
+
"anchor-unreadable",
|
|
8653
|
+
"anchor-moved"
|
|
8654
|
+
]);
|
|
8655
|
+
_enum([
|
|
8656
|
+
"live-tail",
|
|
8657
|
+
"listing-error",
|
|
8658
|
+
"path-mismatch",
|
|
8659
|
+
"durable-refused"
|
|
8660
|
+
]);
|
|
8661
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8662
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8663
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8664
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8665
|
+
"live-tail": number$1().int().nonnegative(),
|
|
8666
|
+
"listing-error": number$1().int().nonnegative(),
|
|
8667
|
+
"path-mismatch": number$1().int().nonnegative(),
|
|
8668
|
+
"durable-refused": number$1().int().nonnegative()
|
|
8669
|
+
});
|
|
8670
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8671
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8672
|
+
deviceId: number$1().int(),
|
|
8673
|
+
hoursWalked: number$1().int().nonnegative(),
|
|
8674
|
+
hoursMissing: number$1().int().nonnegative(),
|
|
8675
|
+
ghostSegments: number$1().int().nonnegative(),
|
|
8676
|
+
ghostBytes: number$1().int().nonnegative(),
|
|
8677
|
+
forgottenSegments: number$1().int().nonnegative(),
|
|
8678
|
+
orphanFiles: number$1().int().nonnegative()
|
|
8679
|
+
});
|
|
8680
|
+
/**
|
|
8681
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8682
|
+
*
|
|
8683
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8684
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8685
|
+
* than in the absence of one.
|
|
8686
|
+
*/
|
|
8687
|
+
var LedgerWalkReportSchema = object({
|
|
8688
|
+
locationId: string(),
|
|
8689
|
+
applied: boolean(),
|
|
8690
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8691
|
+
archiveSegments: number$1().int().nonnegative().nullable(),
|
|
8692
|
+
archiveBytes: number$1().int().nonnegative().nullable(),
|
|
8693
|
+
hoursClaimed: number$1().int().nonnegative(),
|
|
8694
|
+
hoursWalked: number$1().int().nonnegative(),
|
|
8695
|
+
hoursMissing: number$1().int().nonnegative(),
|
|
8696
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8697
|
+
listings: number$1().int().nonnegative(),
|
|
8698
|
+
segmentsClaimed: number$1().int().nonnegative(),
|
|
8699
|
+
ghostSegments: number$1().int().nonnegative(),
|
|
8700
|
+
ghostBytes: number$1().int().nonnegative(),
|
|
8701
|
+
ghostHoursWhole: number$1().int().nonnegative(),
|
|
8702
|
+
forgottenSegments: number$1().int().nonnegative(),
|
|
8703
|
+
forgottenBytes: number$1().int().nonnegative(),
|
|
8704
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8705
|
+
orphanFiles: number$1().int().nonnegative(),
|
|
8706
|
+
orphanSample: array(string()).readonly(),
|
|
8707
|
+
hoursSkipped: number$1().int().nonnegative(),
|
|
8708
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8709
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8710
|
+
bounded: boolean(),
|
|
8711
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8712
|
+
});
|
|
8614
8713
|
/** How many rows a media pass would still act on against a given target — the
|
|
8615
8714
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8616
8715
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18978,13 +19077,15 @@ var ListGroupsPageSchema = object({
|
|
|
18978
19077
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18979
19078
|
nextCursor: string().nullable()
|
|
18980
19079
|
});
|
|
19080
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
19081
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18981
19082
|
var KeyEventQueryInput = object({
|
|
18982
19083
|
deviceId: number$1(),
|
|
18983
19084
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18984
19085
|
since: number$1(),
|
|
18985
19086
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18986
19087
|
until: number$1(),
|
|
18987
|
-
limit: number$1().int().min(1).max(
|
|
19088
|
+
limit: number$1().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18988
19089
|
/** Drop tracks scoring below this importance. */
|
|
18989
19090
|
minImportance: number$1().min(0).max(1).optional(),
|
|
18990
19091
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -19006,6 +19107,32 @@ var KeyEventSchema = object({
|
|
|
19006
19107
|
...TrackFlagFields,
|
|
19007
19108
|
...TrackRetrainFields
|
|
19008
19109
|
});
|
|
19110
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
19111
|
+
var KeyEventBatchQueryInput = object({
|
|
19112
|
+
deviceIds: array(number$1()).min(1).max(200),
|
|
19113
|
+
since: number$1(),
|
|
19114
|
+
until: number$1(),
|
|
19115
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
19116
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
19117
|
+
* rows and change what the merged feed contains. */
|
|
19118
|
+
limit: number$1().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
19119
|
+
minImportance: number$1().min(0).max(1).optional(),
|
|
19120
|
+
classFilter: string().optional()
|
|
19121
|
+
});
|
|
19122
|
+
/**
|
|
19123
|
+
* One camera's key events in a batch answer.
|
|
19124
|
+
*
|
|
19125
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
19126
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
19127
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
19128
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
19129
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
19130
|
+
* key, which only worked because there was one query per camera).
|
|
19131
|
+
*/
|
|
19132
|
+
var KeyEventsForDeviceSchema = object({
|
|
19133
|
+
deviceId: number$1(),
|
|
19134
|
+
events: array(KeyEventSchema).readonly()
|
|
19135
|
+
});
|
|
19009
19136
|
object({
|
|
19010
19137
|
trackId: string(),
|
|
19011
19138
|
className: string(),
|
|
@@ -19077,6 +19204,50 @@ var EventStoreFootprintSchema = object({
|
|
|
19077
19204
|
totalBytes: number$1().int(),
|
|
19078
19205
|
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
19079
19206
|
});
|
|
19207
|
+
/** Event-media footprint for one {@link MediaFileKind}. */
|
|
19208
|
+
var EventMediaKindFootprintSchema = object({
|
|
19209
|
+
kind: MediaFileKindEnum,
|
|
19210
|
+
/** Media rows of this kind. */
|
|
19211
|
+
rows: number$1().int(),
|
|
19212
|
+
/** Bytes on disk held by those rows. */
|
|
19213
|
+
bytes: number$1().int()
|
|
19214
|
+
});
|
|
19215
|
+
/**
|
|
19216
|
+
* The media footprint broken down by KIND — the axis a deletion decision
|
|
19217
|
+
* actually turns on.
|
|
19218
|
+
*
|
|
19219
|
+
* A byte total says how much there is; it cannot say what is safe to remove.
|
|
19220
|
+
* The deletable set (the periodic `snapshot` filmstrip, the surplus per-edge
|
|
19221
|
+
* motion stills) and the keep set (`firstFrame`, rolling `lastFrame`,
|
|
19222
|
+
* `thumbnail`/`thumbnailSmall`, `keyFrame`/`keyFrameSmall`, the face/plate
|
|
19223
|
+
* buffers, gallery media, the CLIP `crop`) are distinguished by `kind` and by
|
|
19224
|
+
* nothing else, so sizing a deletion means summing per kind.
|
|
19225
|
+
*
|
|
19226
|
+
* ## Why `unaccounted*` exists
|
|
19227
|
+
*
|
|
19228
|
+
* `kinds` is enumerated from {@link MediaFileKindEnum} — the closed set the
|
|
19229
|
+
* writers use — and summed one kind at a time. `totalRows` / `totalBytes` come
|
|
19230
|
+
* from a SEPARATE unfiltered aggregate over the same rows, never from adding
|
|
19231
|
+
* `kinds` up. A row whose stored `kind` is not in the enum (written by a
|
|
19232
|
+
* retired code path, or by a version that knew a kind this one does not) would
|
|
19233
|
+
* otherwise vanish from the total silently, and an operator would delete
|
|
19234
|
+
* against a denominator smaller than the disk.
|
|
19235
|
+
*
|
|
19236
|
+
* `unaccountedRows` / `unaccountedBytes` are the difference. They are normally
|
|
19237
|
+
* zero; a non-zero value is a real finding and must be shown, not rounded away.
|
|
19238
|
+
*/
|
|
19239
|
+
var EventMediaKindBreakdownSchema = object({
|
|
19240
|
+
/** Every media row in scope, from one unfiltered aggregate. */
|
|
19241
|
+
totalRows: number$1().int(),
|
|
19242
|
+
/** Every media byte in scope, from that same aggregate. */
|
|
19243
|
+
totalBytes: number$1().int(),
|
|
19244
|
+
/** Per-kind footprint, ordered by bytes descending. */
|
|
19245
|
+
kinds: array(EventMediaKindFootprintSchema).readonly(),
|
|
19246
|
+
/** `totalRows` minus the summed `kinds` rows — see the schema note. */
|
|
19247
|
+
unaccountedRows: number$1().int(),
|
|
19248
|
+
/** `totalBytes` minus the summed `kinds` bytes — see the schema note. */
|
|
19249
|
+
unaccountedBytes: number$1().int()
|
|
19250
|
+
});
|
|
19080
19251
|
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
19081
19252
|
var EventPruneCountsSchema = object({
|
|
19082
19253
|
motion: number$1().int(),
|
|
@@ -19231,7 +19402,7 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
19231
19402
|
until: number$1().optional(),
|
|
19232
19403
|
kinds: array(string()).optional(),
|
|
19233
19404
|
limit: number$1().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
19234
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19405
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
19235
19406
|
deviceId: number$1(),
|
|
19236
19407
|
since: number$1(),
|
|
19237
19408
|
until: number$1(),
|
|
@@ -19280,6 +19451,9 @@ DeviceType.Camera, method(object({ deviceId: number$1() }), array(TrackSchema).r
|
|
|
19280
19451
|
}), TrackFlagsSchema, { kind: "mutation" }), method(object({}), EventStoreFootprintSchema, {
|
|
19281
19452
|
kind: "query",
|
|
19282
19453
|
auth: "admin"
|
|
19454
|
+
}), method(object({ deviceId: number$1().int().optional() }), EventMediaKindBreakdownSchema, {
|
|
19455
|
+
kind: "query",
|
|
19456
|
+
auth: "admin"
|
|
19283
19457
|
}), method(object({
|
|
19284
19458
|
olderThanMs: number$1(),
|
|
19285
19459
|
reason: OpsLogReasonSchema.optional()
|
|
@@ -21231,6 +21405,20 @@ method(object({
|
|
|
21231
21405
|
error: string().optional()
|
|
21232
21406
|
}), { auth: "admin" }), method(_void(), array(ProviderListEntrySchema).readonly()), method(object({
|
|
21233
21407
|
providerId: string(),
|
|
21408
|
+
/**
|
|
21409
|
+
* The location this config is an UNSAVED edit of, when there is one.
|
|
21410
|
+
*
|
|
21411
|
+
* `listLocations` replaces every declared secret with the redaction
|
|
21412
|
+
* sentinel, so the edit modal's form state holds the sentinel for any
|
|
21413
|
+
* credential the operator did not retype — and posting that here
|
|
21414
|
+
* without a way to resolve it makes the provider try to authenticate
|
|
21415
|
+
* as `__camstack_redacted__` and report the operator's own working
|
|
21416
|
+
* password as wrong. Given this id, the orchestrator restores each
|
|
21417
|
+
* sentinel from the stored config (same rule as `upsertLocation`)
|
|
21418
|
+
* before dispatching. Omitted by the "Add location" wizard, where
|
|
21419
|
+
* every value was typed just now and nothing is stored yet.
|
|
21420
|
+
*/
|
|
21421
|
+
locationId: string().optional(),
|
|
21234
21422
|
config: record(string(), unknown())
|
|
21235
21423
|
}), object({
|
|
21236
21424
|
ok: boolean(),
|
|
@@ -26866,6 +27054,9 @@ method(object({
|
|
|
26866
27054
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26867
27055
|
kind: "query",
|
|
26868
27056
|
auth: "admin"
|
|
27057
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
27058
|
+
kind: "mutation",
|
|
27059
|
+
auth: "admin"
|
|
26869
27060
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26870
27061
|
kind: "mutation",
|
|
26871
27062
|
auth: "admin"
|
|
@@ -27257,7 +27448,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27257
27448
|
monitors: array(SceneMonitorSchema),
|
|
27258
27449
|
lastFetchedAt: number$1()
|
|
27259
27450
|
});
|
|
27260
|
-
|
|
27451
|
+
/**
|
|
27452
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27453
|
+
*
|
|
27454
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27455
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27456
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27457
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27458
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27459
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27460
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27461
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27462
|
+
*
|
|
27463
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27464
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27465
|
+
*/
|
|
27466
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27467
|
+
deviceId: number$1(),
|
|
27468
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27469
|
+
});
|
|
27470
|
+
DeviceType.Camera, method(object({ deviceId: number$1() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27261
27471
|
deviceId: number$1(),
|
|
27262
27472
|
label: string(),
|
|
27263
27473
|
roi: MaskRectShapeSchema,
|
|
@@ -28581,6 +28791,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28581
28791
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28582
28792
|
});
|
|
28583
28793
|
/**
|
|
28794
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28795
|
+
*
|
|
28796
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28797
|
+
* because `snapshot: null` was already spoken for:
|
|
28798
|
+
*
|
|
28799
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28800
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28801
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28802
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28803
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28804
|
+
*
|
|
28805
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28806
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28807
|
+
* which is a definite claim about a camera nobody could read.
|
|
28808
|
+
*/
|
|
28809
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28810
|
+
deviceId: number$1(),
|
|
28811
|
+
read: _enum(["read", "unreadable"]),
|
|
28812
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28813
|
+
});
|
|
28814
|
+
/**
|
|
28584
28815
|
* Time-series resolution. The history methods return one bucket per
|
|
28585
28816
|
* step over the requested range. Smaller resolutions cost more
|
|
28586
28817
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28604,7 +28835,7 @@ var HistoryPointSchema = object({
|
|
|
28604
28835
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28605
28836
|
count: number$1().int().nonnegative()
|
|
28606
28837
|
});
|
|
28607
|
-
DeviceType.Camera, method(object({ deviceId: number$1() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28838
|
+
DeviceType.Camera, method(object({ deviceId: number$1() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number$1()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28608
28839
|
deviceId: number$1(),
|
|
28609
28840
|
zoneId: string(),
|
|
28610
28841
|
className: string().optional()
|
|
@@ -31885,6 +32116,12 @@ Object.freeze({
|
|
|
31885
32116
|
addonId: null,
|
|
31886
32117
|
access: "view"
|
|
31887
32118
|
},
|
|
32119
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": {
|
|
32120
|
+
capName: "pipeline-analytics",
|
|
32121
|
+
capScope: "device",
|
|
32122
|
+
addonId: null,
|
|
32123
|
+
access: "view"
|
|
32124
|
+
},
|
|
31888
32125
|
"pipelineAnalytics.getEventStoreFootprint": {
|
|
31889
32126
|
capName: "pipeline-analytics",
|
|
31890
32127
|
capScope: "device",
|
|
@@ -31903,6 +32140,12 @@ Object.freeze({
|
|
|
31903
32140
|
addonId: null,
|
|
31904
32141
|
access: "view"
|
|
31905
32142
|
},
|
|
32143
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
32144
|
+
capName: "pipeline-analytics",
|
|
32145
|
+
capScope: "device",
|
|
32146
|
+
addonId: null,
|
|
32147
|
+
access: "view"
|
|
32148
|
+
},
|
|
31906
32149
|
"pipelineAnalytics.getMotionEvents": {
|
|
31907
32150
|
capName: "pipeline-analytics",
|
|
31908
32151
|
capScope: "device",
|
|
@@ -33079,6 +33322,12 @@ Object.freeze({
|
|
|
33079
33322
|
addonId: null,
|
|
33080
33323
|
access: "view"
|
|
33081
33324
|
},
|
|
33325
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33326
|
+
capName: "recording",
|
|
33327
|
+
capScope: "system",
|
|
33328
|
+
addonId: null,
|
|
33329
|
+
access: "create"
|
|
33330
|
+
},
|
|
33082
33331
|
"recording.refreshStorageLocationsForMigration": {
|
|
33083
33332
|
capName: "recording",
|
|
33084
33333
|
capScope: "system",
|
|
@@ -33205,6 +33454,12 @@ Object.freeze({
|
|
|
33205
33454
|
addonId: null,
|
|
33206
33455
|
access: "view"
|
|
33207
33456
|
},
|
|
33457
|
+
"sceneMonitor.listScenesBatch": {
|
|
33458
|
+
capName: "scene-monitor",
|
|
33459
|
+
capScope: "device",
|
|
33460
|
+
addonId: null,
|
|
33461
|
+
access: "view"
|
|
33462
|
+
},
|
|
33208
33463
|
"sceneMonitor.recheckNow": {
|
|
33209
33464
|
capName: "scene-monitor",
|
|
33210
33465
|
capScope: "device",
|
|
@@ -34561,6 +34816,12 @@ Object.freeze({
|
|
|
34561
34816
|
addonId: null,
|
|
34562
34817
|
access: "view"
|
|
34563
34818
|
},
|
|
34819
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34820
|
+
capName: "zone-analytics",
|
|
34821
|
+
capScope: "device",
|
|
34822
|
+
addonId: null,
|
|
34823
|
+
access: "view"
|
|
34824
|
+
},
|
|
34564
34825
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34565
34826
|
capName: "zone-analytics",
|
|
34566
34827
|
capScope: "device",
|
|
@@ -35550,6 +35811,11 @@ Object.freeze({
|
|
|
35550
35811
|
form: "single",
|
|
35551
35812
|
optional: false
|
|
35552
35813
|
}],
|
|
35814
|
+
"pipelineAnalytics.getEventMediaFootprintByKind": [{
|
|
35815
|
+
name: "deviceId",
|
|
35816
|
+
form: "single",
|
|
35817
|
+
optional: true
|
|
35818
|
+
}],
|
|
35553
35819
|
"pipelineAnalytics.getGroup": [{
|
|
35554
35820
|
name: "deviceId",
|
|
35555
35821
|
form: "single",
|
|
@@ -35560,6 +35826,11 @@ Object.freeze({
|
|
|
35560
35826
|
form: "single",
|
|
35561
35827
|
optional: false
|
|
35562
35828
|
}],
|
|
35829
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35830
|
+
name: "deviceIds",
|
|
35831
|
+
form: "array",
|
|
35832
|
+
optional: false
|
|
35833
|
+
}],
|
|
35563
35834
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35564
35835
|
name: "deviceId",
|
|
35565
35836
|
form: "single",
|
|
@@ -36000,6 +36271,11 @@ Object.freeze({
|
|
|
36000
36271
|
form: "single",
|
|
36001
36272
|
optional: false
|
|
36002
36273
|
}],
|
|
36274
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
36275
|
+
name: "deviceId",
|
|
36276
|
+
form: "single",
|
|
36277
|
+
optional: true
|
|
36278
|
+
}],
|
|
36003
36279
|
"recording.relocateFootage": [{
|
|
36004
36280
|
name: "deviceId",
|
|
36005
36281
|
form: "single",
|
|
@@ -36065,6 +36341,11 @@ Object.freeze({
|
|
|
36065
36341
|
form: "single",
|
|
36066
36342
|
optional: false
|
|
36067
36343
|
}],
|
|
36344
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36345
|
+
name: "deviceIds",
|
|
36346
|
+
form: "array",
|
|
36347
|
+
optional: false
|
|
36348
|
+
}],
|
|
36068
36349
|
"sceneMonitor.recheckNow": [{
|
|
36069
36350
|
name: "deviceId",
|
|
36070
36351
|
form: "single",
|
|
@@ -36326,6 +36607,11 @@ Object.freeze({
|
|
|
36326
36607
|
form: "single",
|
|
36327
36608
|
optional: false
|
|
36328
36609
|
}],
|
|
36610
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36611
|
+
name: "deviceIds",
|
|
36612
|
+
form: "array",
|
|
36613
|
+
optional: false
|
|
36614
|
+
}],
|
|
36329
36615
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36330
36616
|
name: "deviceId",
|
|
36331
36617
|
form: "single",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.45",
|
|
4
4
|
"description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|