@camstack/addon-static-turn 1.1.26 → 1.1.28
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/static-turn.addon.js +511 -2
- package/dist/static-turn.addon.mjs +511 -2
- package/package.json +1 -1
|
@@ -7328,6 +7328,62 @@ var RecordingConfigSchema = object({
|
|
|
7328
7328
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7329
7329
|
});
|
|
7330
7330
|
/**
|
|
7331
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7332
|
+
* recordings and events management surfaces.
|
|
7333
|
+
*
|
|
7334
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7335
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7336
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7337
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7338
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7339
|
+
* never fail the operation it records.
|
|
7340
|
+
*/
|
|
7341
|
+
/** Which management domain the operation belongs to. */
|
|
7342
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7343
|
+
/** The kind of management operation performed. */
|
|
7344
|
+
var OpsLogOpSchema = _enum([
|
|
7345
|
+
"prune",
|
|
7346
|
+
"manual-delete",
|
|
7347
|
+
"rescan",
|
|
7348
|
+
"retention-run"
|
|
7349
|
+
]);
|
|
7350
|
+
/** Why the operation ran. */
|
|
7351
|
+
var OpsLogReasonSchema = _enum([
|
|
7352
|
+
"retention",
|
|
7353
|
+
"quota",
|
|
7354
|
+
"manual",
|
|
7355
|
+
"operator"
|
|
7356
|
+
]);
|
|
7357
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7358
|
+
var OpsLogEntrySchema = object({
|
|
7359
|
+
/** Unique row id. */
|
|
7360
|
+
id: string(),
|
|
7361
|
+
/** Epoch ms the operation completed. */
|
|
7362
|
+
at: number(),
|
|
7363
|
+
domain: OpsLogDomainSchema,
|
|
7364
|
+
op: OpsLogOpSchema,
|
|
7365
|
+
reason: OpsLogReasonSchema,
|
|
7366
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7367
|
+
deviceId: number().nullable(),
|
|
7368
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7369
|
+
nodeId: string(),
|
|
7370
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7371
|
+
itemsAffected: number(),
|
|
7372
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7373
|
+
bytesReclaimed: number(),
|
|
7374
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7375
|
+
detail: string().nullable(),
|
|
7376
|
+
/** Who/what triggered the op. */
|
|
7377
|
+
actor: string()
|
|
7378
|
+
});
|
|
7379
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7380
|
+
var OpsLogQueryInputSchema = object({
|
|
7381
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7382
|
+
deviceId: number().optional(),
|
|
7383
|
+
/** Max rows returned, newest-first. */
|
|
7384
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7385
|
+
});
|
|
7386
|
+
/**
|
|
7331
7387
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7332
7388
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7333
7389
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7571,6 +7627,160 @@ var EncodeProfileSchema = object({
|
|
|
7571
7627
|
*/
|
|
7572
7628
|
outputArgs: array(string()).optional()
|
|
7573
7629
|
});
|
|
7630
|
+
var COCO_TO_MACRO = {
|
|
7631
|
+
mapping: {
|
|
7632
|
+
person: "person",
|
|
7633
|
+
bicycle: "vehicle",
|
|
7634
|
+
car: "vehicle",
|
|
7635
|
+
motorcycle: "vehicle",
|
|
7636
|
+
airplane: "vehicle",
|
|
7637
|
+
bus: "vehicle",
|
|
7638
|
+
train: "vehicle",
|
|
7639
|
+
truck: "vehicle",
|
|
7640
|
+
boat: "vehicle",
|
|
7641
|
+
bird: "animal",
|
|
7642
|
+
cat: "animal",
|
|
7643
|
+
dog: "animal",
|
|
7644
|
+
horse: "animal",
|
|
7645
|
+
sheep: "animal",
|
|
7646
|
+
cow: "animal",
|
|
7647
|
+
elephant: "animal",
|
|
7648
|
+
bear: "animal",
|
|
7649
|
+
zebra: "animal",
|
|
7650
|
+
giraffe: "animal",
|
|
7651
|
+
suitcase: "package",
|
|
7652
|
+
backpack: "package",
|
|
7653
|
+
handbag: "package"
|
|
7654
|
+
},
|
|
7655
|
+
preserveOriginal: false
|
|
7656
|
+
};
|
|
7657
|
+
var AUDIO_MACRO_LABELS = [
|
|
7658
|
+
{
|
|
7659
|
+
id: "speech",
|
|
7660
|
+
name: "Speech",
|
|
7661
|
+
icon: "🗣️"
|
|
7662
|
+
},
|
|
7663
|
+
{
|
|
7664
|
+
id: "scream",
|
|
7665
|
+
name: "Scream / Shout",
|
|
7666
|
+
icon: "😱"
|
|
7667
|
+
},
|
|
7668
|
+
{
|
|
7669
|
+
id: "crying",
|
|
7670
|
+
name: "Crying / Baby",
|
|
7671
|
+
icon: "😢"
|
|
7672
|
+
},
|
|
7673
|
+
{
|
|
7674
|
+
id: "laughter",
|
|
7675
|
+
name: "Laughter",
|
|
7676
|
+
icon: "😂"
|
|
7677
|
+
},
|
|
7678
|
+
{
|
|
7679
|
+
id: "music",
|
|
7680
|
+
name: "Music",
|
|
7681
|
+
icon: "🎵"
|
|
7682
|
+
},
|
|
7683
|
+
{
|
|
7684
|
+
id: "dog",
|
|
7685
|
+
name: "Dog",
|
|
7686
|
+
icon: "🐕"
|
|
7687
|
+
},
|
|
7688
|
+
{
|
|
7689
|
+
id: "cat",
|
|
7690
|
+
name: "Cat",
|
|
7691
|
+
icon: "🐈"
|
|
7692
|
+
},
|
|
7693
|
+
{
|
|
7694
|
+
id: "bird",
|
|
7695
|
+
name: "Bird",
|
|
7696
|
+
icon: "🐦"
|
|
7697
|
+
},
|
|
7698
|
+
{
|
|
7699
|
+
id: "animal",
|
|
7700
|
+
name: "Animal (other)",
|
|
7701
|
+
icon: "🐾"
|
|
7702
|
+
},
|
|
7703
|
+
{
|
|
7704
|
+
id: "alarm",
|
|
7705
|
+
name: "Alarm / Siren",
|
|
7706
|
+
icon: "🚨"
|
|
7707
|
+
},
|
|
7708
|
+
{
|
|
7709
|
+
id: "doorbell",
|
|
7710
|
+
name: "Doorbell / Knock",
|
|
7711
|
+
icon: "🔔"
|
|
7712
|
+
},
|
|
7713
|
+
{
|
|
7714
|
+
id: "glass_breaking",
|
|
7715
|
+
name: "Glass Breaking",
|
|
7716
|
+
icon: "💥"
|
|
7717
|
+
},
|
|
7718
|
+
{
|
|
7719
|
+
id: "gunshot",
|
|
7720
|
+
name: "Gunshot / Explosion",
|
|
7721
|
+
icon: "💣"
|
|
7722
|
+
},
|
|
7723
|
+
{
|
|
7724
|
+
id: "vehicle",
|
|
7725
|
+
name: "Vehicle",
|
|
7726
|
+
icon: "🚗"
|
|
7727
|
+
},
|
|
7728
|
+
{
|
|
7729
|
+
id: "siren",
|
|
7730
|
+
name: "Emergency Siren",
|
|
7731
|
+
icon: "🚑"
|
|
7732
|
+
},
|
|
7733
|
+
{
|
|
7734
|
+
id: "fire",
|
|
7735
|
+
name: "Fire / Smoke",
|
|
7736
|
+
icon: "🔥"
|
|
7737
|
+
},
|
|
7738
|
+
{
|
|
7739
|
+
id: "water",
|
|
7740
|
+
name: "Water",
|
|
7741
|
+
icon: "💧"
|
|
7742
|
+
},
|
|
7743
|
+
{
|
|
7744
|
+
id: "wind",
|
|
7745
|
+
name: "Wind / Weather",
|
|
7746
|
+
icon: "🌬️"
|
|
7747
|
+
},
|
|
7748
|
+
{
|
|
7749
|
+
id: "door",
|
|
7750
|
+
name: "Door",
|
|
7751
|
+
icon: "🚪"
|
|
7752
|
+
},
|
|
7753
|
+
{
|
|
7754
|
+
id: "footsteps",
|
|
7755
|
+
name: "Footsteps",
|
|
7756
|
+
icon: "👣"
|
|
7757
|
+
},
|
|
7758
|
+
{
|
|
7759
|
+
id: "crowd",
|
|
7760
|
+
name: "Crowd / Chatter",
|
|
7761
|
+
icon: "👥"
|
|
7762
|
+
},
|
|
7763
|
+
{
|
|
7764
|
+
id: "telephone",
|
|
7765
|
+
name: "Telephone",
|
|
7766
|
+
icon: "📞"
|
|
7767
|
+
},
|
|
7768
|
+
{
|
|
7769
|
+
id: "engine",
|
|
7770
|
+
name: "Engine / Motor",
|
|
7771
|
+
icon: "⚙️"
|
|
7772
|
+
},
|
|
7773
|
+
{
|
|
7774
|
+
id: "tools",
|
|
7775
|
+
name: "Tools / Construction",
|
|
7776
|
+
icon: "🔨"
|
|
7777
|
+
},
|
|
7778
|
+
{
|
|
7779
|
+
id: "silence",
|
|
7780
|
+
name: "Silence",
|
|
7781
|
+
icon: "🤫"
|
|
7782
|
+
}
|
|
7783
|
+
];
|
|
7574
7784
|
var YAMNET_TO_MACRO = {
|
|
7575
7785
|
mapping: {
|
|
7576
7786
|
Speech: "speech",
|
|
@@ -7837,6 +8047,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7837
8047
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7838
8048
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7839
8049
|
/**
|
|
8050
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8051
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8052
|
+
* icon }`.
|
|
8053
|
+
*
|
|
8054
|
+
* This dictionary folds together what used to be scattered across four
|
|
8055
|
+
* copies:
|
|
8056
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8057
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8058
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8059
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8060
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8061
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8062
|
+
*
|
|
8063
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8064
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8065
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8066
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8067
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8068
|
+
*
|
|
8069
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8070
|
+
*/
|
|
8071
|
+
var TAXONOMY_COLORS = {
|
|
8072
|
+
motion: "#f59e0b",
|
|
8073
|
+
audio: "#06b6d4",
|
|
8074
|
+
person: "#22c55e",
|
|
8075
|
+
vehicle: "#3b82f6",
|
|
8076
|
+
animal: "#f97316",
|
|
8077
|
+
package: "#a855f7",
|
|
8078
|
+
sensor: "#8b5cf6",
|
|
8079
|
+
control: "#10b981",
|
|
8080
|
+
genericDetection: "#64748b"
|
|
8081
|
+
};
|
|
8082
|
+
var DETECTION_SUB_COLORS = {
|
|
8083
|
+
car: "#f59e0b",
|
|
8084
|
+
truck: "#d97706",
|
|
8085
|
+
bus: "#b45309",
|
|
8086
|
+
motorcycle: "#eab308",
|
|
8087
|
+
bicycle: "#ca8a04",
|
|
8088
|
+
airplane: "#60a5fa",
|
|
8089
|
+
boat: "#2563eb",
|
|
8090
|
+
train: "#1d4ed8",
|
|
8091
|
+
bird: "#14b8a6",
|
|
8092
|
+
dog: "#84cc16",
|
|
8093
|
+
cat: "#f97316",
|
|
8094
|
+
horse: "#a16207",
|
|
8095
|
+
sheep: "#a3a3a3",
|
|
8096
|
+
cow: "#78716c",
|
|
8097
|
+
elephant: "#6b7280",
|
|
8098
|
+
bear: "#7c2d12",
|
|
8099
|
+
zebra: "#404040",
|
|
8100
|
+
giraffe: "#d4a373"
|
|
8101
|
+
};
|
|
8102
|
+
function titleCase(id) {
|
|
8103
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8104
|
+
}
|
|
8105
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8106
|
+
function macro(kind, category, color, iconId, label) {
|
|
8107
|
+
entries.set(kind, {
|
|
8108
|
+
kind,
|
|
8109
|
+
parentKind: null,
|
|
8110
|
+
level: "macro",
|
|
8111
|
+
category,
|
|
8112
|
+
color,
|
|
8113
|
+
iconId,
|
|
8114
|
+
labelKey: `eventKind.${kind}`,
|
|
8115
|
+
label
|
|
8116
|
+
});
|
|
8117
|
+
}
|
|
8118
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8119
|
+
entries.set(kind, {
|
|
8120
|
+
kind,
|
|
8121
|
+
parentKind,
|
|
8122
|
+
level: "sub",
|
|
8123
|
+
category,
|
|
8124
|
+
color,
|
|
8125
|
+
iconId,
|
|
8126
|
+
labelKey: `eventKind.${kind}`,
|
|
8127
|
+
label
|
|
8128
|
+
});
|
|
8129
|
+
}
|
|
8130
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8131
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8132
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8133
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8134
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8135
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8136
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8137
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8138
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8139
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8140
|
+
if (entries.has(cocoClass)) continue;
|
|
8141
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8142
|
+
}
|
|
8143
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8144
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8145
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8146
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8147
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8148
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8149
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8150
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8151
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8152
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8153
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8154
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8155
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8156
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8157
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8158
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8159
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8160
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8161
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8162
|
+
const kind = `audio-${l.id}`;
|
|
8163
|
+
if (entries.has(kind)) continue;
|
|
8164
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8165
|
+
}
|
|
8166
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8167
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8168
|
+
/**
|
|
7840
8169
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7841
8170
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7842
8171
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15786,17 +16115,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15786
16115
|
"audio",
|
|
15787
16116
|
"detection",
|
|
15788
16117
|
"sensor",
|
|
16118
|
+
"control",
|
|
15789
16119
|
"custom",
|
|
15790
16120
|
"package"
|
|
15791
16121
|
]);
|
|
16122
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16123
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15792
16124
|
var EventKindDescriptorSchema = object({
|
|
15793
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16125
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15794
16126
|
kind: string(),
|
|
16127
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16128
|
+
labelKey: string(),
|
|
16129
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15795
16130
|
label: string(),
|
|
15796
16131
|
/** Hex color for timeline/legend rendering. */
|
|
15797
16132
|
color: string(),
|
|
16133
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16134
|
+
iconId: string(),
|
|
16135
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15798
16136
|
icon: EventKindIconSchema,
|
|
15799
16137
|
category: EventKindCategorySchema,
|
|
16138
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16139
|
+
parentKind: string().nullable(),
|
|
16140
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16141
|
+
level: EventKindLevelSchema,
|
|
15800
16142
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15801
16143
|
* itself; for sensor kinds the LINKED source device. */
|
|
15802
16144
|
source: object({
|
|
@@ -15869,11 +16211,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15869
16211
|
firstAt: number(),
|
|
15870
16212
|
lastAt: number()
|
|
15871
16213
|
});
|
|
16214
|
+
/**
|
|
16215
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16216
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16217
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16218
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16219
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16220
|
+
*/
|
|
16221
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15872
16222
|
var TrackSchema = object({
|
|
15873
16223
|
trackId: string(),
|
|
15874
16224
|
deviceId: number(),
|
|
15875
16225
|
className: string(),
|
|
15876
16226
|
label: string().optional(),
|
|
16227
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16228
|
+
source: TrackSourceSchema.optional(),
|
|
15877
16229
|
firstSeen: number(),
|
|
15878
16230
|
lastSeen: number(),
|
|
15879
16231
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16128,6 +16480,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16128
16480
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16129
16481
|
embeddings: number().int()
|
|
16130
16482
|
});
|
|
16483
|
+
/** Event-store footprint for one camera. */
|
|
16484
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16485
|
+
deviceId: number(),
|
|
16486
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16487
|
+
rows: number().int(),
|
|
16488
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16489
|
+
bytes: number().int()
|
|
16490
|
+
});
|
|
16491
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16492
|
+
var EventStoreFootprintSchema = object({
|
|
16493
|
+
totalRows: number().int(),
|
|
16494
|
+
totalBytes: number().int(),
|
|
16495
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16496
|
+
});
|
|
16497
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16498
|
+
var EventPruneCountsSchema = object({
|
|
16499
|
+
motion: number().int(),
|
|
16500
|
+
object: number().int(),
|
|
16501
|
+
audio: number().int()
|
|
16502
|
+
});
|
|
16131
16503
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16132
16504
|
deviceId: number(),
|
|
16133
16505
|
trackId: string()
|
|
@@ -16191,6 +16563,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16191
16563
|
}), {
|
|
16192
16564
|
kind: "mutation",
|
|
16193
16565
|
auth: "admin"
|
|
16566
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16567
|
+
kind: "query",
|
|
16568
|
+
auth: "admin"
|
|
16569
|
+
}), method(object({
|
|
16570
|
+
olderThanMs: number(),
|
|
16571
|
+
reason: OpsLogReasonSchema.optional()
|
|
16572
|
+
}), EventPruneCountsSchema, {
|
|
16573
|
+
kind: "mutation",
|
|
16574
|
+
auth: "admin"
|
|
16575
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16576
|
+
kind: "mutation",
|
|
16577
|
+
auth: "admin"
|
|
16578
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16579
|
+
kind: "query",
|
|
16580
|
+
auth: "admin"
|
|
16194
16581
|
}), method(object({
|
|
16195
16582
|
eventId: string(),
|
|
16196
16583
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16215,6 +16602,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16215
16602
|
eventId: string(),
|
|
16216
16603
|
timestamp: number()
|
|
16217
16604
|
});
|
|
16605
|
+
/**
|
|
16606
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16607
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16608
|
+
* caps into per-camera event-kind descriptors.
|
|
16609
|
+
*
|
|
16610
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16611
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16612
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16613
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16614
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16615
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16616
|
+
* eventful cap is missing.
|
|
16617
|
+
*/
|
|
16618
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16619
|
+
var LEGACY_ICON = {
|
|
16620
|
+
motion: "motion",
|
|
16621
|
+
audio: "audio",
|
|
16622
|
+
person: "person",
|
|
16623
|
+
vehicle: "vehicle",
|
|
16624
|
+
animal: "animal",
|
|
16625
|
+
package: "package",
|
|
16626
|
+
door: "door",
|
|
16627
|
+
pir: "pir",
|
|
16628
|
+
smoke: "smoke",
|
|
16629
|
+
water: "water",
|
|
16630
|
+
button: "button",
|
|
16631
|
+
generic: "generic",
|
|
16632
|
+
gas: "smoke",
|
|
16633
|
+
vibration: "generic",
|
|
16634
|
+
tamper: "generic",
|
|
16635
|
+
presence: "person",
|
|
16636
|
+
lock: "generic",
|
|
16637
|
+
siren: "generic",
|
|
16638
|
+
switch: "generic",
|
|
16639
|
+
doorbell: "button"
|
|
16640
|
+
};
|
|
16641
|
+
function legacyIcon(iconId) {
|
|
16642
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16643
|
+
}
|
|
16644
|
+
/**
|
|
16645
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16646
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16647
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16648
|
+
*/
|
|
16649
|
+
var CAP_TO_KIND = {
|
|
16650
|
+
contact: "contact",
|
|
16651
|
+
motion: "motion-sensor",
|
|
16652
|
+
smoke: "smoke",
|
|
16653
|
+
flood: "flood",
|
|
16654
|
+
gas: "gas",
|
|
16655
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16656
|
+
vibration: "vibration",
|
|
16657
|
+
tamper: "tamper",
|
|
16658
|
+
presence: "presence",
|
|
16659
|
+
"enum-sensor": "enum-sensor",
|
|
16660
|
+
"event-emitter": "device-event",
|
|
16661
|
+
"lock-control": "lock",
|
|
16662
|
+
switch: "switch",
|
|
16663
|
+
button: "button",
|
|
16664
|
+
doorbell: "doorbell"
|
|
16665
|
+
};
|
|
16666
|
+
function buildDescriptor(capName, kind) {
|
|
16667
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16668
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16669
|
+
return {
|
|
16670
|
+
...t,
|
|
16671
|
+
icon: legacyIcon(t.iconId)
|
|
16672
|
+
};
|
|
16673
|
+
}
|
|
16674
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16218
16675
|
var CameraPipelineConfigSchema = object({
|
|
16219
16676
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16220
16677
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19447,13 +19904,29 @@ method(object({
|
|
|
19447
19904
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19448
19905
|
kind: "mutation",
|
|
19449
19906
|
auth: "admin"
|
|
19450
|
-
}), method(object({
|
|
19907
|
+
}), method(object({
|
|
19908
|
+
deviceId: number(),
|
|
19909
|
+
reason: OpsLogReasonSchema.optional()
|
|
19910
|
+
}), object({
|
|
19451
19911
|
floorMs: number().nullable(),
|
|
19452
19912
|
deletedBuckets: number().int(),
|
|
19453
19913
|
reclaimedBytes: number().int()
|
|
19454
19914
|
}), {
|
|
19455
19915
|
kind: "mutation",
|
|
19456
19916
|
auth: "admin"
|
|
19917
|
+
}), method(object({
|
|
19918
|
+
deviceId: number(),
|
|
19919
|
+
fromMs: number().optional(),
|
|
19920
|
+
toMs: number().optional()
|
|
19921
|
+
}), object({
|
|
19922
|
+
deletedBuckets: number().int(),
|
|
19923
|
+
reclaimedBytes: number().int()
|
|
19924
|
+
}), {
|
|
19925
|
+
kind: "mutation",
|
|
19926
|
+
auth: "admin"
|
|
19927
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19928
|
+
kind: "query",
|
|
19929
|
+
auth: "admin"
|
|
19457
19930
|
});
|
|
19458
19931
|
/**
|
|
19459
19932
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22575,6 +23048,12 @@ Object.freeze({
|
|
|
22575
23048
|
addonId: null,
|
|
22576
23049
|
access: "delete"
|
|
22577
23050
|
},
|
|
23051
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23052
|
+
capName: "pipeline-analytics",
|
|
23053
|
+
capScope: "device",
|
|
23054
|
+
addonId: null,
|
|
23055
|
+
access: "delete"
|
|
23056
|
+
},
|
|
22578
23057
|
"pipelineAnalytics.deleteTracks": {
|
|
22579
23058
|
capName: "pipeline-analytics",
|
|
22580
23059
|
capScope: "device",
|
|
@@ -22605,6 +23084,12 @@ Object.freeze({
|
|
|
22605
23084
|
addonId: null,
|
|
22606
23085
|
access: "view"
|
|
22607
23086
|
},
|
|
23087
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23088
|
+
capName: "pipeline-analytics",
|
|
23089
|
+
capScope: "device",
|
|
23090
|
+
addonId: null,
|
|
23091
|
+
access: "view"
|
|
23092
|
+
},
|
|
22608
23093
|
"pipelineAnalytics.getKeyEvents": {
|
|
22609
23094
|
capName: "pipeline-analytics",
|
|
22610
23095
|
capScope: "device",
|
|
@@ -22647,6 +23132,12 @@ Object.freeze({
|
|
|
22647
23132
|
addonId: null,
|
|
22648
23133
|
access: "view"
|
|
22649
23134
|
},
|
|
23135
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23136
|
+
capName: "pipeline-analytics",
|
|
23137
|
+
capScope: "device",
|
|
23138
|
+
addonId: null,
|
|
23139
|
+
access: "view"
|
|
23140
|
+
},
|
|
22650
23141
|
"pipelineAnalytics.listRecentTracks": {
|
|
22651
23142
|
capName: "pipeline-analytics",
|
|
22652
23143
|
capScope: "device",
|
|
@@ -22659,6 +23150,12 @@ Object.freeze({
|
|
|
22659
23150
|
addonId: null,
|
|
22660
23151
|
access: "view"
|
|
22661
23152
|
},
|
|
23153
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23154
|
+
capName: "pipeline-analytics",
|
|
23155
|
+
capScope: "device",
|
|
23156
|
+
addonId: null,
|
|
23157
|
+
access: "create"
|
|
23158
|
+
},
|
|
22662
23159
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22663
23160
|
capName: "pipeline-analytics",
|
|
22664
23161
|
capScope: "device",
|
|
@@ -23421,6 +23918,12 @@ Object.freeze({
|
|
|
23421
23918
|
addonId: null,
|
|
23422
23919
|
access: "create"
|
|
23423
23920
|
},
|
|
23921
|
+
"recording.deleteFootprint": {
|
|
23922
|
+
capName: "recording",
|
|
23923
|
+
capScope: "system",
|
|
23924
|
+
addonId: null,
|
|
23925
|
+
access: "delete"
|
|
23926
|
+
},
|
|
23424
23927
|
"recording.getAvailability": {
|
|
23425
23928
|
capName: "recording",
|
|
23426
23929
|
capScope: "system",
|
|
@@ -23451,6 +23954,12 @@ Object.freeze({
|
|
|
23451
23954
|
addonId: null,
|
|
23452
23955
|
access: "view"
|
|
23453
23956
|
},
|
|
23957
|
+
"recording.listOpsLog": {
|
|
23958
|
+
capName: "recording",
|
|
23959
|
+
capScope: "system",
|
|
23960
|
+
addonId: null,
|
|
23961
|
+
access: "view"
|
|
23962
|
+
},
|
|
23454
23963
|
"recording.locateSegment": {
|
|
23455
23964
|
capName: "recording",
|
|
23456
23965
|
capScope: "system",
|
|
@@ -7327,6 +7327,62 @@ var RecordingConfigSchema = object({
|
|
|
7327
7327
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7328
7328
|
});
|
|
7329
7329
|
/**
|
|
7330
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7331
|
+
* recordings and events management surfaces.
|
|
7332
|
+
*
|
|
7333
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7334
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7335
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7336
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7337
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7338
|
+
* never fail the operation it records.
|
|
7339
|
+
*/
|
|
7340
|
+
/** Which management domain the operation belongs to. */
|
|
7341
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7342
|
+
/** The kind of management operation performed. */
|
|
7343
|
+
var OpsLogOpSchema = _enum([
|
|
7344
|
+
"prune",
|
|
7345
|
+
"manual-delete",
|
|
7346
|
+
"rescan",
|
|
7347
|
+
"retention-run"
|
|
7348
|
+
]);
|
|
7349
|
+
/** Why the operation ran. */
|
|
7350
|
+
var OpsLogReasonSchema = _enum([
|
|
7351
|
+
"retention",
|
|
7352
|
+
"quota",
|
|
7353
|
+
"manual",
|
|
7354
|
+
"operator"
|
|
7355
|
+
]);
|
|
7356
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7357
|
+
var OpsLogEntrySchema = object({
|
|
7358
|
+
/** Unique row id. */
|
|
7359
|
+
id: string(),
|
|
7360
|
+
/** Epoch ms the operation completed. */
|
|
7361
|
+
at: number(),
|
|
7362
|
+
domain: OpsLogDomainSchema,
|
|
7363
|
+
op: OpsLogOpSchema,
|
|
7364
|
+
reason: OpsLogReasonSchema,
|
|
7365
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7366
|
+
deviceId: number().nullable(),
|
|
7367
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7368
|
+
nodeId: string(),
|
|
7369
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7370
|
+
itemsAffected: number(),
|
|
7371
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7372
|
+
bytesReclaimed: number(),
|
|
7373
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7374
|
+
detail: string().nullable(),
|
|
7375
|
+
/** Who/what triggered the op. */
|
|
7376
|
+
actor: string()
|
|
7377
|
+
});
|
|
7378
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7379
|
+
var OpsLogQueryInputSchema = object({
|
|
7380
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7381
|
+
deviceId: number().optional(),
|
|
7382
|
+
/** Max rows returned, newest-first. */
|
|
7383
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7384
|
+
});
|
|
7385
|
+
/**
|
|
7330
7386
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7331
7387
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7332
7388
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7570,6 +7626,160 @@ var EncodeProfileSchema = object({
|
|
|
7570
7626
|
*/
|
|
7571
7627
|
outputArgs: array(string()).optional()
|
|
7572
7628
|
});
|
|
7629
|
+
var COCO_TO_MACRO = {
|
|
7630
|
+
mapping: {
|
|
7631
|
+
person: "person",
|
|
7632
|
+
bicycle: "vehicle",
|
|
7633
|
+
car: "vehicle",
|
|
7634
|
+
motorcycle: "vehicle",
|
|
7635
|
+
airplane: "vehicle",
|
|
7636
|
+
bus: "vehicle",
|
|
7637
|
+
train: "vehicle",
|
|
7638
|
+
truck: "vehicle",
|
|
7639
|
+
boat: "vehicle",
|
|
7640
|
+
bird: "animal",
|
|
7641
|
+
cat: "animal",
|
|
7642
|
+
dog: "animal",
|
|
7643
|
+
horse: "animal",
|
|
7644
|
+
sheep: "animal",
|
|
7645
|
+
cow: "animal",
|
|
7646
|
+
elephant: "animal",
|
|
7647
|
+
bear: "animal",
|
|
7648
|
+
zebra: "animal",
|
|
7649
|
+
giraffe: "animal",
|
|
7650
|
+
suitcase: "package",
|
|
7651
|
+
backpack: "package",
|
|
7652
|
+
handbag: "package"
|
|
7653
|
+
},
|
|
7654
|
+
preserveOriginal: false
|
|
7655
|
+
};
|
|
7656
|
+
var AUDIO_MACRO_LABELS = [
|
|
7657
|
+
{
|
|
7658
|
+
id: "speech",
|
|
7659
|
+
name: "Speech",
|
|
7660
|
+
icon: "🗣️"
|
|
7661
|
+
},
|
|
7662
|
+
{
|
|
7663
|
+
id: "scream",
|
|
7664
|
+
name: "Scream / Shout",
|
|
7665
|
+
icon: "😱"
|
|
7666
|
+
},
|
|
7667
|
+
{
|
|
7668
|
+
id: "crying",
|
|
7669
|
+
name: "Crying / Baby",
|
|
7670
|
+
icon: "😢"
|
|
7671
|
+
},
|
|
7672
|
+
{
|
|
7673
|
+
id: "laughter",
|
|
7674
|
+
name: "Laughter",
|
|
7675
|
+
icon: "😂"
|
|
7676
|
+
},
|
|
7677
|
+
{
|
|
7678
|
+
id: "music",
|
|
7679
|
+
name: "Music",
|
|
7680
|
+
icon: "🎵"
|
|
7681
|
+
},
|
|
7682
|
+
{
|
|
7683
|
+
id: "dog",
|
|
7684
|
+
name: "Dog",
|
|
7685
|
+
icon: "🐕"
|
|
7686
|
+
},
|
|
7687
|
+
{
|
|
7688
|
+
id: "cat",
|
|
7689
|
+
name: "Cat",
|
|
7690
|
+
icon: "🐈"
|
|
7691
|
+
},
|
|
7692
|
+
{
|
|
7693
|
+
id: "bird",
|
|
7694
|
+
name: "Bird",
|
|
7695
|
+
icon: "🐦"
|
|
7696
|
+
},
|
|
7697
|
+
{
|
|
7698
|
+
id: "animal",
|
|
7699
|
+
name: "Animal (other)",
|
|
7700
|
+
icon: "🐾"
|
|
7701
|
+
},
|
|
7702
|
+
{
|
|
7703
|
+
id: "alarm",
|
|
7704
|
+
name: "Alarm / Siren",
|
|
7705
|
+
icon: "🚨"
|
|
7706
|
+
},
|
|
7707
|
+
{
|
|
7708
|
+
id: "doorbell",
|
|
7709
|
+
name: "Doorbell / Knock",
|
|
7710
|
+
icon: "🔔"
|
|
7711
|
+
},
|
|
7712
|
+
{
|
|
7713
|
+
id: "glass_breaking",
|
|
7714
|
+
name: "Glass Breaking",
|
|
7715
|
+
icon: "💥"
|
|
7716
|
+
},
|
|
7717
|
+
{
|
|
7718
|
+
id: "gunshot",
|
|
7719
|
+
name: "Gunshot / Explosion",
|
|
7720
|
+
icon: "💣"
|
|
7721
|
+
},
|
|
7722
|
+
{
|
|
7723
|
+
id: "vehicle",
|
|
7724
|
+
name: "Vehicle",
|
|
7725
|
+
icon: "🚗"
|
|
7726
|
+
},
|
|
7727
|
+
{
|
|
7728
|
+
id: "siren",
|
|
7729
|
+
name: "Emergency Siren",
|
|
7730
|
+
icon: "🚑"
|
|
7731
|
+
},
|
|
7732
|
+
{
|
|
7733
|
+
id: "fire",
|
|
7734
|
+
name: "Fire / Smoke",
|
|
7735
|
+
icon: "🔥"
|
|
7736
|
+
},
|
|
7737
|
+
{
|
|
7738
|
+
id: "water",
|
|
7739
|
+
name: "Water",
|
|
7740
|
+
icon: "💧"
|
|
7741
|
+
},
|
|
7742
|
+
{
|
|
7743
|
+
id: "wind",
|
|
7744
|
+
name: "Wind / Weather",
|
|
7745
|
+
icon: "🌬️"
|
|
7746
|
+
},
|
|
7747
|
+
{
|
|
7748
|
+
id: "door",
|
|
7749
|
+
name: "Door",
|
|
7750
|
+
icon: "🚪"
|
|
7751
|
+
},
|
|
7752
|
+
{
|
|
7753
|
+
id: "footsteps",
|
|
7754
|
+
name: "Footsteps",
|
|
7755
|
+
icon: "👣"
|
|
7756
|
+
},
|
|
7757
|
+
{
|
|
7758
|
+
id: "crowd",
|
|
7759
|
+
name: "Crowd / Chatter",
|
|
7760
|
+
icon: "👥"
|
|
7761
|
+
},
|
|
7762
|
+
{
|
|
7763
|
+
id: "telephone",
|
|
7764
|
+
name: "Telephone",
|
|
7765
|
+
icon: "📞"
|
|
7766
|
+
},
|
|
7767
|
+
{
|
|
7768
|
+
id: "engine",
|
|
7769
|
+
name: "Engine / Motor",
|
|
7770
|
+
icon: "⚙️"
|
|
7771
|
+
},
|
|
7772
|
+
{
|
|
7773
|
+
id: "tools",
|
|
7774
|
+
name: "Tools / Construction",
|
|
7775
|
+
icon: "🔨"
|
|
7776
|
+
},
|
|
7777
|
+
{
|
|
7778
|
+
id: "silence",
|
|
7779
|
+
name: "Silence",
|
|
7780
|
+
icon: "🤫"
|
|
7781
|
+
}
|
|
7782
|
+
];
|
|
7573
7783
|
var YAMNET_TO_MACRO = {
|
|
7574
7784
|
mapping: {
|
|
7575
7785
|
Speech: "speech",
|
|
@@ -7836,6 +8046,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7836
8046
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7837
8047
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7838
8048
|
/**
|
|
8049
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8050
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8051
|
+
* icon }`.
|
|
8052
|
+
*
|
|
8053
|
+
* This dictionary folds together what used to be scattered across four
|
|
8054
|
+
* copies:
|
|
8055
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8056
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8057
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8058
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8059
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8060
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8061
|
+
*
|
|
8062
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8063
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8064
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8065
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8066
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8067
|
+
*
|
|
8068
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8069
|
+
*/
|
|
8070
|
+
var TAXONOMY_COLORS = {
|
|
8071
|
+
motion: "#f59e0b",
|
|
8072
|
+
audio: "#06b6d4",
|
|
8073
|
+
person: "#22c55e",
|
|
8074
|
+
vehicle: "#3b82f6",
|
|
8075
|
+
animal: "#f97316",
|
|
8076
|
+
package: "#a855f7",
|
|
8077
|
+
sensor: "#8b5cf6",
|
|
8078
|
+
control: "#10b981",
|
|
8079
|
+
genericDetection: "#64748b"
|
|
8080
|
+
};
|
|
8081
|
+
var DETECTION_SUB_COLORS = {
|
|
8082
|
+
car: "#f59e0b",
|
|
8083
|
+
truck: "#d97706",
|
|
8084
|
+
bus: "#b45309",
|
|
8085
|
+
motorcycle: "#eab308",
|
|
8086
|
+
bicycle: "#ca8a04",
|
|
8087
|
+
airplane: "#60a5fa",
|
|
8088
|
+
boat: "#2563eb",
|
|
8089
|
+
train: "#1d4ed8",
|
|
8090
|
+
bird: "#14b8a6",
|
|
8091
|
+
dog: "#84cc16",
|
|
8092
|
+
cat: "#f97316",
|
|
8093
|
+
horse: "#a16207",
|
|
8094
|
+
sheep: "#a3a3a3",
|
|
8095
|
+
cow: "#78716c",
|
|
8096
|
+
elephant: "#6b7280",
|
|
8097
|
+
bear: "#7c2d12",
|
|
8098
|
+
zebra: "#404040",
|
|
8099
|
+
giraffe: "#d4a373"
|
|
8100
|
+
};
|
|
8101
|
+
function titleCase(id) {
|
|
8102
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8103
|
+
}
|
|
8104
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8105
|
+
function macro(kind, category, color, iconId, label) {
|
|
8106
|
+
entries.set(kind, {
|
|
8107
|
+
kind,
|
|
8108
|
+
parentKind: null,
|
|
8109
|
+
level: "macro",
|
|
8110
|
+
category,
|
|
8111
|
+
color,
|
|
8112
|
+
iconId,
|
|
8113
|
+
labelKey: `eventKind.${kind}`,
|
|
8114
|
+
label
|
|
8115
|
+
});
|
|
8116
|
+
}
|
|
8117
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8118
|
+
entries.set(kind, {
|
|
8119
|
+
kind,
|
|
8120
|
+
parentKind,
|
|
8121
|
+
level: "sub",
|
|
8122
|
+
category,
|
|
8123
|
+
color,
|
|
8124
|
+
iconId,
|
|
8125
|
+
labelKey: `eventKind.${kind}`,
|
|
8126
|
+
label
|
|
8127
|
+
});
|
|
8128
|
+
}
|
|
8129
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8130
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8131
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8132
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8133
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8134
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8135
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8136
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8137
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8138
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8139
|
+
if (entries.has(cocoClass)) continue;
|
|
8140
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8141
|
+
}
|
|
8142
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8143
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8144
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8145
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8146
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8147
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8148
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8149
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8150
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8151
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8152
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8153
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8154
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8155
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8156
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8157
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8158
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8159
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8160
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8161
|
+
const kind = `audio-${l.id}`;
|
|
8162
|
+
if (entries.has(kind)) continue;
|
|
8163
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8164
|
+
}
|
|
8165
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8166
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8167
|
+
/**
|
|
7839
8168
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7840
8169
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7841
8170
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15785,17 +16114,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15785
16114
|
"audio",
|
|
15786
16115
|
"detection",
|
|
15787
16116
|
"sensor",
|
|
16117
|
+
"control",
|
|
15788
16118
|
"custom",
|
|
15789
16119
|
"package"
|
|
15790
16120
|
]);
|
|
16121
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16122
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15791
16123
|
var EventKindDescriptorSchema = object({
|
|
15792
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16124
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15793
16125
|
kind: string(),
|
|
16126
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16127
|
+
labelKey: string(),
|
|
16128
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15794
16129
|
label: string(),
|
|
15795
16130
|
/** Hex color for timeline/legend rendering. */
|
|
15796
16131
|
color: string(),
|
|
16132
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16133
|
+
iconId: string(),
|
|
16134
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15797
16135
|
icon: EventKindIconSchema,
|
|
15798
16136
|
category: EventKindCategorySchema,
|
|
16137
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16138
|
+
parentKind: string().nullable(),
|
|
16139
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16140
|
+
level: EventKindLevelSchema,
|
|
15799
16141
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15800
16142
|
* itself; for sensor kinds the LINKED source device. */
|
|
15801
16143
|
source: object({
|
|
@@ -15868,11 +16210,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15868
16210
|
firstAt: number(),
|
|
15869
16211
|
lastAt: number()
|
|
15870
16212
|
});
|
|
16213
|
+
/**
|
|
16214
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16215
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16216
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16217
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16218
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16219
|
+
*/
|
|
16220
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15871
16221
|
var TrackSchema = object({
|
|
15872
16222
|
trackId: string(),
|
|
15873
16223
|
deviceId: number(),
|
|
15874
16224
|
className: string(),
|
|
15875
16225
|
label: string().optional(),
|
|
16226
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16227
|
+
source: TrackSourceSchema.optional(),
|
|
15876
16228
|
firstSeen: number(),
|
|
15877
16229
|
lastSeen: number(),
|
|
15878
16230
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16127,6 +16479,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16127
16479
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16128
16480
|
embeddings: number().int()
|
|
16129
16481
|
});
|
|
16482
|
+
/** Event-store footprint for one camera. */
|
|
16483
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16484
|
+
deviceId: number(),
|
|
16485
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16486
|
+
rows: number().int(),
|
|
16487
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16488
|
+
bytes: number().int()
|
|
16489
|
+
});
|
|
16490
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16491
|
+
var EventStoreFootprintSchema = object({
|
|
16492
|
+
totalRows: number().int(),
|
|
16493
|
+
totalBytes: number().int(),
|
|
16494
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16495
|
+
});
|
|
16496
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16497
|
+
var EventPruneCountsSchema = object({
|
|
16498
|
+
motion: number().int(),
|
|
16499
|
+
object: number().int(),
|
|
16500
|
+
audio: number().int()
|
|
16501
|
+
});
|
|
16130
16502
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16131
16503
|
deviceId: number(),
|
|
16132
16504
|
trackId: string()
|
|
@@ -16190,6 +16562,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16190
16562
|
}), {
|
|
16191
16563
|
kind: "mutation",
|
|
16192
16564
|
auth: "admin"
|
|
16565
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16566
|
+
kind: "query",
|
|
16567
|
+
auth: "admin"
|
|
16568
|
+
}), method(object({
|
|
16569
|
+
olderThanMs: number(),
|
|
16570
|
+
reason: OpsLogReasonSchema.optional()
|
|
16571
|
+
}), EventPruneCountsSchema, {
|
|
16572
|
+
kind: "mutation",
|
|
16573
|
+
auth: "admin"
|
|
16574
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16575
|
+
kind: "mutation",
|
|
16576
|
+
auth: "admin"
|
|
16577
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16578
|
+
kind: "query",
|
|
16579
|
+
auth: "admin"
|
|
16193
16580
|
}), method(object({
|
|
16194
16581
|
eventId: string(),
|
|
16195
16582
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16214,6 +16601,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16214
16601
|
eventId: string(),
|
|
16215
16602
|
timestamp: number()
|
|
16216
16603
|
});
|
|
16604
|
+
/**
|
|
16605
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16606
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16607
|
+
* caps into per-camera event-kind descriptors.
|
|
16608
|
+
*
|
|
16609
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16610
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16611
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16612
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16613
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16614
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16615
|
+
* eventful cap is missing.
|
|
16616
|
+
*/
|
|
16617
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16618
|
+
var LEGACY_ICON = {
|
|
16619
|
+
motion: "motion",
|
|
16620
|
+
audio: "audio",
|
|
16621
|
+
person: "person",
|
|
16622
|
+
vehicle: "vehicle",
|
|
16623
|
+
animal: "animal",
|
|
16624
|
+
package: "package",
|
|
16625
|
+
door: "door",
|
|
16626
|
+
pir: "pir",
|
|
16627
|
+
smoke: "smoke",
|
|
16628
|
+
water: "water",
|
|
16629
|
+
button: "button",
|
|
16630
|
+
generic: "generic",
|
|
16631
|
+
gas: "smoke",
|
|
16632
|
+
vibration: "generic",
|
|
16633
|
+
tamper: "generic",
|
|
16634
|
+
presence: "person",
|
|
16635
|
+
lock: "generic",
|
|
16636
|
+
siren: "generic",
|
|
16637
|
+
switch: "generic",
|
|
16638
|
+
doorbell: "button"
|
|
16639
|
+
};
|
|
16640
|
+
function legacyIcon(iconId) {
|
|
16641
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16642
|
+
}
|
|
16643
|
+
/**
|
|
16644
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16645
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16646
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16647
|
+
*/
|
|
16648
|
+
var CAP_TO_KIND = {
|
|
16649
|
+
contact: "contact",
|
|
16650
|
+
motion: "motion-sensor",
|
|
16651
|
+
smoke: "smoke",
|
|
16652
|
+
flood: "flood",
|
|
16653
|
+
gas: "gas",
|
|
16654
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16655
|
+
vibration: "vibration",
|
|
16656
|
+
tamper: "tamper",
|
|
16657
|
+
presence: "presence",
|
|
16658
|
+
"enum-sensor": "enum-sensor",
|
|
16659
|
+
"event-emitter": "device-event",
|
|
16660
|
+
"lock-control": "lock",
|
|
16661
|
+
switch: "switch",
|
|
16662
|
+
button: "button",
|
|
16663
|
+
doorbell: "doorbell"
|
|
16664
|
+
};
|
|
16665
|
+
function buildDescriptor(capName, kind) {
|
|
16666
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16667
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16668
|
+
return {
|
|
16669
|
+
...t,
|
|
16670
|
+
icon: legacyIcon(t.iconId)
|
|
16671
|
+
};
|
|
16672
|
+
}
|
|
16673
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16217
16674
|
var CameraPipelineConfigSchema = object({
|
|
16218
16675
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16219
16676
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19446,13 +19903,29 @@ method(object({
|
|
|
19446
19903
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19447
19904
|
kind: "mutation",
|
|
19448
19905
|
auth: "admin"
|
|
19449
|
-
}), method(object({
|
|
19906
|
+
}), method(object({
|
|
19907
|
+
deviceId: number(),
|
|
19908
|
+
reason: OpsLogReasonSchema.optional()
|
|
19909
|
+
}), object({
|
|
19450
19910
|
floorMs: number().nullable(),
|
|
19451
19911
|
deletedBuckets: number().int(),
|
|
19452
19912
|
reclaimedBytes: number().int()
|
|
19453
19913
|
}), {
|
|
19454
19914
|
kind: "mutation",
|
|
19455
19915
|
auth: "admin"
|
|
19916
|
+
}), method(object({
|
|
19917
|
+
deviceId: number(),
|
|
19918
|
+
fromMs: number().optional(),
|
|
19919
|
+
toMs: number().optional()
|
|
19920
|
+
}), object({
|
|
19921
|
+
deletedBuckets: number().int(),
|
|
19922
|
+
reclaimedBytes: number().int()
|
|
19923
|
+
}), {
|
|
19924
|
+
kind: "mutation",
|
|
19925
|
+
auth: "admin"
|
|
19926
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19927
|
+
kind: "query",
|
|
19928
|
+
auth: "admin"
|
|
19456
19929
|
});
|
|
19457
19930
|
/**
|
|
19458
19931
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22574,6 +23047,12 @@ Object.freeze({
|
|
|
22574
23047
|
addonId: null,
|
|
22575
23048
|
access: "delete"
|
|
22576
23049
|
},
|
|
23050
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23051
|
+
capName: "pipeline-analytics",
|
|
23052
|
+
capScope: "device",
|
|
23053
|
+
addonId: null,
|
|
23054
|
+
access: "delete"
|
|
23055
|
+
},
|
|
22577
23056
|
"pipelineAnalytics.deleteTracks": {
|
|
22578
23057
|
capName: "pipeline-analytics",
|
|
22579
23058
|
capScope: "device",
|
|
@@ -22604,6 +23083,12 @@ Object.freeze({
|
|
|
22604
23083
|
addonId: null,
|
|
22605
23084
|
access: "view"
|
|
22606
23085
|
},
|
|
23086
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23087
|
+
capName: "pipeline-analytics",
|
|
23088
|
+
capScope: "device",
|
|
23089
|
+
addonId: null,
|
|
23090
|
+
access: "view"
|
|
23091
|
+
},
|
|
22607
23092
|
"pipelineAnalytics.getKeyEvents": {
|
|
22608
23093
|
capName: "pipeline-analytics",
|
|
22609
23094
|
capScope: "device",
|
|
@@ -22646,6 +23131,12 @@ Object.freeze({
|
|
|
22646
23131
|
addonId: null,
|
|
22647
23132
|
access: "view"
|
|
22648
23133
|
},
|
|
23134
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23135
|
+
capName: "pipeline-analytics",
|
|
23136
|
+
capScope: "device",
|
|
23137
|
+
addonId: null,
|
|
23138
|
+
access: "view"
|
|
23139
|
+
},
|
|
22649
23140
|
"pipelineAnalytics.listRecentTracks": {
|
|
22650
23141
|
capName: "pipeline-analytics",
|
|
22651
23142
|
capScope: "device",
|
|
@@ -22658,6 +23149,12 @@ Object.freeze({
|
|
|
22658
23149
|
addonId: null,
|
|
22659
23150
|
access: "view"
|
|
22660
23151
|
},
|
|
23152
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23153
|
+
capName: "pipeline-analytics",
|
|
23154
|
+
capScope: "device",
|
|
23155
|
+
addonId: null,
|
|
23156
|
+
access: "create"
|
|
23157
|
+
},
|
|
22661
23158
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22662
23159
|
capName: "pipeline-analytics",
|
|
22663
23160
|
capScope: "device",
|
|
@@ -23420,6 +23917,12 @@ Object.freeze({
|
|
|
23420
23917
|
addonId: null,
|
|
23421
23918
|
access: "create"
|
|
23422
23919
|
},
|
|
23920
|
+
"recording.deleteFootprint": {
|
|
23921
|
+
capName: "recording",
|
|
23922
|
+
capScope: "system",
|
|
23923
|
+
addonId: null,
|
|
23924
|
+
access: "delete"
|
|
23925
|
+
},
|
|
23423
23926
|
"recording.getAvailability": {
|
|
23424
23927
|
capName: "recording",
|
|
23425
23928
|
capScope: "system",
|
|
@@ -23450,6 +23953,12 @@ Object.freeze({
|
|
|
23450
23953
|
addonId: null,
|
|
23451
23954
|
access: "view"
|
|
23452
23955
|
},
|
|
23956
|
+
"recording.listOpsLog": {
|
|
23957
|
+
capName: "recording",
|
|
23958
|
+
capScope: "system",
|
|
23959
|
+
addonId: null,
|
|
23960
|
+
access: "view"
|
|
23961
|
+
},
|
|
23453
23962
|
"recording.locateSegment": {
|
|
23454
23963
|
capName: "recording",
|
|
23455
23964
|
capScope: "system",
|