@camstack/addon-notifiers 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 +511 -2
- package/dist/addon.mjs +511 -2
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -7449,6 +7449,62 @@ var RecordingConfigSchema = object({
|
|
|
7449
7449
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7450
7450
|
});
|
|
7451
7451
|
/**
|
|
7452
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7453
|
+
* recordings and events management surfaces.
|
|
7454
|
+
*
|
|
7455
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7456
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7457
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7458
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7459
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7460
|
+
* never fail the operation it records.
|
|
7461
|
+
*/
|
|
7462
|
+
/** Which management domain the operation belongs to. */
|
|
7463
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7464
|
+
/** The kind of management operation performed. */
|
|
7465
|
+
var OpsLogOpSchema = _enum([
|
|
7466
|
+
"prune",
|
|
7467
|
+
"manual-delete",
|
|
7468
|
+
"rescan",
|
|
7469
|
+
"retention-run"
|
|
7470
|
+
]);
|
|
7471
|
+
/** Why the operation ran. */
|
|
7472
|
+
var OpsLogReasonSchema = _enum([
|
|
7473
|
+
"retention",
|
|
7474
|
+
"quota",
|
|
7475
|
+
"manual",
|
|
7476
|
+
"operator"
|
|
7477
|
+
]);
|
|
7478
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7479
|
+
var OpsLogEntrySchema = object({
|
|
7480
|
+
/** Unique row id. */
|
|
7481
|
+
id: string(),
|
|
7482
|
+
/** Epoch ms the operation completed. */
|
|
7483
|
+
at: number(),
|
|
7484
|
+
domain: OpsLogDomainSchema,
|
|
7485
|
+
op: OpsLogOpSchema,
|
|
7486
|
+
reason: OpsLogReasonSchema,
|
|
7487
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7488
|
+
deviceId: number().nullable(),
|
|
7489
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7490
|
+
nodeId: string(),
|
|
7491
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7492
|
+
itemsAffected: number(),
|
|
7493
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7494
|
+
bytesReclaimed: number(),
|
|
7495
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7496
|
+
detail: string().nullable(),
|
|
7497
|
+
/** Who/what triggered the op. */
|
|
7498
|
+
actor: string()
|
|
7499
|
+
});
|
|
7500
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7501
|
+
var OpsLogQueryInputSchema = object({
|
|
7502
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7503
|
+
deviceId: number().optional(),
|
|
7504
|
+
/** Max rows returned, newest-first. */
|
|
7505
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7506
|
+
});
|
|
7507
|
+
/**
|
|
7452
7508
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7453
7509
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7454
7510
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7692,6 +7748,160 @@ var EncodeProfileSchema = object({
|
|
|
7692
7748
|
*/
|
|
7693
7749
|
outputArgs: array(string()).optional()
|
|
7694
7750
|
});
|
|
7751
|
+
var COCO_TO_MACRO = {
|
|
7752
|
+
mapping: {
|
|
7753
|
+
person: "person",
|
|
7754
|
+
bicycle: "vehicle",
|
|
7755
|
+
car: "vehicle",
|
|
7756
|
+
motorcycle: "vehicle",
|
|
7757
|
+
airplane: "vehicle",
|
|
7758
|
+
bus: "vehicle",
|
|
7759
|
+
train: "vehicle",
|
|
7760
|
+
truck: "vehicle",
|
|
7761
|
+
boat: "vehicle",
|
|
7762
|
+
bird: "animal",
|
|
7763
|
+
cat: "animal",
|
|
7764
|
+
dog: "animal",
|
|
7765
|
+
horse: "animal",
|
|
7766
|
+
sheep: "animal",
|
|
7767
|
+
cow: "animal",
|
|
7768
|
+
elephant: "animal",
|
|
7769
|
+
bear: "animal",
|
|
7770
|
+
zebra: "animal",
|
|
7771
|
+
giraffe: "animal",
|
|
7772
|
+
suitcase: "package",
|
|
7773
|
+
backpack: "package",
|
|
7774
|
+
handbag: "package"
|
|
7775
|
+
},
|
|
7776
|
+
preserveOriginal: false
|
|
7777
|
+
};
|
|
7778
|
+
var AUDIO_MACRO_LABELS = [
|
|
7779
|
+
{
|
|
7780
|
+
id: "speech",
|
|
7781
|
+
name: "Speech",
|
|
7782
|
+
icon: "🗣️"
|
|
7783
|
+
},
|
|
7784
|
+
{
|
|
7785
|
+
id: "scream",
|
|
7786
|
+
name: "Scream / Shout",
|
|
7787
|
+
icon: "😱"
|
|
7788
|
+
},
|
|
7789
|
+
{
|
|
7790
|
+
id: "crying",
|
|
7791
|
+
name: "Crying / Baby",
|
|
7792
|
+
icon: "😢"
|
|
7793
|
+
},
|
|
7794
|
+
{
|
|
7795
|
+
id: "laughter",
|
|
7796
|
+
name: "Laughter",
|
|
7797
|
+
icon: "😂"
|
|
7798
|
+
},
|
|
7799
|
+
{
|
|
7800
|
+
id: "music",
|
|
7801
|
+
name: "Music",
|
|
7802
|
+
icon: "🎵"
|
|
7803
|
+
},
|
|
7804
|
+
{
|
|
7805
|
+
id: "dog",
|
|
7806
|
+
name: "Dog",
|
|
7807
|
+
icon: "🐕"
|
|
7808
|
+
},
|
|
7809
|
+
{
|
|
7810
|
+
id: "cat",
|
|
7811
|
+
name: "Cat",
|
|
7812
|
+
icon: "🐈"
|
|
7813
|
+
},
|
|
7814
|
+
{
|
|
7815
|
+
id: "bird",
|
|
7816
|
+
name: "Bird",
|
|
7817
|
+
icon: "🐦"
|
|
7818
|
+
},
|
|
7819
|
+
{
|
|
7820
|
+
id: "animal",
|
|
7821
|
+
name: "Animal (other)",
|
|
7822
|
+
icon: "🐾"
|
|
7823
|
+
},
|
|
7824
|
+
{
|
|
7825
|
+
id: "alarm",
|
|
7826
|
+
name: "Alarm / Siren",
|
|
7827
|
+
icon: "🚨"
|
|
7828
|
+
},
|
|
7829
|
+
{
|
|
7830
|
+
id: "doorbell",
|
|
7831
|
+
name: "Doorbell / Knock",
|
|
7832
|
+
icon: "🔔"
|
|
7833
|
+
},
|
|
7834
|
+
{
|
|
7835
|
+
id: "glass_breaking",
|
|
7836
|
+
name: "Glass Breaking",
|
|
7837
|
+
icon: "💥"
|
|
7838
|
+
},
|
|
7839
|
+
{
|
|
7840
|
+
id: "gunshot",
|
|
7841
|
+
name: "Gunshot / Explosion",
|
|
7842
|
+
icon: "💣"
|
|
7843
|
+
},
|
|
7844
|
+
{
|
|
7845
|
+
id: "vehicle",
|
|
7846
|
+
name: "Vehicle",
|
|
7847
|
+
icon: "🚗"
|
|
7848
|
+
},
|
|
7849
|
+
{
|
|
7850
|
+
id: "siren",
|
|
7851
|
+
name: "Emergency Siren",
|
|
7852
|
+
icon: "🚑"
|
|
7853
|
+
},
|
|
7854
|
+
{
|
|
7855
|
+
id: "fire",
|
|
7856
|
+
name: "Fire / Smoke",
|
|
7857
|
+
icon: "🔥"
|
|
7858
|
+
},
|
|
7859
|
+
{
|
|
7860
|
+
id: "water",
|
|
7861
|
+
name: "Water",
|
|
7862
|
+
icon: "💧"
|
|
7863
|
+
},
|
|
7864
|
+
{
|
|
7865
|
+
id: "wind",
|
|
7866
|
+
name: "Wind / Weather",
|
|
7867
|
+
icon: "🌬️"
|
|
7868
|
+
},
|
|
7869
|
+
{
|
|
7870
|
+
id: "door",
|
|
7871
|
+
name: "Door",
|
|
7872
|
+
icon: "🚪"
|
|
7873
|
+
},
|
|
7874
|
+
{
|
|
7875
|
+
id: "footsteps",
|
|
7876
|
+
name: "Footsteps",
|
|
7877
|
+
icon: "👣"
|
|
7878
|
+
},
|
|
7879
|
+
{
|
|
7880
|
+
id: "crowd",
|
|
7881
|
+
name: "Crowd / Chatter",
|
|
7882
|
+
icon: "👥"
|
|
7883
|
+
},
|
|
7884
|
+
{
|
|
7885
|
+
id: "telephone",
|
|
7886
|
+
name: "Telephone",
|
|
7887
|
+
icon: "📞"
|
|
7888
|
+
},
|
|
7889
|
+
{
|
|
7890
|
+
id: "engine",
|
|
7891
|
+
name: "Engine / Motor",
|
|
7892
|
+
icon: "⚙️"
|
|
7893
|
+
},
|
|
7894
|
+
{
|
|
7895
|
+
id: "tools",
|
|
7896
|
+
name: "Tools / Construction",
|
|
7897
|
+
icon: "🔨"
|
|
7898
|
+
},
|
|
7899
|
+
{
|
|
7900
|
+
id: "silence",
|
|
7901
|
+
name: "Silence",
|
|
7902
|
+
icon: "🤫"
|
|
7903
|
+
}
|
|
7904
|
+
];
|
|
7695
7905
|
var YAMNET_TO_MACRO = {
|
|
7696
7906
|
mapping: {
|
|
7697
7907
|
Speech: "speech",
|
|
@@ -7958,6 +8168,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7958
8168
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7959
8169
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7960
8170
|
/**
|
|
8171
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8172
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8173
|
+
* icon }`.
|
|
8174
|
+
*
|
|
8175
|
+
* This dictionary folds together what used to be scattered across four
|
|
8176
|
+
* copies:
|
|
8177
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8178
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8179
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8180
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8181
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8182
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8183
|
+
*
|
|
8184
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8185
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8186
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8187
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8188
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8189
|
+
*
|
|
8190
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8191
|
+
*/
|
|
8192
|
+
var TAXONOMY_COLORS = {
|
|
8193
|
+
motion: "#f59e0b",
|
|
8194
|
+
audio: "#06b6d4",
|
|
8195
|
+
person: "#22c55e",
|
|
8196
|
+
vehicle: "#3b82f6",
|
|
8197
|
+
animal: "#f97316",
|
|
8198
|
+
package: "#a855f7",
|
|
8199
|
+
sensor: "#8b5cf6",
|
|
8200
|
+
control: "#10b981",
|
|
8201
|
+
genericDetection: "#64748b"
|
|
8202
|
+
};
|
|
8203
|
+
var DETECTION_SUB_COLORS = {
|
|
8204
|
+
car: "#f59e0b",
|
|
8205
|
+
truck: "#d97706",
|
|
8206
|
+
bus: "#b45309",
|
|
8207
|
+
motorcycle: "#eab308",
|
|
8208
|
+
bicycle: "#ca8a04",
|
|
8209
|
+
airplane: "#60a5fa",
|
|
8210
|
+
boat: "#2563eb",
|
|
8211
|
+
train: "#1d4ed8",
|
|
8212
|
+
bird: "#14b8a6",
|
|
8213
|
+
dog: "#84cc16",
|
|
8214
|
+
cat: "#f97316",
|
|
8215
|
+
horse: "#a16207",
|
|
8216
|
+
sheep: "#a3a3a3",
|
|
8217
|
+
cow: "#78716c",
|
|
8218
|
+
elephant: "#6b7280",
|
|
8219
|
+
bear: "#7c2d12",
|
|
8220
|
+
zebra: "#404040",
|
|
8221
|
+
giraffe: "#d4a373"
|
|
8222
|
+
};
|
|
8223
|
+
function titleCase(id) {
|
|
8224
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8225
|
+
}
|
|
8226
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8227
|
+
function macro(kind, category, color, iconId, label) {
|
|
8228
|
+
entries.set(kind, {
|
|
8229
|
+
kind,
|
|
8230
|
+
parentKind: null,
|
|
8231
|
+
level: "macro",
|
|
8232
|
+
category,
|
|
8233
|
+
color,
|
|
8234
|
+
iconId,
|
|
8235
|
+
labelKey: `eventKind.${kind}`,
|
|
8236
|
+
label
|
|
8237
|
+
});
|
|
8238
|
+
}
|
|
8239
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8240
|
+
entries.set(kind, {
|
|
8241
|
+
kind,
|
|
8242
|
+
parentKind,
|
|
8243
|
+
level: "sub",
|
|
8244
|
+
category,
|
|
8245
|
+
color,
|
|
8246
|
+
iconId,
|
|
8247
|
+
labelKey: `eventKind.${kind}`,
|
|
8248
|
+
label
|
|
8249
|
+
});
|
|
8250
|
+
}
|
|
8251
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8252
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8253
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8254
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8255
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8256
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8257
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8258
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8259
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8260
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8261
|
+
if (entries.has(cocoClass)) continue;
|
|
8262
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8263
|
+
}
|
|
8264
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8265
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8266
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8267
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8268
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8269
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8270
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8271
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8272
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8273
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8274
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8275
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8276
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8277
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8278
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8279
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8280
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8281
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8282
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8283
|
+
const kind = `audio-${l.id}`;
|
|
8284
|
+
if (entries.has(kind)) continue;
|
|
8285
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8286
|
+
}
|
|
8287
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8288
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8289
|
+
/**
|
|
7961
8290
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7962
8291
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7963
8292
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -16133,17 +16462,30 @@ var EventKindCategorySchema = _enum([
|
|
|
16133
16462
|
"audio",
|
|
16134
16463
|
"detection",
|
|
16135
16464
|
"sensor",
|
|
16465
|
+
"control",
|
|
16136
16466
|
"custom",
|
|
16137
16467
|
"package"
|
|
16138
16468
|
]);
|
|
16469
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16470
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
16139
16471
|
var EventKindDescriptorSchema = object({
|
|
16140
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16472
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
16141
16473
|
kind: string(),
|
|
16474
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16475
|
+
labelKey: string(),
|
|
16476
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
16142
16477
|
label: string(),
|
|
16143
16478
|
/** Hex color for timeline/legend rendering. */
|
|
16144
16479
|
color: string(),
|
|
16480
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16481
|
+
iconId: string(),
|
|
16482
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
16145
16483
|
icon: EventKindIconSchema,
|
|
16146
16484
|
category: EventKindCategorySchema,
|
|
16485
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16486
|
+
parentKind: string().nullable(),
|
|
16487
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16488
|
+
level: EventKindLevelSchema,
|
|
16147
16489
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
16148
16490
|
* itself; for sensor kinds the LINKED source device. */
|
|
16149
16491
|
source: object({
|
|
@@ -16216,11 +16558,21 @@ var TrackAudioLabelSchema = object({
|
|
|
16216
16558
|
firstAt: number(),
|
|
16217
16559
|
lastAt: number()
|
|
16218
16560
|
});
|
|
16561
|
+
/**
|
|
16562
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16563
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16564
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16565
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16566
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16567
|
+
*/
|
|
16568
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
16219
16569
|
var TrackSchema = object({
|
|
16220
16570
|
trackId: string(),
|
|
16221
16571
|
deviceId: number(),
|
|
16222
16572
|
className: string(),
|
|
16223
16573
|
label: string().optional(),
|
|
16574
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16575
|
+
source: TrackSourceSchema.optional(),
|
|
16224
16576
|
firstSeen: number(),
|
|
16225
16577
|
lastSeen: number(),
|
|
16226
16578
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16475,6 +16827,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16475
16827
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16476
16828
|
embeddings: number().int()
|
|
16477
16829
|
});
|
|
16830
|
+
/** Event-store footprint for one camera. */
|
|
16831
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16832
|
+
deviceId: number(),
|
|
16833
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16834
|
+
rows: number().int(),
|
|
16835
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16836
|
+
bytes: number().int()
|
|
16837
|
+
});
|
|
16838
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16839
|
+
var EventStoreFootprintSchema = object({
|
|
16840
|
+
totalRows: number().int(),
|
|
16841
|
+
totalBytes: number().int(),
|
|
16842
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16843
|
+
});
|
|
16844
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16845
|
+
var EventPruneCountsSchema = object({
|
|
16846
|
+
motion: number().int(),
|
|
16847
|
+
object: number().int(),
|
|
16848
|
+
audio: number().int()
|
|
16849
|
+
});
|
|
16478
16850
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16479
16851
|
deviceId: number(),
|
|
16480
16852
|
trackId: string()
|
|
@@ -16538,6 +16910,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16538
16910
|
}), {
|
|
16539
16911
|
kind: "mutation",
|
|
16540
16912
|
auth: "admin"
|
|
16913
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16914
|
+
kind: "query",
|
|
16915
|
+
auth: "admin"
|
|
16916
|
+
}), method(object({
|
|
16917
|
+
olderThanMs: number(),
|
|
16918
|
+
reason: OpsLogReasonSchema.optional()
|
|
16919
|
+
}), EventPruneCountsSchema, {
|
|
16920
|
+
kind: "mutation",
|
|
16921
|
+
auth: "admin"
|
|
16922
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16923
|
+
kind: "mutation",
|
|
16924
|
+
auth: "admin"
|
|
16925
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16926
|
+
kind: "query",
|
|
16927
|
+
auth: "admin"
|
|
16541
16928
|
}), method(object({
|
|
16542
16929
|
eventId: string(),
|
|
16543
16930
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16562,6 +16949,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16562
16949
|
eventId: string(),
|
|
16563
16950
|
timestamp: number()
|
|
16564
16951
|
});
|
|
16952
|
+
/**
|
|
16953
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16954
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16955
|
+
* caps into per-camera event-kind descriptors.
|
|
16956
|
+
*
|
|
16957
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16958
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16959
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16960
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16961
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16962
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16963
|
+
* eventful cap is missing.
|
|
16964
|
+
*/
|
|
16965
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16966
|
+
var LEGACY_ICON = {
|
|
16967
|
+
motion: "motion",
|
|
16968
|
+
audio: "audio",
|
|
16969
|
+
person: "person",
|
|
16970
|
+
vehicle: "vehicle",
|
|
16971
|
+
animal: "animal",
|
|
16972
|
+
package: "package",
|
|
16973
|
+
door: "door",
|
|
16974
|
+
pir: "pir",
|
|
16975
|
+
smoke: "smoke",
|
|
16976
|
+
water: "water",
|
|
16977
|
+
button: "button",
|
|
16978
|
+
generic: "generic",
|
|
16979
|
+
gas: "smoke",
|
|
16980
|
+
vibration: "generic",
|
|
16981
|
+
tamper: "generic",
|
|
16982
|
+
presence: "person",
|
|
16983
|
+
lock: "generic",
|
|
16984
|
+
siren: "generic",
|
|
16985
|
+
switch: "generic",
|
|
16986
|
+
doorbell: "button"
|
|
16987
|
+
};
|
|
16988
|
+
function legacyIcon(iconId) {
|
|
16989
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16990
|
+
}
|
|
16991
|
+
/**
|
|
16992
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16993
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16994
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16995
|
+
*/
|
|
16996
|
+
var CAP_TO_KIND = {
|
|
16997
|
+
contact: "contact",
|
|
16998
|
+
motion: "motion-sensor",
|
|
16999
|
+
smoke: "smoke",
|
|
17000
|
+
flood: "flood",
|
|
17001
|
+
gas: "gas",
|
|
17002
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
17003
|
+
vibration: "vibration",
|
|
17004
|
+
tamper: "tamper",
|
|
17005
|
+
presence: "presence",
|
|
17006
|
+
"enum-sensor": "enum-sensor",
|
|
17007
|
+
"event-emitter": "device-event",
|
|
17008
|
+
"lock-control": "lock",
|
|
17009
|
+
switch: "switch",
|
|
17010
|
+
button: "button",
|
|
17011
|
+
doorbell: "doorbell"
|
|
17012
|
+
};
|
|
17013
|
+
function buildDescriptor(capName, kind) {
|
|
17014
|
+
const t = EVENT_TAXONOMY[kind];
|
|
17015
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
17016
|
+
return {
|
|
17017
|
+
...t,
|
|
17018
|
+
icon: legacyIcon(t.iconId)
|
|
17019
|
+
};
|
|
17020
|
+
}
|
|
17021
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16565
17022
|
var CameraPipelineConfigSchema = object({
|
|
16566
17023
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16567
17024
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19771,13 +20228,29 @@ method(object({
|
|
|
19771
20228
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19772
20229
|
kind: "mutation",
|
|
19773
20230
|
auth: "admin"
|
|
19774
|
-
}), method(object({
|
|
20231
|
+
}), method(object({
|
|
20232
|
+
deviceId: number(),
|
|
20233
|
+
reason: OpsLogReasonSchema.optional()
|
|
20234
|
+
}), object({
|
|
19775
20235
|
floorMs: number().nullable(),
|
|
19776
20236
|
deletedBuckets: number().int(),
|
|
19777
20237
|
reclaimedBytes: number().int()
|
|
19778
20238
|
}), {
|
|
19779
20239
|
kind: "mutation",
|
|
19780
20240
|
auth: "admin"
|
|
20241
|
+
}), method(object({
|
|
20242
|
+
deviceId: number(),
|
|
20243
|
+
fromMs: number().optional(),
|
|
20244
|
+
toMs: number().optional()
|
|
20245
|
+
}), object({
|
|
20246
|
+
deletedBuckets: number().int(),
|
|
20247
|
+
reclaimedBytes: number().int()
|
|
20248
|
+
}), {
|
|
20249
|
+
kind: "mutation",
|
|
20250
|
+
auth: "admin"
|
|
20251
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20252
|
+
kind: "query",
|
|
20253
|
+
auth: "admin"
|
|
19781
20254
|
});
|
|
19782
20255
|
/**
|
|
19783
20256
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22899,6 +23372,12 @@ Object.freeze({
|
|
|
22899
23372
|
addonId: null,
|
|
22900
23373
|
access: "delete"
|
|
22901
23374
|
},
|
|
23375
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23376
|
+
capName: "pipeline-analytics",
|
|
23377
|
+
capScope: "device",
|
|
23378
|
+
addonId: null,
|
|
23379
|
+
access: "delete"
|
|
23380
|
+
},
|
|
22902
23381
|
"pipelineAnalytics.deleteTracks": {
|
|
22903
23382
|
capName: "pipeline-analytics",
|
|
22904
23383
|
capScope: "device",
|
|
@@ -22929,6 +23408,12 @@ Object.freeze({
|
|
|
22929
23408
|
addonId: null,
|
|
22930
23409
|
access: "view"
|
|
22931
23410
|
},
|
|
23411
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23412
|
+
capName: "pipeline-analytics",
|
|
23413
|
+
capScope: "device",
|
|
23414
|
+
addonId: null,
|
|
23415
|
+
access: "view"
|
|
23416
|
+
},
|
|
22932
23417
|
"pipelineAnalytics.getKeyEvents": {
|
|
22933
23418
|
capName: "pipeline-analytics",
|
|
22934
23419
|
capScope: "device",
|
|
@@ -22971,6 +23456,12 @@ Object.freeze({
|
|
|
22971
23456
|
addonId: null,
|
|
22972
23457
|
access: "view"
|
|
22973
23458
|
},
|
|
23459
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23460
|
+
capName: "pipeline-analytics",
|
|
23461
|
+
capScope: "device",
|
|
23462
|
+
addonId: null,
|
|
23463
|
+
access: "view"
|
|
23464
|
+
},
|
|
22974
23465
|
"pipelineAnalytics.listRecentTracks": {
|
|
22975
23466
|
capName: "pipeline-analytics",
|
|
22976
23467
|
capScope: "device",
|
|
@@ -22983,6 +23474,12 @@ Object.freeze({
|
|
|
22983
23474
|
addonId: null,
|
|
22984
23475
|
access: "view"
|
|
22985
23476
|
},
|
|
23477
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23478
|
+
capName: "pipeline-analytics",
|
|
23479
|
+
capScope: "device",
|
|
23480
|
+
addonId: null,
|
|
23481
|
+
access: "create"
|
|
23482
|
+
},
|
|
22986
23483
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22987
23484
|
capName: "pipeline-analytics",
|
|
22988
23485
|
capScope: "device",
|
|
@@ -23745,6 +24242,12 @@ Object.freeze({
|
|
|
23745
24242
|
addonId: null,
|
|
23746
24243
|
access: "create"
|
|
23747
24244
|
},
|
|
24245
|
+
"recording.deleteFootprint": {
|
|
24246
|
+
capName: "recording",
|
|
24247
|
+
capScope: "system",
|
|
24248
|
+
addonId: null,
|
|
24249
|
+
access: "delete"
|
|
24250
|
+
},
|
|
23748
24251
|
"recording.getAvailability": {
|
|
23749
24252
|
capName: "recording",
|
|
23750
24253
|
capScope: "system",
|
|
@@ -23775,6 +24278,12 @@ Object.freeze({
|
|
|
23775
24278
|
addonId: null,
|
|
23776
24279
|
access: "view"
|
|
23777
24280
|
},
|
|
24281
|
+
"recording.listOpsLog": {
|
|
24282
|
+
capName: "recording",
|
|
24283
|
+
capScope: "system",
|
|
24284
|
+
addonId: null,
|
|
24285
|
+
access: "view"
|
|
24286
|
+
},
|
|
23778
24287
|
"recording.locateSegment": {
|
|
23779
24288
|
capName: "recording",
|
|
23780
24289
|
capScope: "system",
|
package/dist/addon.mjs
CHANGED
|
@@ -7445,6 +7445,62 @@ var RecordingConfigSchema = object({
|
|
|
7445
7445
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7446
7446
|
});
|
|
7447
7447
|
/**
|
|
7448
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7449
|
+
* recordings and events management surfaces.
|
|
7450
|
+
*
|
|
7451
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7452
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7453
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7454
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7455
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7456
|
+
* never fail the operation it records.
|
|
7457
|
+
*/
|
|
7458
|
+
/** Which management domain the operation belongs to. */
|
|
7459
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7460
|
+
/** The kind of management operation performed. */
|
|
7461
|
+
var OpsLogOpSchema = _enum([
|
|
7462
|
+
"prune",
|
|
7463
|
+
"manual-delete",
|
|
7464
|
+
"rescan",
|
|
7465
|
+
"retention-run"
|
|
7466
|
+
]);
|
|
7467
|
+
/** Why the operation ran. */
|
|
7468
|
+
var OpsLogReasonSchema = _enum([
|
|
7469
|
+
"retention",
|
|
7470
|
+
"quota",
|
|
7471
|
+
"manual",
|
|
7472
|
+
"operator"
|
|
7473
|
+
]);
|
|
7474
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7475
|
+
var OpsLogEntrySchema = object({
|
|
7476
|
+
/** Unique row id. */
|
|
7477
|
+
id: string(),
|
|
7478
|
+
/** Epoch ms the operation completed. */
|
|
7479
|
+
at: number(),
|
|
7480
|
+
domain: OpsLogDomainSchema,
|
|
7481
|
+
op: OpsLogOpSchema,
|
|
7482
|
+
reason: OpsLogReasonSchema,
|
|
7483
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7484
|
+
deviceId: number().nullable(),
|
|
7485
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7486
|
+
nodeId: string(),
|
|
7487
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7488
|
+
itemsAffected: number(),
|
|
7489
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7490
|
+
bytesReclaimed: number(),
|
|
7491
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7492
|
+
detail: string().nullable(),
|
|
7493
|
+
/** Who/what triggered the op. */
|
|
7494
|
+
actor: string()
|
|
7495
|
+
});
|
|
7496
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7497
|
+
var OpsLogQueryInputSchema = object({
|
|
7498
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7499
|
+
deviceId: number().optional(),
|
|
7500
|
+
/** Max rows returned, newest-first. */
|
|
7501
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7502
|
+
});
|
|
7503
|
+
/**
|
|
7448
7504
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7449
7505
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7450
7506
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7688,6 +7744,160 @@ var EncodeProfileSchema = object({
|
|
|
7688
7744
|
*/
|
|
7689
7745
|
outputArgs: array(string()).optional()
|
|
7690
7746
|
});
|
|
7747
|
+
var COCO_TO_MACRO = {
|
|
7748
|
+
mapping: {
|
|
7749
|
+
person: "person",
|
|
7750
|
+
bicycle: "vehicle",
|
|
7751
|
+
car: "vehicle",
|
|
7752
|
+
motorcycle: "vehicle",
|
|
7753
|
+
airplane: "vehicle",
|
|
7754
|
+
bus: "vehicle",
|
|
7755
|
+
train: "vehicle",
|
|
7756
|
+
truck: "vehicle",
|
|
7757
|
+
boat: "vehicle",
|
|
7758
|
+
bird: "animal",
|
|
7759
|
+
cat: "animal",
|
|
7760
|
+
dog: "animal",
|
|
7761
|
+
horse: "animal",
|
|
7762
|
+
sheep: "animal",
|
|
7763
|
+
cow: "animal",
|
|
7764
|
+
elephant: "animal",
|
|
7765
|
+
bear: "animal",
|
|
7766
|
+
zebra: "animal",
|
|
7767
|
+
giraffe: "animal",
|
|
7768
|
+
suitcase: "package",
|
|
7769
|
+
backpack: "package",
|
|
7770
|
+
handbag: "package"
|
|
7771
|
+
},
|
|
7772
|
+
preserveOriginal: false
|
|
7773
|
+
};
|
|
7774
|
+
var AUDIO_MACRO_LABELS = [
|
|
7775
|
+
{
|
|
7776
|
+
id: "speech",
|
|
7777
|
+
name: "Speech",
|
|
7778
|
+
icon: "🗣️"
|
|
7779
|
+
},
|
|
7780
|
+
{
|
|
7781
|
+
id: "scream",
|
|
7782
|
+
name: "Scream / Shout",
|
|
7783
|
+
icon: "😱"
|
|
7784
|
+
},
|
|
7785
|
+
{
|
|
7786
|
+
id: "crying",
|
|
7787
|
+
name: "Crying / Baby",
|
|
7788
|
+
icon: "😢"
|
|
7789
|
+
},
|
|
7790
|
+
{
|
|
7791
|
+
id: "laughter",
|
|
7792
|
+
name: "Laughter",
|
|
7793
|
+
icon: "😂"
|
|
7794
|
+
},
|
|
7795
|
+
{
|
|
7796
|
+
id: "music",
|
|
7797
|
+
name: "Music",
|
|
7798
|
+
icon: "🎵"
|
|
7799
|
+
},
|
|
7800
|
+
{
|
|
7801
|
+
id: "dog",
|
|
7802
|
+
name: "Dog",
|
|
7803
|
+
icon: "🐕"
|
|
7804
|
+
},
|
|
7805
|
+
{
|
|
7806
|
+
id: "cat",
|
|
7807
|
+
name: "Cat",
|
|
7808
|
+
icon: "🐈"
|
|
7809
|
+
},
|
|
7810
|
+
{
|
|
7811
|
+
id: "bird",
|
|
7812
|
+
name: "Bird",
|
|
7813
|
+
icon: "🐦"
|
|
7814
|
+
},
|
|
7815
|
+
{
|
|
7816
|
+
id: "animal",
|
|
7817
|
+
name: "Animal (other)",
|
|
7818
|
+
icon: "🐾"
|
|
7819
|
+
},
|
|
7820
|
+
{
|
|
7821
|
+
id: "alarm",
|
|
7822
|
+
name: "Alarm / Siren",
|
|
7823
|
+
icon: "🚨"
|
|
7824
|
+
},
|
|
7825
|
+
{
|
|
7826
|
+
id: "doorbell",
|
|
7827
|
+
name: "Doorbell / Knock",
|
|
7828
|
+
icon: "🔔"
|
|
7829
|
+
},
|
|
7830
|
+
{
|
|
7831
|
+
id: "glass_breaking",
|
|
7832
|
+
name: "Glass Breaking",
|
|
7833
|
+
icon: "💥"
|
|
7834
|
+
},
|
|
7835
|
+
{
|
|
7836
|
+
id: "gunshot",
|
|
7837
|
+
name: "Gunshot / Explosion",
|
|
7838
|
+
icon: "💣"
|
|
7839
|
+
},
|
|
7840
|
+
{
|
|
7841
|
+
id: "vehicle",
|
|
7842
|
+
name: "Vehicle",
|
|
7843
|
+
icon: "🚗"
|
|
7844
|
+
},
|
|
7845
|
+
{
|
|
7846
|
+
id: "siren",
|
|
7847
|
+
name: "Emergency Siren",
|
|
7848
|
+
icon: "🚑"
|
|
7849
|
+
},
|
|
7850
|
+
{
|
|
7851
|
+
id: "fire",
|
|
7852
|
+
name: "Fire / Smoke",
|
|
7853
|
+
icon: "🔥"
|
|
7854
|
+
},
|
|
7855
|
+
{
|
|
7856
|
+
id: "water",
|
|
7857
|
+
name: "Water",
|
|
7858
|
+
icon: "💧"
|
|
7859
|
+
},
|
|
7860
|
+
{
|
|
7861
|
+
id: "wind",
|
|
7862
|
+
name: "Wind / Weather",
|
|
7863
|
+
icon: "🌬️"
|
|
7864
|
+
},
|
|
7865
|
+
{
|
|
7866
|
+
id: "door",
|
|
7867
|
+
name: "Door",
|
|
7868
|
+
icon: "🚪"
|
|
7869
|
+
},
|
|
7870
|
+
{
|
|
7871
|
+
id: "footsteps",
|
|
7872
|
+
name: "Footsteps",
|
|
7873
|
+
icon: "👣"
|
|
7874
|
+
},
|
|
7875
|
+
{
|
|
7876
|
+
id: "crowd",
|
|
7877
|
+
name: "Crowd / Chatter",
|
|
7878
|
+
icon: "👥"
|
|
7879
|
+
},
|
|
7880
|
+
{
|
|
7881
|
+
id: "telephone",
|
|
7882
|
+
name: "Telephone",
|
|
7883
|
+
icon: "📞"
|
|
7884
|
+
},
|
|
7885
|
+
{
|
|
7886
|
+
id: "engine",
|
|
7887
|
+
name: "Engine / Motor",
|
|
7888
|
+
icon: "⚙️"
|
|
7889
|
+
},
|
|
7890
|
+
{
|
|
7891
|
+
id: "tools",
|
|
7892
|
+
name: "Tools / Construction",
|
|
7893
|
+
icon: "🔨"
|
|
7894
|
+
},
|
|
7895
|
+
{
|
|
7896
|
+
id: "silence",
|
|
7897
|
+
name: "Silence",
|
|
7898
|
+
icon: "🤫"
|
|
7899
|
+
}
|
|
7900
|
+
];
|
|
7691
7901
|
var YAMNET_TO_MACRO = {
|
|
7692
7902
|
mapping: {
|
|
7693
7903
|
Speech: "speech",
|
|
@@ -7954,6 +8164,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7954
8164
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7955
8165
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7956
8166
|
/**
|
|
8167
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8168
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8169
|
+
* icon }`.
|
|
8170
|
+
*
|
|
8171
|
+
* This dictionary folds together what used to be scattered across four
|
|
8172
|
+
* copies:
|
|
8173
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8174
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8175
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8176
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8177
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8178
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8179
|
+
*
|
|
8180
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8181
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8182
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8183
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8184
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8185
|
+
*
|
|
8186
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8187
|
+
*/
|
|
8188
|
+
var TAXONOMY_COLORS = {
|
|
8189
|
+
motion: "#f59e0b",
|
|
8190
|
+
audio: "#06b6d4",
|
|
8191
|
+
person: "#22c55e",
|
|
8192
|
+
vehicle: "#3b82f6",
|
|
8193
|
+
animal: "#f97316",
|
|
8194
|
+
package: "#a855f7",
|
|
8195
|
+
sensor: "#8b5cf6",
|
|
8196
|
+
control: "#10b981",
|
|
8197
|
+
genericDetection: "#64748b"
|
|
8198
|
+
};
|
|
8199
|
+
var DETECTION_SUB_COLORS = {
|
|
8200
|
+
car: "#f59e0b",
|
|
8201
|
+
truck: "#d97706",
|
|
8202
|
+
bus: "#b45309",
|
|
8203
|
+
motorcycle: "#eab308",
|
|
8204
|
+
bicycle: "#ca8a04",
|
|
8205
|
+
airplane: "#60a5fa",
|
|
8206
|
+
boat: "#2563eb",
|
|
8207
|
+
train: "#1d4ed8",
|
|
8208
|
+
bird: "#14b8a6",
|
|
8209
|
+
dog: "#84cc16",
|
|
8210
|
+
cat: "#f97316",
|
|
8211
|
+
horse: "#a16207",
|
|
8212
|
+
sheep: "#a3a3a3",
|
|
8213
|
+
cow: "#78716c",
|
|
8214
|
+
elephant: "#6b7280",
|
|
8215
|
+
bear: "#7c2d12",
|
|
8216
|
+
zebra: "#404040",
|
|
8217
|
+
giraffe: "#d4a373"
|
|
8218
|
+
};
|
|
8219
|
+
function titleCase(id) {
|
|
8220
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8221
|
+
}
|
|
8222
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8223
|
+
function macro(kind, category, color, iconId, label) {
|
|
8224
|
+
entries.set(kind, {
|
|
8225
|
+
kind,
|
|
8226
|
+
parentKind: null,
|
|
8227
|
+
level: "macro",
|
|
8228
|
+
category,
|
|
8229
|
+
color,
|
|
8230
|
+
iconId,
|
|
8231
|
+
labelKey: `eventKind.${kind}`,
|
|
8232
|
+
label
|
|
8233
|
+
});
|
|
8234
|
+
}
|
|
8235
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8236
|
+
entries.set(kind, {
|
|
8237
|
+
kind,
|
|
8238
|
+
parentKind,
|
|
8239
|
+
level: "sub",
|
|
8240
|
+
category,
|
|
8241
|
+
color,
|
|
8242
|
+
iconId,
|
|
8243
|
+
labelKey: `eventKind.${kind}`,
|
|
8244
|
+
label
|
|
8245
|
+
});
|
|
8246
|
+
}
|
|
8247
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8248
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8249
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8250
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8251
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8252
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8253
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8254
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8255
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8256
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8257
|
+
if (entries.has(cocoClass)) continue;
|
|
8258
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8259
|
+
}
|
|
8260
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8261
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8262
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8263
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8264
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8265
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8266
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8267
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8268
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8269
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8270
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8271
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8272
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8273
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8274
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8275
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8276
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8277
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8278
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8279
|
+
const kind = `audio-${l.id}`;
|
|
8280
|
+
if (entries.has(kind)) continue;
|
|
8281
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8282
|
+
}
|
|
8283
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8284
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8285
|
+
/**
|
|
7957
8286
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7958
8287
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7959
8288
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -16129,17 +16458,30 @@ var EventKindCategorySchema = _enum([
|
|
|
16129
16458
|
"audio",
|
|
16130
16459
|
"detection",
|
|
16131
16460
|
"sensor",
|
|
16461
|
+
"control",
|
|
16132
16462
|
"custom",
|
|
16133
16463
|
"package"
|
|
16134
16464
|
]);
|
|
16465
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16466
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
16135
16467
|
var EventKindDescriptorSchema = object({
|
|
16136
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16468
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
16137
16469
|
kind: string(),
|
|
16470
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16471
|
+
labelKey: string(),
|
|
16472
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
16138
16473
|
label: string(),
|
|
16139
16474
|
/** Hex color for timeline/legend rendering. */
|
|
16140
16475
|
color: string(),
|
|
16476
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16477
|
+
iconId: string(),
|
|
16478
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
16141
16479
|
icon: EventKindIconSchema,
|
|
16142
16480
|
category: EventKindCategorySchema,
|
|
16481
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16482
|
+
parentKind: string().nullable(),
|
|
16483
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16484
|
+
level: EventKindLevelSchema,
|
|
16143
16485
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
16144
16486
|
* itself; for sensor kinds the LINKED source device. */
|
|
16145
16487
|
source: object({
|
|
@@ -16212,11 +16554,21 @@ var TrackAudioLabelSchema = object({
|
|
|
16212
16554
|
firstAt: number(),
|
|
16213
16555
|
lastAt: number()
|
|
16214
16556
|
});
|
|
16557
|
+
/**
|
|
16558
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16559
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16560
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16561
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16562
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16563
|
+
*/
|
|
16564
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
16215
16565
|
var TrackSchema = object({
|
|
16216
16566
|
trackId: string(),
|
|
16217
16567
|
deviceId: number(),
|
|
16218
16568
|
className: string(),
|
|
16219
16569
|
label: string().optional(),
|
|
16570
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16571
|
+
source: TrackSourceSchema.optional(),
|
|
16220
16572
|
firstSeen: number(),
|
|
16221
16573
|
lastSeen: number(),
|
|
16222
16574
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16471,6 +16823,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16471
16823
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16472
16824
|
embeddings: number().int()
|
|
16473
16825
|
});
|
|
16826
|
+
/** Event-store footprint for one camera. */
|
|
16827
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16828
|
+
deviceId: number(),
|
|
16829
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16830
|
+
rows: number().int(),
|
|
16831
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16832
|
+
bytes: number().int()
|
|
16833
|
+
});
|
|
16834
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16835
|
+
var EventStoreFootprintSchema = object({
|
|
16836
|
+
totalRows: number().int(),
|
|
16837
|
+
totalBytes: number().int(),
|
|
16838
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16839
|
+
});
|
|
16840
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16841
|
+
var EventPruneCountsSchema = object({
|
|
16842
|
+
motion: number().int(),
|
|
16843
|
+
object: number().int(),
|
|
16844
|
+
audio: number().int()
|
|
16845
|
+
});
|
|
16474
16846
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16475
16847
|
deviceId: number(),
|
|
16476
16848
|
trackId: string()
|
|
@@ -16534,6 +16906,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16534
16906
|
}), {
|
|
16535
16907
|
kind: "mutation",
|
|
16536
16908
|
auth: "admin"
|
|
16909
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16910
|
+
kind: "query",
|
|
16911
|
+
auth: "admin"
|
|
16912
|
+
}), method(object({
|
|
16913
|
+
olderThanMs: number(),
|
|
16914
|
+
reason: OpsLogReasonSchema.optional()
|
|
16915
|
+
}), EventPruneCountsSchema, {
|
|
16916
|
+
kind: "mutation",
|
|
16917
|
+
auth: "admin"
|
|
16918
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16919
|
+
kind: "mutation",
|
|
16920
|
+
auth: "admin"
|
|
16921
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16922
|
+
kind: "query",
|
|
16923
|
+
auth: "admin"
|
|
16537
16924
|
}), method(object({
|
|
16538
16925
|
eventId: string(),
|
|
16539
16926
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16558,6 +16945,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16558
16945
|
eventId: string(),
|
|
16559
16946
|
timestamp: number()
|
|
16560
16947
|
});
|
|
16948
|
+
/**
|
|
16949
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16950
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16951
|
+
* caps into per-camera event-kind descriptors.
|
|
16952
|
+
*
|
|
16953
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16954
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16955
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16956
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16957
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16958
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16959
|
+
* eventful cap is missing.
|
|
16960
|
+
*/
|
|
16961
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16962
|
+
var LEGACY_ICON = {
|
|
16963
|
+
motion: "motion",
|
|
16964
|
+
audio: "audio",
|
|
16965
|
+
person: "person",
|
|
16966
|
+
vehicle: "vehicle",
|
|
16967
|
+
animal: "animal",
|
|
16968
|
+
package: "package",
|
|
16969
|
+
door: "door",
|
|
16970
|
+
pir: "pir",
|
|
16971
|
+
smoke: "smoke",
|
|
16972
|
+
water: "water",
|
|
16973
|
+
button: "button",
|
|
16974
|
+
generic: "generic",
|
|
16975
|
+
gas: "smoke",
|
|
16976
|
+
vibration: "generic",
|
|
16977
|
+
tamper: "generic",
|
|
16978
|
+
presence: "person",
|
|
16979
|
+
lock: "generic",
|
|
16980
|
+
siren: "generic",
|
|
16981
|
+
switch: "generic",
|
|
16982
|
+
doorbell: "button"
|
|
16983
|
+
};
|
|
16984
|
+
function legacyIcon(iconId) {
|
|
16985
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16986
|
+
}
|
|
16987
|
+
/**
|
|
16988
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16989
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16990
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16991
|
+
*/
|
|
16992
|
+
var CAP_TO_KIND = {
|
|
16993
|
+
contact: "contact",
|
|
16994
|
+
motion: "motion-sensor",
|
|
16995
|
+
smoke: "smoke",
|
|
16996
|
+
flood: "flood",
|
|
16997
|
+
gas: "gas",
|
|
16998
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16999
|
+
vibration: "vibration",
|
|
17000
|
+
tamper: "tamper",
|
|
17001
|
+
presence: "presence",
|
|
17002
|
+
"enum-sensor": "enum-sensor",
|
|
17003
|
+
"event-emitter": "device-event",
|
|
17004
|
+
"lock-control": "lock",
|
|
17005
|
+
switch: "switch",
|
|
17006
|
+
button: "button",
|
|
17007
|
+
doorbell: "doorbell"
|
|
17008
|
+
};
|
|
17009
|
+
function buildDescriptor(capName, kind) {
|
|
17010
|
+
const t = EVENT_TAXONOMY[kind];
|
|
17011
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
17012
|
+
return {
|
|
17013
|
+
...t,
|
|
17014
|
+
icon: legacyIcon(t.iconId)
|
|
17015
|
+
};
|
|
17016
|
+
}
|
|
17017
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16561
17018
|
var CameraPipelineConfigSchema = object({
|
|
16562
17019
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16563
17020
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19767,13 +20224,29 @@ method(object({
|
|
|
19767
20224
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19768
20225
|
kind: "mutation",
|
|
19769
20226
|
auth: "admin"
|
|
19770
|
-
}), method(object({
|
|
20227
|
+
}), method(object({
|
|
20228
|
+
deviceId: number(),
|
|
20229
|
+
reason: OpsLogReasonSchema.optional()
|
|
20230
|
+
}), object({
|
|
19771
20231
|
floorMs: number().nullable(),
|
|
19772
20232
|
deletedBuckets: number().int(),
|
|
19773
20233
|
reclaimedBytes: number().int()
|
|
19774
20234
|
}), {
|
|
19775
20235
|
kind: "mutation",
|
|
19776
20236
|
auth: "admin"
|
|
20237
|
+
}), method(object({
|
|
20238
|
+
deviceId: number(),
|
|
20239
|
+
fromMs: number().optional(),
|
|
20240
|
+
toMs: number().optional()
|
|
20241
|
+
}), object({
|
|
20242
|
+
deletedBuckets: number().int(),
|
|
20243
|
+
reclaimedBytes: number().int()
|
|
20244
|
+
}), {
|
|
20245
|
+
kind: "mutation",
|
|
20246
|
+
auth: "admin"
|
|
20247
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20248
|
+
kind: "query",
|
|
20249
|
+
auth: "admin"
|
|
19777
20250
|
});
|
|
19778
20251
|
/**
|
|
19779
20252
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22895,6 +23368,12 @@ Object.freeze({
|
|
|
22895
23368
|
addonId: null,
|
|
22896
23369
|
access: "delete"
|
|
22897
23370
|
},
|
|
23371
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23372
|
+
capName: "pipeline-analytics",
|
|
23373
|
+
capScope: "device",
|
|
23374
|
+
addonId: null,
|
|
23375
|
+
access: "delete"
|
|
23376
|
+
},
|
|
22898
23377
|
"pipelineAnalytics.deleteTracks": {
|
|
22899
23378
|
capName: "pipeline-analytics",
|
|
22900
23379
|
capScope: "device",
|
|
@@ -22925,6 +23404,12 @@ Object.freeze({
|
|
|
22925
23404
|
addonId: null,
|
|
22926
23405
|
access: "view"
|
|
22927
23406
|
},
|
|
23407
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23408
|
+
capName: "pipeline-analytics",
|
|
23409
|
+
capScope: "device",
|
|
23410
|
+
addonId: null,
|
|
23411
|
+
access: "view"
|
|
23412
|
+
},
|
|
22928
23413
|
"pipelineAnalytics.getKeyEvents": {
|
|
22929
23414
|
capName: "pipeline-analytics",
|
|
22930
23415
|
capScope: "device",
|
|
@@ -22967,6 +23452,12 @@ Object.freeze({
|
|
|
22967
23452
|
addonId: null,
|
|
22968
23453
|
access: "view"
|
|
22969
23454
|
},
|
|
23455
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23456
|
+
capName: "pipeline-analytics",
|
|
23457
|
+
capScope: "device",
|
|
23458
|
+
addonId: null,
|
|
23459
|
+
access: "view"
|
|
23460
|
+
},
|
|
22970
23461
|
"pipelineAnalytics.listRecentTracks": {
|
|
22971
23462
|
capName: "pipeline-analytics",
|
|
22972
23463
|
capScope: "device",
|
|
@@ -22979,6 +23470,12 @@ Object.freeze({
|
|
|
22979
23470
|
addonId: null,
|
|
22980
23471
|
access: "view"
|
|
22981
23472
|
},
|
|
23473
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23474
|
+
capName: "pipeline-analytics",
|
|
23475
|
+
capScope: "device",
|
|
23476
|
+
addonId: null,
|
|
23477
|
+
access: "create"
|
|
23478
|
+
},
|
|
22982
23479
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22983
23480
|
capName: "pipeline-analytics",
|
|
22984
23481
|
capScope: "device",
|
|
@@ -23741,6 +24238,12 @@ Object.freeze({
|
|
|
23741
24238
|
addonId: null,
|
|
23742
24239
|
access: "create"
|
|
23743
24240
|
},
|
|
24241
|
+
"recording.deleteFootprint": {
|
|
24242
|
+
capName: "recording",
|
|
24243
|
+
capScope: "system",
|
|
24244
|
+
addonId: null,
|
|
24245
|
+
access: "delete"
|
|
24246
|
+
},
|
|
23744
24247
|
"recording.getAvailability": {
|
|
23745
24248
|
capName: "recording",
|
|
23746
24249
|
capScope: "system",
|
|
@@ -23771,6 +24274,12 @@ Object.freeze({
|
|
|
23771
24274
|
addonId: null,
|
|
23772
24275
|
access: "view"
|
|
23773
24276
|
},
|
|
24277
|
+
"recording.listOpsLog": {
|
|
24278
|
+
capName: "recording",
|
|
24279
|
+
capScope: "system",
|
|
24280
|
+
addonId: null,
|
|
24281
|
+
access: "view"
|
|
24282
|
+
},
|
|
23774
24283
|
"recording.locateSegment": {
|
|
23775
24284
|
capName: "recording",
|
|
23776
24285
|
capScope: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-notifiers",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.30",
|
|
4
4
|
"description": "System notifiers addon for CamStack — a `notification-output` collection provider hosting per-kind notifier adapters (ntfy, pushover, gotify, telegram, discord, webhook, zentik).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|