@camstack/addon-advanced-notifier 1.1.28 → 1.1.30
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 +516 -5
- package/dist/addon.mjs +516 -5
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -7332,6 +7332,62 @@ var RecordingConfigSchema = object({
|
|
|
7332
7332
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7333
7333
|
});
|
|
7334
7334
|
/**
|
|
7335
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7336
|
+
* recordings and events management surfaces.
|
|
7337
|
+
*
|
|
7338
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7339
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7340
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7341
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7342
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7343
|
+
* never fail the operation it records.
|
|
7344
|
+
*/
|
|
7345
|
+
/** Which management domain the operation belongs to. */
|
|
7346
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7347
|
+
/** The kind of management operation performed. */
|
|
7348
|
+
var OpsLogOpSchema = _enum([
|
|
7349
|
+
"prune",
|
|
7350
|
+
"manual-delete",
|
|
7351
|
+
"rescan",
|
|
7352
|
+
"retention-run"
|
|
7353
|
+
]);
|
|
7354
|
+
/** Why the operation ran. */
|
|
7355
|
+
var OpsLogReasonSchema = _enum([
|
|
7356
|
+
"retention",
|
|
7357
|
+
"quota",
|
|
7358
|
+
"manual",
|
|
7359
|
+
"operator"
|
|
7360
|
+
]);
|
|
7361
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7362
|
+
var OpsLogEntrySchema = object({
|
|
7363
|
+
/** Unique row id. */
|
|
7364
|
+
id: string(),
|
|
7365
|
+
/** Epoch ms the operation completed. */
|
|
7366
|
+
at: number(),
|
|
7367
|
+
domain: OpsLogDomainSchema,
|
|
7368
|
+
op: OpsLogOpSchema,
|
|
7369
|
+
reason: OpsLogReasonSchema,
|
|
7370
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7371
|
+
deviceId: number().nullable(),
|
|
7372
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7373
|
+
nodeId: string(),
|
|
7374
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7375
|
+
itemsAffected: number(),
|
|
7376
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7377
|
+
bytesReclaimed: number(),
|
|
7378
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7379
|
+
detail: string().nullable(),
|
|
7380
|
+
/** Who/what triggered the op. */
|
|
7381
|
+
actor: string()
|
|
7382
|
+
});
|
|
7383
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7384
|
+
var OpsLogQueryInputSchema = object({
|
|
7385
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7386
|
+
deviceId: number().optional(),
|
|
7387
|
+
/** Max rows returned, newest-first. */
|
|
7388
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7389
|
+
});
|
|
7390
|
+
/**
|
|
7335
7391
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7336
7392
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7337
7393
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7589,6 +7645,160 @@ function cosineSimilarity(a, b) {
|
|
|
7589
7645
|
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
7590
7646
|
return denom === 0 ? 0 : dotProduct / denom;
|
|
7591
7647
|
}
|
|
7648
|
+
var COCO_TO_MACRO = {
|
|
7649
|
+
mapping: {
|
|
7650
|
+
person: "person",
|
|
7651
|
+
bicycle: "vehicle",
|
|
7652
|
+
car: "vehicle",
|
|
7653
|
+
motorcycle: "vehicle",
|
|
7654
|
+
airplane: "vehicle",
|
|
7655
|
+
bus: "vehicle",
|
|
7656
|
+
train: "vehicle",
|
|
7657
|
+
truck: "vehicle",
|
|
7658
|
+
boat: "vehicle",
|
|
7659
|
+
bird: "animal",
|
|
7660
|
+
cat: "animal",
|
|
7661
|
+
dog: "animal",
|
|
7662
|
+
horse: "animal",
|
|
7663
|
+
sheep: "animal",
|
|
7664
|
+
cow: "animal",
|
|
7665
|
+
elephant: "animal",
|
|
7666
|
+
bear: "animal",
|
|
7667
|
+
zebra: "animal",
|
|
7668
|
+
giraffe: "animal",
|
|
7669
|
+
suitcase: "package",
|
|
7670
|
+
backpack: "package",
|
|
7671
|
+
handbag: "package"
|
|
7672
|
+
},
|
|
7673
|
+
preserveOriginal: false
|
|
7674
|
+
};
|
|
7675
|
+
var AUDIO_MACRO_LABELS = [
|
|
7676
|
+
{
|
|
7677
|
+
id: "speech",
|
|
7678
|
+
name: "Speech",
|
|
7679
|
+
icon: "🗣️"
|
|
7680
|
+
},
|
|
7681
|
+
{
|
|
7682
|
+
id: "scream",
|
|
7683
|
+
name: "Scream / Shout",
|
|
7684
|
+
icon: "😱"
|
|
7685
|
+
},
|
|
7686
|
+
{
|
|
7687
|
+
id: "crying",
|
|
7688
|
+
name: "Crying / Baby",
|
|
7689
|
+
icon: "😢"
|
|
7690
|
+
},
|
|
7691
|
+
{
|
|
7692
|
+
id: "laughter",
|
|
7693
|
+
name: "Laughter",
|
|
7694
|
+
icon: "😂"
|
|
7695
|
+
},
|
|
7696
|
+
{
|
|
7697
|
+
id: "music",
|
|
7698
|
+
name: "Music",
|
|
7699
|
+
icon: "🎵"
|
|
7700
|
+
},
|
|
7701
|
+
{
|
|
7702
|
+
id: "dog",
|
|
7703
|
+
name: "Dog",
|
|
7704
|
+
icon: "🐕"
|
|
7705
|
+
},
|
|
7706
|
+
{
|
|
7707
|
+
id: "cat",
|
|
7708
|
+
name: "Cat",
|
|
7709
|
+
icon: "🐈"
|
|
7710
|
+
},
|
|
7711
|
+
{
|
|
7712
|
+
id: "bird",
|
|
7713
|
+
name: "Bird",
|
|
7714
|
+
icon: "🐦"
|
|
7715
|
+
},
|
|
7716
|
+
{
|
|
7717
|
+
id: "animal",
|
|
7718
|
+
name: "Animal (other)",
|
|
7719
|
+
icon: "🐾"
|
|
7720
|
+
},
|
|
7721
|
+
{
|
|
7722
|
+
id: "alarm",
|
|
7723
|
+
name: "Alarm / Siren",
|
|
7724
|
+
icon: "🚨"
|
|
7725
|
+
},
|
|
7726
|
+
{
|
|
7727
|
+
id: "doorbell",
|
|
7728
|
+
name: "Doorbell / Knock",
|
|
7729
|
+
icon: "🔔"
|
|
7730
|
+
},
|
|
7731
|
+
{
|
|
7732
|
+
id: "glass_breaking",
|
|
7733
|
+
name: "Glass Breaking",
|
|
7734
|
+
icon: "💥"
|
|
7735
|
+
},
|
|
7736
|
+
{
|
|
7737
|
+
id: "gunshot",
|
|
7738
|
+
name: "Gunshot / Explosion",
|
|
7739
|
+
icon: "💣"
|
|
7740
|
+
},
|
|
7741
|
+
{
|
|
7742
|
+
id: "vehicle",
|
|
7743
|
+
name: "Vehicle",
|
|
7744
|
+
icon: "🚗"
|
|
7745
|
+
},
|
|
7746
|
+
{
|
|
7747
|
+
id: "siren",
|
|
7748
|
+
name: "Emergency Siren",
|
|
7749
|
+
icon: "🚑"
|
|
7750
|
+
},
|
|
7751
|
+
{
|
|
7752
|
+
id: "fire",
|
|
7753
|
+
name: "Fire / Smoke",
|
|
7754
|
+
icon: "🔥"
|
|
7755
|
+
},
|
|
7756
|
+
{
|
|
7757
|
+
id: "water",
|
|
7758
|
+
name: "Water",
|
|
7759
|
+
icon: "💧"
|
|
7760
|
+
},
|
|
7761
|
+
{
|
|
7762
|
+
id: "wind",
|
|
7763
|
+
name: "Wind / Weather",
|
|
7764
|
+
icon: "🌬️"
|
|
7765
|
+
},
|
|
7766
|
+
{
|
|
7767
|
+
id: "door",
|
|
7768
|
+
name: "Door",
|
|
7769
|
+
icon: "🚪"
|
|
7770
|
+
},
|
|
7771
|
+
{
|
|
7772
|
+
id: "footsteps",
|
|
7773
|
+
name: "Footsteps",
|
|
7774
|
+
icon: "👣"
|
|
7775
|
+
},
|
|
7776
|
+
{
|
|
7777
|
+
id: "crowd",
|
|
7778
|
+
name: "Crowd / Chatter",
|
|
7779
|
+
icon: "👥"
|
|
7780
|
+
},
|
|
7781
|
+
{
|
|
7782
|
+
id: "telephone",
|
|
7783
|
+
name: "Telephone",
|
|
7784
|
+
icon: "📞"
|
|
7785
|
+
},
|
|
7786
|
+
{
|
|
7787
|
+
id: "engine",
|
|
7788
|
+
name: "Engine / Motor",
|
|
7789
|
+
icon: "⚙️"
|
|
7790
|
+
},
|
|
7791
|
+
{
|
|
7792
|
+
id: "tools",
|
|
7793
|
+
name: "Tools / Construction",
|
|
7794
|
+
icon: "🔨"
|
|
7795
|
+
},
|
|
7796
|
+
{
|
|
7797
|
+
id: "silence",
|
|
7798
|
+
name: "Silence",
|
|
7799
|
+
icon: "🤫"
|
|
7800
|
+
}
|
|
7801
|
+
];
|
|
7592
7802
|
var YAMNET_TO_MACRO = {
|
|
7593
7803
|
mapping: {
|
|
7594
7804
|
Speech: "speech",
|
|
@@ -7855,6 +8065,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7855
8065
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7856
8066
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7857
8067
|
/**
|
|
8068
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8069
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8070
|
+
* icon }`.
|
|
8071
|
+
*
|
|
8072
|
+
* This dictionary folds together what used to be scattered across four
|
|
8073
|
+
* copies:
|
|
8074
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8075
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8076
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8077
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8078
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8079
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8080
|
+
*
|
|
8081
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8082
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8083
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8084
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8085
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8086
|
+
*
|
|
8087
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8088
|
+
*/
|
|
8089
|
+
var TAXONOMY_COLORS = {
|
|
8090
|
+
motion: "#f59e0b",
|
|
8091
|
+
audio: "#06b6d4",
|
|
8092
|
+
person: "#22c55e",
|
|
8093
|
+
vehicle: "#3b82f6",
|
|
8094
|
+
animal: "#f97316",
|
|
8095
|
+
package: "#a855f7",
|
|
8096
|
+
sensor: "#8b5cf6",
|
|
8097
|
+
control: "#10b981",
|
|
8098
|
+
genericDetection: "#64748b"
|
|
8099
|
+
};
|
|
8100
|
+
var DETECTION_SUB_COLORS = {
|
|
8101
|
+
car: "#f59e0b",
|
|
8102
|
+
truck: "#d97706",
|
|
8103
|
+
bus: "#b45309",
|
|
8104
|
+
motorcycle: "#eab308",
|
|
8105
|
+
bicycle: "#ca8a04",
|
|
8106
|
+
airplane: "#60a5fa",
|
|
8107
|
+
boat: "#2563eb",
|
|
8108
|
+
train: "#1d4ed8",
|
|
8109
|
+
bird: "#14b8a6",
|
|
8110
|
+
dog: "#84cc16",
|
|
8111
|
+
cat: "#f97316",
|
|
8112
|
+
horse: "#a16207",
|
|
8113
|
+
sheep: "#a3a3a3",
|
|
8114
|
+
cow: "#78716c",
|
|
8115
|
+
elephant: "#6b7280",
|
|
8116
|
+
bear: "#7c2d12",
|
|
8117
|
+
zebra: "#404040",
|
|
8118
|
+
giraffe: "#d4a373"
|
|
8119
|
+
};
|
|
8120
|
+
function titleCase(id) {
|
|
8121
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8122
|
+
}
|
|
8123
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8124
|
+
function macro(kind, category, color, iconId, label) {
|
|
8125
|
+
entries.set(kind, {
|
|
8126
|
+
kind,
|
|
8127
|
+
parentKind: null,
|
|
8128
|
+
level: "macro",
|
|
8129
|
+
category,
|
|
8130
|
+
color,
|
|
8131
|
+
iconId,
|
|
8132
|
+
labelKey: `eventKind.${kind}`,
|
|
8133
|
+
label
|
|
8134
|
+
});
|
|
8135
|
+
}
|
|
8136
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8137
|
+
entries.set(kind, {
|
|
8138
|
+
kind,
|
|
8139
|
+
parentKind,
|
|
8140
|
+
level: "sub",
|
|
8141
|
+
category,
|
|
8142
|
+
color,
|
|
8143
|
+
iconId,
|
|
8144
|
+
labelKey: `eventKind.${kind}`,
|
|
8145
|
+
label
|
|
8146
|
+
});
|
|
8147
|
+
}
|
|
8148
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8149
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8150
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8151
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8152
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8153
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8154
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8155
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8156
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8157
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8158
|
+
if (entries.has(cocoClass)) continue;
|
|
8159
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8160
|
+
}
|
|
8161
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8162
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8163
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8164
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8165
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8166
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8167
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8168
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8169
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8170
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8171
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8172
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8173
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8174
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8175
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8176
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8177
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8178
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8179
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8180
|
+
const kind = `audio-${l.id}`;
|
|
8181
|
+
if (entries.has(kind)) continue;
|
|
8182
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8183
|
+
}
|
|
8184
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8185
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8186
|
+
/**
|
|
7858
8187
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7859
8188
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7860
8189
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15830,17 +16159,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15830
16159
|
"audio",
|
|
15831
16160
|
"detection",
|
|
15832
16161
|
"sensor",
|
|
16162
|
+
"control",
|
|
15833
16163
|
"custom",
|
|
15834
16164
|
"package"
|
|
15835
16165
|
]);
|
|
16166
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16167
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15836
16168
|
var EventKindDescriptorSchema = object({
|
|
15837
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16169
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15838
16170
|
kind: string(),
|
|
16171
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16172
|
+
labelKey: string(),
|
|
16173
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15839
16174
|
label: string(),
|
|
15840
16175
|
/** Hex color for timeline/legend rendering. */
|
|
15841
16176
|
color: string(),
|
|
16177
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16178
|
+
iconId: string(),
|
|
16179
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15842
16180
|
icon: EventKindIconSchema,
|
|
15843
16181
|
category: EventKindCategorySchema,
|
|
16182
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16183
|
+
parentKind: string().nullable(),
|
|
16184
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16185
|
+
level: EventKindLevelSchema,
|
|
15844
16186
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15845
16187
|
* itself; for sensor kinds the LINKED source device. */
|
|
15846
16188
|
source: object({
|
|
@@ -15913,11 +16255,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15913
16255
|
firstAt: number(),
|
|
15914
16256
|
lastAt: number()
|
|
15915
16257
|
});
|
|
16258
|
+
/**
|
|
16259
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16260
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16261
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16262
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16263
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16264
|
+
*/
|
|
16265
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15916
16266
|
var TrackSchema = object({
|
|
15917
16267
|
trackId: string(),
|
|
15918
16268
|
deviceId: number(),
|
|
15919
16269
|
className: string(),
|
|
15920
16270
|
label: string().optional(),
|
|
16271
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16272
|
+
source: TrackSourceSchema.optional(),
|
|
15921
16273
|
firstSeen: number(),
|
|
15922
16274
|
lastSeen: number(),
|
|
15923
16275
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16172,6 +16524,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16172
16524
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16173
16525
|
embeddings: number().int()
|
|
16174
16526
|
});
|
|
16527
|
+
/** Event-store footprint for one camera. */
|
|
16528
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16529
|
+
deviceId: number(),
|
|
16530
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16531
|
+
rows: number().int(),
|
|
16532
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16533
|
+
bytes: number().int()
|
|
16534
|
+
});
|
|
16535
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16536
|
+
var EventStoreFootprintSchema = object({
|
|
16537
|
+
totalRows: number().int(),
|
|
16538
|
+
totalBytes: number().int(),
|
|
16539
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16540
|
+
});
|
|
16541
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16542
|
+
var EventPruneCountsSchema = object({
|
|
16543
|
+
motion: number().int(),
|
|
16544
|
+
object: number().int(),
|
|
16545
|
+
audio: number().int()
|
|
16546
|
+
});
|
|
16175
16547
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16176
16548
|
deviceId: number(),
|
|
16177
16549
|
trackId: string()
|
|
@@ -16235,6 +16607,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16235
16607
|
}), {
|
|
16236
16608
|
kind: "mutation",
|
|
16237
16609
|
auth: "admin"
|
|
16610
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16611
|
+
kind: "query",
|
|
16612
|
+
auth: "admin"
|
|
16613
|
+
}), method(object({
|
|
16614
|
+
olderThanMs: number(),
|
|
16615
|
+
reason: OpsLogReasonSchema.optional()
|
|
16616
|
+
}), EventPruneCountsSchema, {
|
|
16617
|
+
kind: "mutation",
|
|
16618
|
+
auth: "admin"
|
|
16619
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16620
|
+
kind: "mutation",
|
|
16621
|
+
auth: "admin"
|
|
16622
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16623
|
+
kind: "query",
|
|
16624
|
+
auth: "admin"
|
|
16238
16625
|
}), method(object({
|
|
16239
16626
|
eventId: string(),
|
|
16240
16627
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16259,6 +16646,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16259
16646
|
eventId: string(),
|
|
16260
16647
|
timestamp: number()
|
|
16261
16648
|
});
|
|
16649
|
+
/**
|
|
16650
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16651
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16652
|
+
* caps into per-camera event-kind descriptors.
|
|
16653
|
+
*
|
|
16654
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16655
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16656
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16657
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16658
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16659
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16660
|
+
* eventful cap is missing.
|
|
16661
|
+
*/
|
|
16662
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16663
|
+
var LEGACY_ICON = {
|
|
16664
|
+
motion: "motion",
|
|
16665
|
+
audio: "audio",
|
|
16666
|
+
person: "person",
|
|
16667
|
+
vehicle: "vehicle",
|
|
16668
|
+
animal: "animal",
|
|
16669
|
+
package: "package",
|
|
16670
|
+
door: "door",
|
|
16671
|
+
pir: "pir",
|
|
16672
|
+
smoke: "smoke",
|
|
16673
|
+
water: "water",
|
|
16674
|
+
button: "button",
|
|
16675
|
+
generic: "generic",
|
|
16676
|
+
gas: "smoke",
|
|
16677
|
+
vibration: "generic",
|
|
16678
|
+
tamper: "generic",
|
|
16679
|
+
presence: "person",
|
|
16680
|
+
lock: "generic",
|
|
16681
|
+
siren: "generic",
|
|
16682
|
+
switch: "generic",
|
|
16683
|
+
doorbell: "button"
|
|
16684
|
+
};
|
|
16685
|
+
function legacyIcon(iconId) {
|
|
16686
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16687
|
+
}
|
|
16688
|
+
/**
|
|
16689
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16690
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16691
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16692
|
+
*/
|
|
16693
|
+
var CAP_TO_KIND = {
|
|
16694
|
+
contact: "contact",
|
|
16695
|
+
motion: "motion-sensor",
|
|
16696
|
+
smoke: "smoke",
|
|
16697
|
+
flood: "flood",
|
|
16698
|
+
gas: "gas",
|
|
16699
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16700
|
+
vibration: "vibration",
|
|
16701
|
+
tamper: "tamper",
|
|
16702
|
+
presence: "presence",
|
|
16703
|
+
"enum-sensor": "enum-sensor",
|
|
16704
|
+
"event-emitter": "device-event",
|
|
16705
|
+
"lock-control": "lock",
|
|
16706
|
+
switch: "switch",
|
|
16707
|
+
button: "button",
|
|
16708
|
+
doorbell: "doorbell"
|
|
16709
|
+
};
|
|
16710
|
+
function buildDescriptor(capName, kind) {
|
|
16711
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16712
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16713
|
+
return {
|
|
16714
|
+
...t,
|
|
16715
|
+
icon: legacyIcon(t.iconId)
|
|
16716
|
+
};
|
|
16717
|
+
}
|
|
16718
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16262
16719
|
var CameraPipelineConfigSchema = object({
|
|
16263
16720
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16264
16721
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19468,13 +19925,29 @@ method(object({
|
|
|
19468
19925
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19469
19926
|
kind: "mutation",
|
|
19470
19927
|
auth: "admin"
|
|
19471
|
-
}), method(object({
|
|
19928
|
+
}), method(object({
|
|
19929
|
+
deviceId: number(),
|
|
19930
|
+
reason: OpsLogReasonSchema.optional()
|
|
19931
|
+
}), object({
|
|
19472
19932
|
floorMs: number().nullable(),
|
|
19473
19933
|
deletedBuckets: number().int(),
|
|
19474
19934
|
reclaimedBytes: number().int()
|
|
19475
19935
|
}), {
|
|
19476
19936
|
kind: "mutation",
|
|
19477
19937
|
auth: "admin"
|
|
19938
|
+
}), method(object({
|
|
19939
|
+
deviceId: number(),
|
|
19940
|
+
fromMs: number().optional(),
|
|
19941
|
+
toMs: number().optional()
|
|
19942
|
+
}), object({
|
|
19943
|
+
deletedBuckets: number().int(),
|
|
19944
|
+
reclaimedBytes: number().int()
|
|
19945
|
+
}), {
|
|
19946
|
+
kind: "mutation",
|
|
19947
|
+
auth: "admin"
|
|
19948
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19949
|
+
kind: "query",
|
|
19950
|
+
auth: "admin"
|
|
19478
19951
|
});
|
|
19479
19952
|
/**
|
|
19480
19953
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22596,6 +23069,12 @@ Object.freeze({
|
|
|
22596
23069
|
addonId: null,
|
|
22597
23070
|
access: "delete"
|
|
22598
23071
|
},
|
|
23072
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23073
|
+
capName: "pipeline-analytics",
|
|
23074
|
+
capScope: "device",
|
|
23075
|
+
addonId: null,
|
|
23076
|
+
access: "delete"
|
|
23077
|
+
},
|
|
22599
23078
|
"pipelineAnalytics.deleteTracks": {
|
|
22600
23079
|
capName: "pipeline-analytics",
|
|
22601
23080
|
capScope: "device",
|
|
@@ -22626,6 +23105,12 @@ Object.freeze({
|
|
|
22626
23105
|
addonId: null,
|
|
22627
23106
|
access: "view"
|
|
22628
23107
|
},
|
|
23108
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23109
|
+
capName: "pipeline-analytics",
|
|
23110
|
+
capScope: "device",
|
|
23111
|
+
addonId: null,
|
|
23112
|
+
access: "view"
|
|
23113
|
+
},
|
|
22629
23114
|
"pipelineAnalytics.getKeyEvents": {
|
|
22630
23115
|
capName: "pipeline-analytics",
|
|
22631
23116
|
capScope: "device",
|
|
@@ -22668,6 +23153,12 @@ Object.freeze({
|
|
|
22668
23153
|
addonId: null,
|
|
22669
23154
|
access: "view"
|
|
22670
23155
|
},
|
|
23156
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23157
|
+
capName: "pipeline-analytics",
|
|
23158
|
+
capScope: "device",
|
|
23159
|
+
addonId: null,
|
|
23160
|
+
access: "view"
|
|
23161
|
+
},
|
|
22671
23162
|
"pipelineAnalytics.listRecentTracks": {
|
|
22672
23163
|
capName: "pipeline-analytics",
|
|
22673
23164
|
capScope: "device",
|
|
@@ -22680,6 +23171,12 @@ Object.freeze({
|
|
|
22680
23171
|
addonId: null,
|
|
22681
23172
|
access: "view"
|
|
22682
23173
|
},
|
|
23174
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23175
|
+
capName: "pipeline-analytics",
|
|
23176
|
+
capScope: "device",
|
|
23177
|
+
addonId: null,
|
|
23178
|
+
access: "create"
|
|
23179
|
+
},
|
|
22683
23180
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22684
23181
|
capName: "pipeline-analytics",
|
|
22685
23182
|
capScope: "device",
|
|
@@ -23442,6 +23939,12 @@ Object.freeze({
|
|
|
23442
23939
|
addonId: null,
|
|
23443
23940
|
access: "create"
|
|
23444
23941
|
},
|
|
23942
|
+
"recording.deleteFootprint": {
|
|
23943
|
+
capName: "recording",
|
|
23944
|
+
capScope: "system",
|
|
23945
|
+
addonId: null,
|
|
23946
|
+
access: "delete"
|
|
23947
|
+
},
|
|
23445
23948
|
"recording.getAvailability": {
|
|
23446
23949
|
capName: "recording",
|
|
23447
23950
|
capScope: "system",
|
|
@@ -23472,6 +23975,12 @@ Object.freeze({
|
|
|
23472
23975
|
addonId: null,
|
|
23473
23976
|
access: "view"
|
|
23474
23977
|
},
|
|
23978
|
+
"recording.listOpsLog": {
|
|
23979
|
+
capName: "recording",
|
|
23980
|
+
capScope: "system",
|
|
23981
|
+
addonId: null,
|
|
23982
|
+
access: "view"
|
|
23983
|
+
},
|
|
23475
23984
|
"recording.locateSegment": {
|
|
23476
23985
|
capName: "recording",
|
|
23477
23986
|
capScope: "system",
|
|
@@ -24845,7 +25354,7 @@ var RuleEngine = class {
|
|
|
24845
25354
|
if (!className || !conditions.classNames.includes(className)) return false;
|
|
24846
25355
|
}
|
|
24847
25356
|
if (conditions.zoneIds?.length) {
|
|
24848
|
-
const zones = data["zones"];
|
|
25357
|
+
const zones = data["zones"] ?? data["zoneIds"];
|
|
24849
25358
|
const zoneId = data["zoneId"];
|
|
24850
25359
|
if (!(zones ?? (zoneId ? [zoneId] : [])).some((z) => conditions.zoneIds.includes(z))) return false;
|
|
24851
25360
|
}
|
|
@@ -24932,7 +25441,9 @@ var EVENT_CATEGORIES = [
|
|
|
24932
25441
|
EventCategory.DetectionRaw,
|
|
24933
25442
|
EventCategory.DetectionResult,
|
|
24934
25443
|
EventCategory.PipelineAnalyticsDetectionEvent,
|
|
24935
|
-
EventCategory.EventEmitted
|
|
25444
|
+
EventCategory.EventEmitted,
|
|
25445
|
+
EventCategory.PipelineAnalyticsPackageDelivered,
|
|
25446
|
+
EventCategory.PipelineAnalyticsPackagePickedUp
|
|
24936
25447
|
];
|
|
24937
25448
|
var DEFAULT_NOTIFIER_CONFIG = {
|
|
24938
25449
|
defaultCooldownSeconds: 60,
|
|
@@ -25187,7 +25698,7 @@ var AdvancedNotifierAddon = class extends BaseAddon {
|
|
|
25187
25698
|
deviceName: data["deviceName"] ?? String(event.source.id),
|
|
25188
25699
|
className: data["className"] ?? "",
|
|
25189
25700
|
confidence: String(data["confidence"] ?? ""),
|
|
25190
|
-
zoneId: data["zoneId"] ?? "",
|
|
25701
|
+
zoneId: data["zoneId"] ?? (Array.isArray(data["zoneIds"]) ? String(data["zoneIds"][0] ?? "") : ""),
|
|
25191
25702
|
zoneName: data["zoneName"] ?? "",
|
|
25192
25703
|
category: event.category,
|
|
25193
25704
|
timestamp: event.timestamp.toISOString()
|
package/dist/addon.mjs
CHANGED
|
@@ -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
|
|
@@ -7585,6 +7641,160 @@ function cosineSimilarity(a, b) {
|
|
|
7585
7641
|
const denom = Math.sqrt(normA) * Math.sqrt(normB);
|
|
7586
7642
|
return denom === 0 ? 0 : dotProduct / denom;
|
|
7587
7643
|
}
|
|
7644
|
+
var COCO_TO_MACRO = {
|
|
7645
|
+
mapping: {
|
|
7646
|
+
person: "person",
|
|
7647
|
+
bicycle: "vehicle",
|
|
7648
|
+
car: "vehicle",
|
|
7649
|
+
motorcycle: "vehicle",
|
|
7650
|
+
airplane: "vehicle",
|
|
7651
|
+
bus: "vehicle",
|
|
7652
|
+
train: "vehicle",
|
|
7653
|
+
truck: "vehicle",
|
|
7654
|
+
boat: "vehicle",
|
|
7655
|
+
bird: "animal",
|
|
7656
|
+
cat: "animal",
|
|
7657
|
+
dog: "animal",
|
|
7658
|
+
horse: "animal",
|
|
7659
|
+
sheep: "animal",
|
|
7660
|
+
cow: "animal",
|
|
7661
|
+
elephant: "animal",
|
|
7662
|
+
bear: "animal",
|
|
7663
|
+
zebra: "animal",
|
|
7664
|
+
giraffe: "animal",
|
|
7665
|
+
suitcase: "package",
|
|
7666
|
+
backpack: "package",
|
|
7667
|
+
handbag: "package"
|
|
7668
|
+
},
|
|
7669
|
+
preserveOriginal: false
|
|
7670
|
+
};
|
|
7671
|
+
var AUDIO_MACRO_LABELS = [
|
|
7672
|
+
{
|
|
7673
|
+
id: "speech",
|
|
7674
|
+
name: "Speech",
|
|
7675
|
+
icon: "🗣️"
|
|
7676
|
+
},
|
|
7677
|
+
{
|
|
7678
|
+
id: "scream",
|
|
7679
|
+
name: "Scream / Shout",
|
|
7680
|
+
icon: "😱"
|
|
7681
|
+
},
|
|
7682
|
+
{
|
|
7683
|
+
id: "crying",
|
|
7684
|
+
name: "Crying / Baby",
|
|
7685
|
+
icon: "😢"
|
|
7686
|
+
},
|
|
7687
|
+
{
|
|
7688
|
+
id: "laughter",
|
|
7689
|
+
name: "Laughter",
|
|
7690
|
+
icon: "😂"
|
|
7691
|
+
},
|
|
7692
|
+
{
|
|
7693
|
+
id: "music",
|
|
7694
|
+
name: "Music",
|
|
7695
|
+
icon: "🎵"
|
|
7696
|
+
},
|
|
7697
|
+
{
|
|
7698
|
+
id: "dog",
|
|
7699
|
+
name: "Dog",
|
|
7700
|
+
icon: "🐕"
|
|
7701
|
+
},
|
|
7702
|
+
{
|
|
7703
|
+
id: "cat",
|
|
7704
|
+
name: "Cat",
|
|
7705
|
+
icon: "🐈"
|
|
7706
|
+
},
|
|
7707
|
+
{
|
|
7708
|
+
id: "bird",
|
|
7709
|
+
name: "Bird",
|
|
7710
|
+
icon: "🐦"
|
|
7711
|
+
},
|
|
7712
|
+
{
|
|
7713
|
+
id: "animal",
|
|
7714
|
+
name: "Animal (other)",
|
|
7715
|
+
icon: "🐾"
|
|
7716
|
+
},
|
|
7717
|
+
{
|
|
7718
|
+
id: "alarm",
|
|
7719
|
+
name: "Alarm / Siren",
|
|
7720
|
+
icon: "🚨"
|
|
7721
|
+
},
|
|
7722
|
+
{
|
|
7723
|
+
id: "doorbell",
|
|
7724
|
+
name: "Doorbell / Knock",
|
|
7725
|
+
icon: "🔔"
|
|
7726
|
+
},
|
|
7727
|
+
{
|
|
7728
|
+
id: "glass_breaking",
|
|
7729
|
+
name: "Glass Breaking",
|
|
7730
|
+
icon: "💥"
|
|
7731
|
+
},
|
|
7732
|
+
{
|
|
7733
|
+
id: "gunshot",
|
|
7734
|
+
name: "Gunshot / Explosion",
|
|
7735
|
+
icon: "💣"
|
|
7736
|
+
},
|
|
7737
|
+
{
|
|
7738
|
+
id: "vehicle",
|
|
7739
|
+
name: "Vehicle",
|
|
7740
|
+
icon: "🚗"
|
|
7741
|
+
},
|
|
7742
|
+
{
|
|
7743
|
+
id: "siren",
|
|
7744
|
+
name: "Emergency Siren",
|
|
7745
|
+
icon: "🚑"
|
|
7746
|
+
},
|
|
7747
|
+
{
|
|
7748
|
+
id: "fire",
|
|
7749
|
+
name: "Fire / Smoke",
|
|
7750
|
+
icon: "🔥"
|
|
7751
|
+
},
|
|
7752
|
+
{
|
|
7753
|
+
id: "water",
|
|
7754
|
+
name: "Water",
|
|
7755
|
+
icon: "💧"
|
|
7756
|
+
},
|
|
7757
|
+
{
|
|
7758
|
+
id: "wind",
|
|
7759
|
+
name: "Wind / Weather",
|
|
7760
|
+
icon: "🌬️"
|
|
7761
|
+
},
|
|
7762
|
+
{
|
|
7763
|
+
id: "door",
|
|
7764
|
+
name: "Door",
|
|
7765
|
+
icon: "🚪"
|
|
7766
|
+
},
|
|
7767
|
+
{
|
|
7768
|
+
id: "footsteps",
|
|
7769
|
+
name: "Footsteps",
|
|
7770
|
+
icon: "👣"
|
|
7771
|
+
},
|
|
7772
|
+
{
|
|
7773
|
+
id: "crowd",
|
|
7774
|
+
name: "Crowd / Chatter",
|
|
7775
|
+
icon: "👥"
|
|
7776
|
+
},
|
|
7777
|
+
{
|
|
7778
|
+
id: "telephone",
|
|
7779
|
+
name: "Telephone",
|
|
7780
|
+
icon: "📞"
|
|
7781
|
+
},
|
|
7782
|
+
{
|
|
7783
|
+
id: "engine",
|
|
7784
|
+
name: "Engine / Motor",
|
|
7785
|
+
icon: "⚙️"
|
|
7786
|
+
},
|
|
7787
|
+
{
|
|
7788
|
+
id: "tools",
|
|
7789
|
+
name: "Tools / Construction",
|
|
7790
|
+
icon: "🔨"
|
|
7791
|
+
},
|
|
7792
|
+
{
|
|
7793
|
+
id: "silence",
|
|
7794
|
+
name: "Silence",
|
|
7795
|
+
icon: "🤫"
|
|
7796
|
+
}
|
|
7797
|
+
];
|
|
7588
7798
|
var YAMNET_TO_MACRO = {
|
|
7589
7799
|
mapping: {
|
|
7590
7800
|
Speech: "speech",
|
|
@@ -7851,6 +8061,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7851
8061
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7852
8062
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7853
8063
|
/**
|
|
8064
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8065
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8066
|
+
* icon }`.
|
|
8067
|
+
*
|
|
8068
|
+
* This dictionary folds together what used to be scattered across four
|
|
8069
|
+
* copies:
|
|
8070
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8071
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8072
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8073
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8074
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8075
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8076
|
+
*
|
|
8077
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8078
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8079
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8080
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8081
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8082
|
+
*
|
|
8083
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8084
|
+
*/
|
|
8085
|
+
var TAXONOMY_COLORS = {
|
|
8086
|
+
motion: "#f59e0b",
|
|
8087
|
+
audio: "#06b6d4",
|
|
8088
|
+
person: "#22c55e",
|
|
8089
|
+
vehicle: "#3b82f6",
|
|
8090
|
+
animal: "#f97316",
|
|
8091
|
+
package: "#a855f7",
|
|
8092
|
+
sensor: "#8b5cf6",
|
|
8093
|
+
control: "#10b981",
|
|
8094
|
+
genericDetection: "#64748b"
|
|
8095
|
+
};
|
|
8096
|
+
var DETECTION_SUB_COLORS = {
|
|
8097
|
+
car: "#f59e0b",
|
|
8098
|
+
truck: "#d97706",
|
|
8099
|
+
bus: "#b45309",
|
|
8100
|
+
motorcycle: "#eab308",
|
|
8101
|
+
bicycle: "#ca8a04",
|
|
8102
|
+
airplane: "#60a5fa",
|
|
8103
|
+
boat: "#2563eb",
|
|
8104
|
+
train: "#1d4ed8",
|
|
8105
|
+
bird: "#14b8a6",
|
|
8106
|
+
dog: "#84cc16",
|
|
8107
|
+
cat: "#f97316",
|
|
8108
|
+
horse: "#a16207",
|
|
8109
|
+
sheep: "#a3a3a3",
|
|
8110
|
+
cow: "#78716c",
|
|
8111
|
+
elephant: "#6b7280",
|
|
8112
|
+
bear: "#7c2d12",
|
|
8113
|
+
zebra: "#404040",
|
|
8114
|
+
giraffe: "#d4a373"
|
|
8115
|
+
};
|
|
8116
|
+
function titleCase(id) {
|
|
8117
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8118
|
+
}
|
|
8119
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8120
|
+
function macro(kind, category, color, iconId, label) {
|
|
8121
|
+
entries.set(kind, {
|
|
8122
|
+
kind,
|
|
8123
|
+
parentKind: null,
|
|
8124
|
+
level: "macro",
|
|
8125
|
+
category,
|
|
8126
|
+
color,
|
|
8127
|
+
iconId,
|
|
8128
|
+
labelKey: `eventKind.${kind}`,
|
|
8129
|
+
label
|
|
8130
|
+
});
|
|
8131
|
+
}
|
|
8132
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8133
|
+
entries.set(kind, {
|
|
8134
|
+
kind,
|
|
8135
|
+
parentKind,
|
|
8136
|
+
level: "sub",
|
|
8137
|
+
category,
|
|
8138
|
+
color,
|
|
8139
|
+
iconId,
|
|
8140
|
+
labelKey: `eventKind.${kind}`,
|
|
8141
|
+
label
|
|
8142
|
+
});
|
|
8143
|
+
}
|
|
8144
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8145
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8146
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8147
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8148
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8149
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8150
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8151
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8152
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8153
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8154
|
+
if (entries.has(cocoClass)) continue;
|
|
8155
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8156
|
+
}
|
|
8157
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8158
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8159
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8160
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8161
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8162
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8163
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8164
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8165
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8166
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8167
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8168
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8169
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8170
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8171
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8172
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8173
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8174
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8175
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8176
|
+
const kind = `audio-${l.id}`;
|
|
8177
|
+
if (entries.has(kind)) continue;
|
|
8178
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8179
|
+
}
|
|
8180
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8181
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8182
|
+
/**
|
|
7854
8183
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7855
8184
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7856
8185
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15826,17 +16155,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15826
16155
|
"audio",
|
|
15827
16156
|
"detection",
|
|
15828
16157
|
"sensor",
|
|
16158
|
+
"control",
|
|
15829
16159
|
"custom",
|
|
15830
16160
|
"package"
|
|
15831
16161
|
]);
|
|
16162
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16163
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15832
16164
|
var EventKindDescriptorSchema = object({
|
|
15833
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16165
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15834
16166
|
kind: string(),
|
|
16167
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16168
|
+
labelKey: string(),
|
|
16169
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15835
16170
|
label: string(),
|
|
15836
16171
|
/** Hex color for timeline/legend rendering. */
|
|
15837
16172
|
color: string(),
|
|
16173
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16174
|
+
iconId: string(),
|
|
16175
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15838
16176
|
icon: EventKindIconSchema,
|
|
15839
16177
|
category: EventKindCategorySchema,
|
|
16178
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16179
|
+
parentKind: string().nullable(),
|
|
16180
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16181
|
+
level: EventKindLevelSchema,
|
|
15840
16182
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15841
16183
|
* itself; for sensor kinds the LINKED source device. */
|
|
15842
16184
|
source: object({
|
|
@@ -15909,11 +16251,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15909
16251
|
firstAt: number(),
|
|
15910
16252
|
lastAt: number()
|
|
15911
16253
|
});
|
|
16254
|
+
/**
|
|
16255
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16256
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16257
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16258
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16259
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16260
|
+
*/
|
|
16261
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15912
16262
|
var TrackSchema = object({
|
|
15913
16263
|
trackId: string(),
|
|
15914
16264
|
deviceId: number(),
|
|
15915
16265
|
className: string(),
|
|
15916
16266
|
label: string().optional(),
|
|
16267
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16268
|
+
source: TrackSourceSchema.optional(),
|
|
15917
16269
|
firstSeen: number(),
|
|
15918
16270
|
lastSeen: number(),
|
|
15919
16271
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16168,6 +16520,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16168
16520
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16169
16521
|
embeddings: number().int()
|
|
16170
16522
|
});
|
|
16523
|
+
/** Event-store footprint for one camera. */
|
|
16524
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16525
|
+
deviceId: number(),
|
|
16526
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16527
|
+
rows: number().int(),
|
|
16528
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16529
|
+
bytes: number().int()
|
|
16530
|
+
});
|
|
16531
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16532
|
+
var EventStoreFootprintSchema = object({
|
|
16533
|
+
totalRows: number().int(),
|
|
16534
|
+
totalBytes: number().int(),
|
|
16535
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16536
|
+
});
|
|
16537
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16538
|
+
var EventPruneCountsSchema = object({
|
|
16539
|
+
motion: number().int(),
|
|
16540
|
+
object: number().int(),
|
|
16541
|
+
audio: number().int()
|
|
16542
|
+
});
|
|
16171
16543
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16172
16544
|
deviceId: number(),
|
|
16173
16545
|
trackId: string()
|
|
@@ -16231,6 +16603,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16231
16603
|
}), {
|
|
16232
16604
|
kind: "mutation",
|
|
16233
16605
|
auth: "admin"
|
|
16606
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16607
|
+
kind: "query",
|
|
16608
|
+
auth: "admin"
|
|
16609
|
+
}), method(object({
|
|
16610
|
+
olderThanMs: number(),
|
|
16611
|
+
reason: OpsLogReasonSchema.optional()
|
|
16612
|
+
}), EventPruneCountsSchema, {
|
|
16613
|
+
kind: "mutation",
|
|
16614
|
+
auth: "admin"
|
|
16615
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16616
|
+
kind: "mutation",
|
|
16617
|
+
auth: "admin"
|
|
16618
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16619
|
+
kind: "query",
|
|
16620
|
+
auth: "admin"
|
|
16234
16621
|
}), method(object({
|
|
16235
16622
|
eventId: string(),
|
|
16236
16623
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16255,6 +16642,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16255
16642
|
eventId: string(),
|
|
16256
16643
|
timestamp: number()
|
|
16257
16644
|
});
|
|
16645
|
+
/**
|
|
16646
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16647
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16648
|
+
* caps into per-camera event-kind descriptors.
|
|
16649
|
+
*
|
|
16650
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16651
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16652
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16653
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16654
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16655
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16656
|
+
* eventful cap is missing.
|
|
16657
|
+
*/
|
|
16658
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16659
|
+
var LEGACY_ICON = {
|
|
16660
|
+
motion: "motion",
|
|
16661
|
+
audio: "audio",
|
|
16662
|
+
person: "person",
|
|
16663
|
+
vehicle: "vehicle",
|
|
16664
|
+
animal: "animal",
|
|
16665
|
+
package: "package",
|
|
16666
|
+
door: "door",
|
|
16667
|
+
pir: "pir",
|
|
16668
|
+
smoke: "smoke",
|
|
16669
|
+
water: "water",
|
|
16670
|
+
button: "button",
|
|
16671
|
+
generic: "generic",
|
|
16672
|
+
gas: "smoke",
|
|
16673
|
+
vibration: "generic",
|
|
16674
|
+
tamper: "generic",
|
|
16675
|
+
presence: "person",
|
|
16676
|
+
lock: "generic",
|
|
16677
|
+
siren: "generic",
|
|
16678
|
+
switch: "generic",
|
|
16679
|
+
doorbell: "button"
|
|
16680
|
+
};
|
|
16681
|
+
function legacyIcon(iconId) {
|
|
16682
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16683
|
+
}
|
|
16684
|
+
/**
|
|
16685
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16686
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16687
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16688
|
+
*/
|
|
16689
|
+
var CAP_TO_KIND = {
|
|
16690
|
+
contact: "contact",
|
|
16691
|
+
motion: "motion-sensor",
|
|
16692
|
+
smoke: "smoke",
|
|
16693
|
+
flood: "flood",
|
|
16694
|
+
gas: "gas",
|
|
16695
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16696
|
+
vibration: "vibration",
|
|
16697
|
+
tamper: "tamper",
|
|
16698
|
+
presence: "presence",
|
|
16699
|
+
"enum-sensor": "enum-sensor",
|
|
16700
|
+
"event-emitter": "device-event",
|
|
16701
|
+
"lock-control": "lock",
|
|
16702
|
+
switch: "switch",
|
|
16703
|
+
button: "button",
|
|
16704
|
+
doorbell: "doorbell"
|
|
16705
|
+
};
|
|
16706
|
+
function buildDescriptor(capName, kind) {
|
|
16707
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16708
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16709
|
+
return {
|
|
16710
|
+
...t,
|
|
16711
|
+
icon: legacyIcon(t.iconId)
|
|
16712
|
+
};
|
|
16713
|
+
}
|
|
16714
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16258
16715
|
var CameraPipelineConfigSchema = object({
|
|
16259
16716
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16260
16717
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19464,13 +19921,29 @@ method(object({
|
|
|
19464
19921
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19465
19922
|
kind: "mutation",
|
|
19466
19923
|
auth: "admin"
|
|
19467
|
-
}), method(object({
|
|
19924
|
+
}), method(object({
|
|
19925
|
+
deviceId: number(),
|
|
19926
|
+
reason: OpsLogReasonSchema.optional()
|
|
19927
|
+
}), object({
|
|
19468
19928
|
floorMs: number().nullable(),
|
|
19469
19929
|
deletedBuckets: number().int(),
|
|
19470
19930
|
reclaimedBytes: number().int()
|
|
19471
19931
|
}), {
|
|
19472
19932
|
kind: "mutation",
|
|
19473
19933
|
auth: "admin"
|
|
19934
|
+
}), method(object({
|
|
19935
|
+
deviceId: number(),
|
|
19936
|
+
fromMs: number().optional(),
|
|
19937
|
+
toMs: number().optional()
|
|
19938
|
+
}), object({
|
|
19939
|
+
deletedBuckets: number().int(),
|
|
19940
|
+
reclaimedBytes: number().int()
|
|
19941
|
+
}), {
|
|
19942
|
+
kind: "mutation",
|
|
19943
|
+
auth: "admin"
|
|
19944
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19945
|
+
kind: "query",
|
|
19946
|
+
auth: "admin"
|
|
19474
19947
|
});
|
|
19475
19948
|
/**
|
|
19476
19949
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22592,6 +23065,12 @@ Object.freeze({
|
|
|
22592
23065
|
addonId: null,
|
|
22593
23066
|
access: "delete"
|
|
22594
23067
|
},
|
|
23068
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23069
|
+
capName: "pipeline-analytics",
|
|
23070
|
+
capScope: "device",
|
|
23071
|
+
addonId: null,
|
|
23072
|
+
access: "delete"
|
|
23073
|
+
},
|
|
22595
23074
|
"pipelineAnalytics.deleteTracks": {
|
|
22596
23075
|
capName: "pipeline-analytics",
|
|
22597
23076
|
capScope: "device",
|
|
@@ -22622,6 +23101,12 @@ Object.freeze({
|
|
|
22622
23101
|
addonId: null,
|
|
22623
23102
|
access: "view"
|
|
22624
23103
|
},
|
|
23104
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23105
|
+
capName: "pipeline-analytics",
|
|
23106
|
+
capScope: "device",
|
|
23107
|
+
addonId: null,
|
|
23108
|
+
access: "view"
|
|
23109
|
+
},
|
|
22625
23110
|
"pipelineAnalytics.getKeyEvents": {
|
|
22626
23111
|
capName: "pipeline-analytics",
|
|
22627
23112
|
capScope: "device",
|
|
@@ -22664,6 +23149,12 @@ Object.freeze({
|
|
|
22664
23149
|
addonId: null,
|
|
22665
23150
|
access: "view"
|
|
22666
23151
|
},
|
|
23152
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23153
|
+
capName: "pipeline-analytics",
|
|
23154
|
+
capScope: "device",
|
|
23155
|
+
addonId: null,
|
|
23156
|
+
access: "view"
|
|
23157
|
+
},
|
|
22667
23158
|
"pipelineAnalytics.listRecentTracks": {
|
|
22668
23159
|
capName: "pipeline-analytics",
|
|
22669
23160
|
capScope: "device",
|
|
@@ -22676,6 +23167,12 @@ Object.freeze({
|
|
|
22676
23167
|
addonId: null,
|
|
22677
23168
|
access: "view"
|
|
22678
23169
|
},
|
|
23170
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23171
|
+
capName: "pipeline-analytics",
|
|
23172
|
+
capScope: "device",
|
|
23173
|
+
addonId: null,
|
|
23174
|
+
access: "create"
|
|
23175
|
+
},
|
|
22679
23176
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22680
23177
|
capName: "pipeline-analytics",
|
|
22681
23178
|
capScope: "device",
|
|
@@ -23438,6 +23935,12 @@ Object.freeze({
|
|
|
23438
23935
|
addonId: null,
|
|
23439
23936
|
access: "create"
|
|
23440
23937
|
},
|
|
23938
|
+
"recording.deleteFootprint": {
|
|
23939
|
+
capName: "recording",
|
|
23940
|
+
capScope: "system",
|
|
23941
|
+
addonId: null,
|
|
23942
|
+
access: "delete"
|
|
23943
|
+
},
|
|
23441
23944
|
"recording.getAvailability": {
|
|
23442
23945
|
capName: "recording",
|
|
23443
23946
|
capScope: "system",
|
|
@@ -23468,6 +23971,12 @@ Object.freeze({
|
|
|
23468
23971
|
addonId: null,
|
|
23469
23972
|
access: "view"
|
|
23470
23973
|
},
|
|
23974
|
+
"recording.listOpsLog": {
|
|
23975
|
+
capName: "recording",
|
|
23976
|
+
capScope: "system",
|
|
23977
|
+
addonId: null,
|
|
23978
|
+
access: "view"
|
|
23979
|
+
},
|
|
23471
23980
|
"recording.locateSegment": {
|
|
23472
23981
|
capName: "recording",
|
|
23473
23982
|
capScope: "system",
|
|
@@ -24841,7 +25350,7 @@ var RuleEngine = class {
|
|
|
24841
25350
|
if (!className || !conditions.classNames.includes(className)) return false;
|
|
24842
25351
|
}
|
|
24843
25352
|
if (conditions.zoneIds?.length) {
|
|
24844
|
-
const zones = data["zones"];
|
|
25353
|
+
const zones = data["zones"] ?? data["zoneIds"];
|
|
24845
25354
|
const zoneId = data["zoneId"];
|
|
24846
25355
|
if (!(zones ?? (zoneId ? [zoneId] : [])).some((z) => conditions.zoneIds.includes(z))) return false;
|
|
24847
25356
|
}
|
|
@@ -24928,7 +25437,9 @@ var EVENT_CATEGORIES = [
|
|
|
24928
25437
|
EventCategory.DetectionRaw,
|
|
24929
25438
|
EventCategory.DetectionResult,
|
|
24930
25439
|
EventCategory.PipelineAnalyticsDetectionEvent,
|
|
24931
|
-
EventCategory.EventEmitted
|
|
25440
|
+
EventCategory.EventEmitted,
|
|
25441
|
+
EventCategory.PipelineAnalyticsPackageDelivered,
|
|
25442
|
+
EventCategory.PipelineAnalyticsPackagePickedUp
|
|
24932
25443
|
];
|
|
24933
25444
|
var DEFAULT_NOTIFIER_CONFIG = {
|
|
24934
25445
|
defaultCooldownSeconds: 60,
|
|
@@ -25183,7 +25694,7 @@ var AdvancedNotifierAddon = class extends BaseAddon {
|
|
|
25183
25694
|
deviceName: data["deviceName"] ?? String(event.source.id),
|
|
25184
25695
|
className: data["className"] ?? "",
|
|
25185
25696
|
confidence: String(data["confidence"] ?? ""),
|
|
25186
|
-
zoneId: data["zoneId"] ?? "",
|
|
25697
|
+
zoneId: data["zoneId"] ?? (Array.isArray(data["zoneIds"]) ? String(data["zoneIds"][0] ?? "") : ""),
|
|
25187
25698
|
zoneName: data["zoneName"] ?? "",
|
|
25188
25699
|
category: event.category,
|
|
25189
25700
|
timestamp: event.timestamp.toISOString()
|