@camstack/addon-ai 0.1.6 → 0.1.8
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
|
@@ -7372,6 +7372,62 @@ var RecordingConfigSchema = object({
|
|
|
7372
7372
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7373
7373
|
});
|
|
7374
7374
|
/**
|
|
7375
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7376
|
+
* recordings and events management surfaces.
|
|
7377
|
+
*
|
|
7378
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7379
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7380
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7381
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7382
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7383
|
+
* never fail the operation it records.
|
|
7384
|
+
*/
|
|
7385
|
+
/** Which management domain the operation belongs to. */
|
|
7386
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7387
|
+
/** The kind of management operation performed. */
|
|
7388
|
+
var OpsLogOpSchema = _enum([
|
|
7389
|
+
"prune",
|
|
7390
|
+
"manual-delete",
|
|
7391
|
+
"rescan",
|
|
7392
|
+
"retention-run"
|
|
7393
|
+
]);
|
|
7394
|
+
/** Why the operation ran. */
|
|
7395
|
+
var OpsLogReasonSchema = _enum([
|
|
7396
|
+
"retention",
|
|
7397
|
+
"quota",
|
|
7398
|
+
"manual",
|
|
7399
|
+
"operator"
|
|
7400
|
+
]);
|
|
7401
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7402
|
+
var OpsLogEntrySchema = object({
|
|
7403
|
+
/** Unique row id. */
|
|
7404
|
+
id: string(),
|
|
7405
|
+
/** Epoch ms the operation completed. */
|
|
7406
|
+
at: number(),
|
|
7407
|
+
domain: OpsLogDomainSchema,
|
|
7408
|
+
op: OpsLogOpSchema,
|
|
7409
|
+
reason: OpsLogReasonSchema,
|
|
7410
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7411
|
+
deviceId: number().nullable(),
|
|
7412
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7413
|
+
nodeId: string(),
|
|
7414
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7415
|
+
itemsAffected: number(),
|
|
7416
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7417
|
+
bytesReclaimed: number(),
|
|
7418
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7419
|
+
detail: string().nullable(),
|
|
7420
|
+
/** Who/what triggered the op. */
|
|
7421
|
+
actor: string()
|
|
7422
|
+
});
|
|
7423
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7424
|
+
var OpsLogQueryInputSchema = object({
|
|
7425
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7426
|
+
deviceId: number().optional(),
|
|
7427
|
+
/** Max rows returned, newest-first. */
|
|
7428
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7429
|
+
});
|
|
7430
|
+
/**
|
|
7375
7431
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7376
7432
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7377
7433
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7645,6 +7701,160 @@ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
|
|
|
7645
7701
|
function nodePin(nodeId) {
|
|
7646
7702
|
return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
|
|
7647
7703
|
}
|
|
7704
|
+
var COCO_TO_MACRO = {
|
|
7705
|
+
mapping: {
|
|
7706
|
+
person: "person",
|
|
7707
|
+
bicycle: "vehicle",
|
|
7708
|
+
car: "vehicle",
|
|
7709
|
+
motorcycle: "vehicle",
|
|
7710
|
+
airplane: "vehicle",
|
|
7711
|
+
bus: "vehicle",
|
|
7712
|
+
train: "vehicle",
|
|
7713
|
+
truck: "vehicle",
|
|
7714
|
+
boat: "vehicle",
|
|
7715
|
+
bird: "animal",
|
|
7716
|
+
cat: "animal",
|
|
7717
|
+
dog: "animal",
|
|
7718
|
+
horse: "animal",
|
|
7719
|
+
sheep: "animal",
|
|
7720
|
+
cow: "animal",
|
|
7721
|
+
elephant: "animal",
|
|
7722
|
+
bear: "animal",
|
|
7723
|
+
zebra: "animal",
|
|
7724
|
+
giraffe: "animal",
|
|
7725
|
+
suitcase: "package",
|
|
7726
|
+
backpack: "package",
|
|
7727
|
+
handbag: "package"
|
|
7728
|
+
},
|
|
7729
|
+
preserveOriginal: false
|
|
7730
|
+
};
|
|
7731
|
+
var AUDIO_MACRO_LABELS = [
|
|
7732
|
+
{
|
|
7733
|
+
id: "speech",
|
|
7734
|
+
name: "Speech",
|
|
7735
|
+
icon: "🗣️"
|
|
7736
|
+
},
|
|
7737
|
+
{
|
|
7738
|
+
id: "scream",
|
|
7739
|
+
name: "Scream / Shout",
|
|
7740
|
+
icon: "😱"
|
|
7741
|
+
},
|
|
7742
|
+
{
|
|
7743
|
+
id: "crying",
|
|
7744
|
+
name: "Crying / Baby",
|
|
7745
|
+
icon: "😢"
|
|
7746
|
+
},
|
|
7747
|
+
{
|
|
7748
|
+
id: "laughter",
|
|
7749
|
+
name: "Laughter",
|
|
7750
|
+
icon: "😂"
|
|
7751
|
+
},
|
|
7752
|
+
{
|
|
7753
|
+
id: "music",
|
|
7754
|
+
name: "Music",
|
|
7755
|
+
icon: "🎵"
|
|
7756
|
+
},
|
|
7757
|
+
{
|
|
7758
|
+
id: "dog",
|
|
7759
|
+
name: "Dog",
|
|
7760
|
+
icon: "🐕"
|
|
7761
|
+
},
|
|
7762
|
+
{
|
|
7763
|
+
id: "cat",
|
|
7764
|
+
name: "Cat",
|
|
7765
|
+
icon: "🐈"
|
|
7766
|
+
},
|
|
7767
|
+
{
|
|
7768
|
+
id: "bird",
|
|
7769
|
+
name: "Bird",
|
|
7770
|
+
icon: "🐦"
|
|
7771
|
+
},
|
|
7772
|
+
{
|
|
7773
|
+
id: "animal",
|
|
7774
|
+
name: "Animal (other)",
|
|
7775
|
+
icon: "🐾"
|
|
7776
|
+
},
|
|
7777
|
+
{
|
|
7778
|
+
id: "alarm",
|
|
7779
|
+
name: "Alarm / Siren",
|
|
7780
|
+
icon: "🚨"
|
|
7781
|
+
},
|
|
7782
|
+
{
|
|
7783
|
+
id: "doorbell",
|
|
7784
|
+
name: "Doorbell / Knock",
|
|
7785
|
+
icon: "🔔"
|
|
7786
|
+
},
|
|
7787
|
+
{
|
|
7788
|
+
id: "glass_breaking",
|
|
7789
|
+
name: "Glass Breaking",
|
|
7790
|
+
icon: "💥"
|
|
7791
|
+
},
|
|
7792
|
+
{
|
|
7793
|
+
id: "gunshot",
|
|
7794
|
+
name: "Gunshot / Explosion",
|
|
7795
|
+
icon: "💣"
|
|
7796
|
+
},
|
|
7797
|
+
{
|
|
7798
|
+
id: "vehicle",
|
|
7799
|
+
name: "Vehicle",
|
|
7800
|
+
icon: "🚗"
|
|
7801
|
+
},
|
|
7802
|
+
{
|
|
7803
|
+
id: "siren",
|
|
7804
|
+
name: "Emergency Siren",
|
|
7805
|
+
icon: "🚑"
|
|
7806
|
+
},
|
|
7807
|
+
{
|
|
7808
|
+
id: "fire",
|
|
7809
|
+
name: "Fire / Smoke",
|
|
7810
|
+
icon: "🔥"
|
|
7811
|
+
},
|
|
7812
|
+
{
|
|
7813
|
+
id: "water",
|
|
7814
|
+
name: "Water",
|
|
7815
|
+
icon: "💧"
|
|
7816
|
+
},
|
|
7817
|
+
{
|
|
7818
|
+
id: "wind",
|
|
7819
|
+
name: "Wind / Weather",
|
|
7820
|
+
icon: "🌬️"
|
|
7821
|
+
},
|
|
7822
|
+
{
|
|
7823
|
+
id: "door",
|
|
7824
|
+
name: "Door",
|
|
7825
|
+
icon: "🚪"
|
|
7826
|
+
},
|
|
7827
|
+
{
|
|
7828
|
+
id: "footsteps",
|
|
7829
|
+
name: "Footsteps",
|
|
7830
|
+
icon: "👣"
|
|
7831
|
+
},
|
|
7832
|
+
{
|
|
7833
|
+
id: "crowd",
|
|
7834
|
+
name: "Crowd / Chatter",
|
|
7835
|
+
icon: "👥"
|
|
7836
|
+
},
|
|
7837
|
+
{
|
|
7838
|
+
id: "telephone",
|
|
7839
|
+
name: "Telephone",
|
|
7840
|
+
icon: "📞"
|
|
7841
|
+
},
|
|
7842
|
+
{
|
|
7843
|
+
id: "engine",
|
|
7844
|
+
name: "Engine / Motor",
|
|
7845
|
+
icon: "⚙️"
|
|
7846
|
+
},
|
|
7847
|
+
{
|
|
7848
|
+
id: "tools",
|
|
7849
|
+
name: "Tools / Construction",
|
|
7850
|
+
icon: "🔨"
|
|
7851
|
+
},
|
|
7852
|
+
{
|
|
7853
|
+
id: "silence",
|
|
7854
|
+
name: "Silence",
|
|
7855
|
+
icon: "🤫"
|
|
7856
|
+
}
|
|
7857
|
+
];
|
|
7648
7858
|
var YAMNET_TO_MACRO = {
|
|
7649
7859
|
mapping: {
|
|
7650
7860
|
Speech: "speech",
|
|
@@ -7911,6 +8121,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7911
8121
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7912
8122
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7913
8123
|
/**
|
|
8124
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8125
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8126
|
+
* icon }`.
|
|
8127
|
+
*
|
|
8128
|
+
* This dictionary folds together what used to be scattered across four
|
|
8129
|
+
* copies:
|
|
8130
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8131
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8132
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8133
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8134
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8135
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8136
|
+
*
|
|
8137
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8138
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8139
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8140
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8141
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8142
|
+
*
|
|
8143
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8144
|
+
*/
|
|
8145
|
+
var TAXONOMY_COLORS = {
|
|
8146
|
+
motion: "#f59e0b",
|
|
8147
|
+
audio: "#06b6d4",
|
|
8148
|
+
person: "#22c55e",
|
|
8149
|
+
vehicle: "#3b82f6",
|
|
8150
|
+
animal: "#f97316",
|
|
8151
|
+
package: "#a855f7",
|
|
8152
|
+
sensor: "#8b5cf6",
|
|
8153
|
+
control: "#10b981",
|
|
8154
|
+
genericDetection: "#64748b"
|
|
8155
|
+
};
|
|
8156
|
+
var DETECTION_SUB_COLORS = {
|
|
8157
|
+
car: "#f59e0b",
|
|
8158
|
+
truck: "#d97706",
|
|
8159
|
+
bus: "#b45309",
|
|
8160
|
+
motorcycle: "#eab308",
|
|
8161
|
+
bicycle: "#ca8a04",
|
|
8162
|
+
airplane: "#60a5fa",
|
|
8163
|
+
boat: "#2563eb",
|
|
8164
|
+
train: "#1d4ed8",
|
|
8165
|
+
bird: "#14b8a6",
|
|
8166
|
+
dog: "#84cc16",
|
|
8167
|
+
cat: "#f97316",
|
|
8168
|
+
horse: "#a16207",
|
|
8169
|
+
sheep: "#a3a3a3",
|
|
8170
|
+
cow: "#78716c",
|
|
8171
|
+
elephant: "#6b7280",
|
|
8172
|
+
bear: "#7c2d12",
|
|
8173
|
+
zebra: "#404040",
|
|
8174
|
+
giraffe: "#d4a373"
|
|
8175
|
+
};
|
|
8176
|
+
function titleCase(id) {
|
|
8177
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8178
|
+
}
|
|
8179
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8180
|
+
function macro(kind, category, color, iconId, label) {
|
|
8181
|
+
entries.set(kind, {
|
|
8182
|
+
kind,
|
|
8183
|
+
parentKind: null,
|
|
8184
|
+
level: "macro",
|
|
8185
|
+
category,
|
|
8186
|
+
color,
|
|
8187
|
+
iconId,
|
|
8188
|
+
labelKey: `eventKind.${kind}`,
|
|
8189
|
+
label
|
|
8190
|
+
});
|
|
8191
|
+
}
|
|
8192
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8193
|
+
entries.set(kind, {
|
|
8194
|
+
kind,
|
|
8195
|
+
parentKind,
|
|
8196
|
+
level: "sub",
|
|
8197
|
+
category,
|
|
8198
|
+
color,
|
|
8199
|
+
iconId,
|
|
8200
|
+
labelKey: `eventKind.${kind}`,
|
|
8201
|
+
label
|
|
8202
|
+
});
|
|
8203
|
+
}
|
|
8204
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8205
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8206
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8207
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8208
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8209
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8210
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8211
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8212
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8213
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8214
|
+
if (entries.has(cocoClass)) continue;
|
|
8215
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8216
|
+
}
|
|
8217
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8218
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8219
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8220
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8221
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8222
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8223
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8224
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8225
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8226
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8227
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8228
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8229
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8230
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8231
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8232
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8233
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8234
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8235
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8236
|
+
const kind = `audio-${l.id}`;
|
|
8237
|
+
if (entries.has(kind)) continue;
|
|
8238
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8239
|
+
}
|
|
8240
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8241
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8242
|
+
/**
|
|
7914
8243
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7915
8244
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7916
8245
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15905,17 +16234,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15905
16234
|
"audio",
|
|
15906
16235
|
"detection",
|
|
15907
16236
|
"sensor",
|
|
16237
|
+
"control",
|
|
15908
16238
|
"custom",
|
|
15909
16239
|
"package"
|
|
15910
16240
|
]);
|
|
16241
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16242
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15911
16243
|
var EventKindDescriptorSchema = object({
|
|
15912
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16244
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15913
16245
|
kind: string(),
|
|
16246
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16247
|
+
labelKey: string(),
|
|
16248
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15914
16249
|
label: string(),
|
|
15915
16250
|
/** Hex color for timeline/legend rendering. */
|
|
15916
16251
|
color: string(),
|
|
16252
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16253
|
+
iconId: string(),
|
|
16254
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15917
16255
|
icon: EventKindIconSchema,
|
|
15918
16256
|
category: EventKindCategorySchema,
|
|
16257
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16258
|
+
parentKind: string().nullable(),
|
|
16259
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16260
|
+
level: EventKindLevelSchema,
|
|
15919
16261
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15920
16262
|
* itself; for sensor kinds the LINKED source device. */
|
|
15921
16263
|
source: object({
|
|
@@ -15988,11 +16330,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15988
16330
|
firstAt: number(),
|
|
15989
16331
|
lastAt: number()
|
|
15990
16332
|
});
|
|
16333
|
+
/**
|
|
16334
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16335
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16336
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16337
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16338
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16339
|
+
*/
|
|
16340
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15991
16341
|
var TrackSchema = object({
|
|
15992
16342
|
trackId: string(),
|
|
15993
16343
|
deviceId: number(),
|
|
15994
16344
|
className: string(),
|
|
15995
16345
|
label: string().optional(),
|
|
16346
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16347
|
+
source: TrackSourceSchema.optional(),
|
|
15996
16348
|
firstSeen: number(),
|
|
15997
16349
|
lastSeen: number(),
|
|
15998
16350
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16247,6 +16599,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16247
16599
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16248
16600
|
embeddings: number().int()
|
|
16249
16601
|
});
|
|
16602
|
+
/** Event-store footprint for one camera. */
|
|
16603
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16604
|
+
deviceId: number(),
|
|
16605
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16606
|
+
rows: number().int(),
|
|
16607
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16608
|
+
bytes: number().int()
|
|
16609
|
+
});
|
|
16610
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16611
|
+
var EventStoreFootprintSchema = object({
|
|
16612
|
+
totalRows: number().int(),
|
|
16613
|
+
totalBytes: number().int(),
|
|
16614
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16615
|
+
});
|
|
16616
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16617
|
+
var EventPruneCountsSchema = object({
|
|
16618
|
+
motion: number().int(),
|
|
16619
|
+
object: number().int(),
|
|
16620
|
+
audio: number().int()
|
|
16621
|
+
});
|
|
16250
16622
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16251
16623
|
deviceId: number(),
|
|
16252
16624
|
trackId: string()
|
|
@@ -16310,6 +16682,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16310
16682
|
}), {
|
|
16311
16683
|
kind: "mutation",
|
|
16312
16684
|
auth: "admin"
|
|
16685
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16686
|
+
kind: "query",
|
|
16687
|
+
auth: "admin"
|
|
16688
|
+
}), method(object({
|
|
16689
|
+
olderThanMs: number(),
|
|
16690
|
+
reason: OpsLogReasonSchema.optional()
|
|
16691
|
+
}), EventPruneCountsSchema, {
|
|
16692
|
+
kind: "mutation",
|
|
16693
|
+
auth: "admin"
|
|
16694
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16695
|
+
kind: "mutation",
|
|
16696
|
+
auth: "admin"
|
|
16697
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16698
|
+
kind: "query",
|
|
16699
|
+
auth: "admin"
|
|
16313
16700
|
}), method(object({
|
|
16314
16701
|
eventId: string(),
|
|
16315
16702
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16334,6 +16721,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16334
16721
|
eventId: string(),
|
|
16335
16722
|
timestamp: number()
|
|
16336
16723
|
});
|
|
16724
|
+
/**
|
|
16725
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16726
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16727
|
+
* caps into per-camera event-kind descriptors.
|
|
16728
|
+
*
|
|
16729
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16730
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16731
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16732
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16733
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16734
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16735
|
+
* eventful cap is missing.
|
|
16736
|
+
*/
|
|
16737
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16738
|
+
var LEGACY_ICON = {
|
|
16739
|
+
motion: "motion",
|
|
16740
|
+
audio: "audio",
|
|
16741
|
+
person: "person",
|
|
16742
|
+
vehicle: "vehicle",
|
|
16743
|
+
animal: "animal",
|
|
16744
|
+
package: "package",
|
|
16745
|
+
door: "door",
|
|
16746
|
+
pir: "pir",
|
|
16747
|
+
smoke: "smoke",
|
|
16748
|
+
water: "water",
|
|
16749
|
+
button: "button",
|
|
16750
|
+
generic: "generic",
|
|
16751
|
+
gas: "smoke",
|
|
16752
|
+
vibration: "generic",
|
|
16753
|
+
tamper: "generic",
|
|
16754
|
+
presence: "person",
|
|
16755
|
+
lock: "generic",
|
|
16756
|
+
siren: "generic",
|
|
16757
|
+
switch: "generic",
|
|
16758
|
+
doorbell: "button"
|
|
16759
|
+
};
|
|
16760
|
+
function legacyIcon(iconId) {
|
|
16761
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16762
|
+
}
|
|
16763
|
+
/**
|
|
16764
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16765
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16766
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16767
|
+
*/
|
|
16768
|
+
var CAP_TO_KIND = {
|
|
16769
|
+
contact: "contact",
|
|
16770
|
+
motion: "motion-sensor",
|
|
16771
|
+
smoke: "smoke",
|
|
16772
|
+
flood: "flood",
|
|
16773
|
+
gas: "gas",
|
|
16774
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16775
|
+
vibration: "vibration",
|
|
16776
|
+
tamper: "tamper",
|
|
16777
|
+
presence: "presence",
|
|
16778
|
+
"enum-sensor": "enum-sensor",
|
|
16779
|
+
"event-emitter": "device-event",
|
|
16780
|
+
"lock-control": "lock",
|
|
16781
|
+
switch: "switch",
|
|
16782
|
+
button: "button",
|
|
16783
|
+
doorbell: "doorbell"
|
|
16784
|
+
};
|
|
16785
|
+
function buildDescriptor(capName, kind) {
|
|
16786
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16787
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16788
|
+
return {
|
|
16789
|
+
...t,
|
|
16790
|
+
icon: legacyIcon(t.iconId)
|
|
16791
|
+
};
|
|
16792
|
+
}
|
|
16793
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16337
16794
|
var CameraPipelineConfigSchema = object({
|
|
16338
16795
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16339
16796
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19543,13 +20000,29 @@ method(object({
|
|
|
19543
20000
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19544
20001
|
kind: "mutation",
|
|
19545
20002
|
auth: "admin"
|
|
19546
|
-
}), method(object({
|
|
20003
|
+
}), method(object({
|
|
20004
|
+
deviceId: number(),
|
|
20005
|
+
reason: OpsLogReasonSchema.optional()
|
|
20006
|
+
}), object({
|
|
19547
20007
|
floorMs: number().nullable(),
|
|
19548
20008
|
deletedBuckets: number().int(),
|
|
19549
20009
|
reclaimedBytes: number().int()
|
|
19550
20010
|
}), {
|
|
19551
20011
|
kind: "mutation",
|
|
19552
20012
|
auth: "admin"
|
|
20013
|
+
}), method(object({
|
|
20014
|
+
deviceId: number(),
|
|
20015
|
+
fromMs: number().optional(),
|
|
20016
|
+
toMs: number().optional()
|
|
20017
|
+
}), object({
|
|
20018
|
+
deletedBuckets: number().int(),
|
|
20019
|
+
reclaimedBytes: number().int()
|
|
20020
|
+
}), {
|
|
20021
|
+
kind: "mutation",
|
|
20022
|
+
auth: "admin"
|
|
20023
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20024
|
+
kind: "query",
|
|
20025
|
+
auth: "admin"
|
|
19553
20026
|
});
|
|
19554
20027
|
/**
|
|
19555
20028
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22671,6 +23144,12 @@ Object.freeze({
|
|
|
22671
23144
|
addonId: null,
|
|
22672
23145
|
access: "delete"
|
|
22673
23146
|
},
|
|
23147
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23148
|
+
capName: "pipeline-analytics",
|
|
23149
|
+
capScope: "device",
|
|
23150
|
+
addonId: null,
|
|
23151
|
+
access: "delete"
|
|
23152
|
+
},
|
|
22674
23153
|
"pipelineAnalytics.deleteTracks": {
|
|
22675
23154
|
capName: "pipeline-analytics",
|
|
22676
23155
|
capScope: "device",
|
|
@@ -22701,6 +23180,12 @@ Object.freeze({
|
|
|
22701
23180
|
addonId: null,
|
|
22702
23181
|
access: "view"
|
|
22703
23182
|
},
|
|
23183
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23184
|
+
capName: "pipeline-analytics",
|
|
23185
|
+
capScope: "device",
|
|
23186
|
+
addonId: null,
|
|
23187
|
+
access: "view"
|
|
23188
|
+
},
|
|
22704
23189
|
"pipelineAnalytics.getKeyEvents": {
|
|
22705
23190
|
capName: "pipeline-analytics",
|
|
22706
23191
|
capScope: "device",
|
|
@@ -22743,6 +23228,12 @@ Object.freeze({
|
|
|
22743
23228
|
addonId: null,
|
|
22744
23229
|
access: "view"
|
|
22745
23230
|
},
|
|
23231
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23232
|
+
capName: "pipeline-analytics",
|
|
23233
|
+
capScope: "device",
|
|
23234
|
+
addonId: null,
|
|
23235
|
+
access: "view"
|
|
23236
|
+
},
|
|
22746
23237
|
"pipelineAnalytics.listRecentTracks": {
|
|
22747
23238
|
capName: "pipeline-analytics",
|
|
22748
23239
|
capScope: "device",
|
|
@@ -22755,6 +23246,12 @@ Object.freeze({
|
|
|
22755
23246
|
addonId: null,
|
|
22756
23247
|
access: "view"
|
|
22757
23248
|
},
|
|
23249
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23250
|
+
capName: "pipeline-analytics",
|
|
23251
|
+
capScope: "device",
|
|
23252
|
+
addonId: null,
|
|
23253
|
+
access: "create"
|
|
23254
|
+
},
|
|
22758
23255
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22759
23256
|
capName: "pipeline-analytics",
|
|
22760
23257
|
capScope: "device",
|
|
@@ -23517,6 +24014,12 @@ Object.freeze({
|
|
|
23517
24014
|
addonId: null,
|
|
23518
24015
|
access: "create"
|
|
23519
24016
|
},
|
|
24017
|
+
"recording.deleteFootprint": {
|
|
24018
|
+
capName: "recording",
|
|
24019
|
+
capScope: "system",
|
|
24020
|
+
addonId: null,
|
|
24021
|
+
access: "delete"
|
|
24022
|
+
},
|
|
23520
24023
|
"recording.getAvailability": {
|
|
23521
24024
|
capName: "recording",
|
|
23522
24025
|
capScope: "system",
|
|
@@ -23547,6 +24050,12 @@ Object.freeze({
|
|
|
23547
24050
|
addonId: null,
|
|
23548
24051
|
access: "view"
|
|
23549
24052
|
},
|
|
24053
|
+
"recording.listOpsLog": {
|
|
24054
|
+
capName: "recording",
|
|
24055
|
+
capScope: "system",
|
|
24056
|
+
addonId: null,
|
|
24057
|
+
access: "view"
|
|
24058
|
+
},
|
|
23550
24059
|
"recording.locateSegment": {
|
|
23551
24060
|
capName: "recording",
|
|
23552
24061
|
capScope: "system",
|
package/dist/addon.mjs
CHANGED
|
@@ -7334,6 +7334,62 @@ var RecordingConfigSchema = object({
|
|
|
7334
7334
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7335
7335
|
});
|
|
7336
7336
|
/**
|
|
7337
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7338
|
+
* recordings and events management surfaces.
|
|
7339
|
+
*
|
|
7340
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7341
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7342
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7343
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7344
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7345
|
+
* never fail the operation it records.
|
|
7346
|
+
*/
|
|
7347
|
+
/** Which management domain the operation belongs to. */
|
|
7348
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7349
|
+
/** The kind of management operation performed. */
|
|
7350
|
+
var OpsLogOpSchema = _enum([
|
|
7351
|
+
"prune",
|
|
7352
|
+
"manual-delete",
|
|
7353
|
+
"rescan",
|
|
7354
|
+
"retention-run"
|
|
7355
|
+
]);
|
|
7356
|
+
/** Why the operation ran. */
|
|
7357
|
+
var OpsLogReasonSchema = _enum([
|
|
7358
|
+
"retention",
|
|
7359
|
+
"quota",
|
|
7360
|
+
"manual",
|
|
7361
|
+
"operator"
|
|
7362
|
+
]);
|
|
7363
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7364
|
+
var OpsLogEntrySchema = object({
|
|
7365
|
+
/** Unique row id. */
|
|
7366
|
+
id: string(),
|
|
7367
|
+
/** Epoch ms the operation completed. */
|
|
7368
|
+
at: number(),
|
|
7369
|
+
domain: OpsLogDomainSchema,
|
|
7370
|
+
op: OpsLogOpSchema,
|
|
7371
|
+
reason: OpsLogReasonSchema,
|
|
7372
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7373
|
+
deviceId: number().nullable(),
|
|
7374
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7375
|
+
nodeId: string(),
|
|
7376
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7377
|
+
itemsAffected: number(),
|
|
7378
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7379
|
+
bytesReclaimed: number(),
|
|
7380
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7381
|
+
detail: string().nullable(),
|
|
7382
|
+
/** Who/what triggered the op. */
|
|
7383
|
+
actor: string()
|
|
7384
|
+
});
|
|
7385
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7386
|
+
var OpsLogQueryInputSchema = object({
|
|
7387
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7388
|
+
deviceId: number().optional(),
|
|
7389
|
+
/** Max rows returned, newest-first. */
|
|
7390
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7391
|
+
});
|
|
7392
|
+
/**
|
|
7337
7393
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7338
7394
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7339
7395
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7607,6 +7663,160 @@ var CAP_NODE_PIN_CONTEXT_KEY = "__camstackNodePin";
|
|
|
7607
7663
|
function nodePin(nodeId) {
|
|
7608
7664
|
return { context: { [CAP_NODE_PIN_CONTEXT_KEY]: nodeId } };
|
|
7609
7665
|
}
|
|
7666
|
+
var COCO_TO_MACRO = {
|
|
7667
|
+
mapping: {
|
|
7668
|
+
person: "person",
|
|
7669
|
+
bicycle: "vehicle",
|
|
7670
|
+
car: "vehicle",
|
|
7671
|
+
motorcycle: "vehicle",
|
|
7672
|
+
airplane: "vehicle",
|
|
7673
|
+
bus: "vehicle",
|
|
7674
|
+
train: "vehicle",
|
|
7675
|
+
truck: "vehicle",
|
|
7676
|
+
boat: "vehicle",
|
|
7677
|
+
bird: "animal",
|
|
7678
|
+
cat: "animal",
|
|
7679
|
+
dog: "animal",
|
|
7680
|
+
horse: "animal",
|
|
7681
|
+
sheep: "animal",
|
|
7682
|
+
cow: "animal",
|
|
7683
|
+
elephant: "animal",
|
|
7684
|
+
bear: "animal",
|
|
7685
|
+
zebra: "animal",
|
|
7686
|
+
giraffe: "animal",
|
|
7687
|
+
suitcase: "package",
|
|
7688
|
+
backpack: "package",
|
|
7689
|
+
handbag: "package"
|
|
7690
|
+
},
|
|
7691
|
+
preserveOriginal: false
|
|
7692
|
+
};
|
|
7693
|
+
var AUDIO_MACRO_LABELS = [
|
|
7694
|
+
{
|
|
7695
|
+
id: "speech",
|
|
7696
|
+
name: "Speech",
|
|
7697
|
+
icon: "🗣️"
|
|
7698
|
+
},
|
|
7699
|
+
{
|
|
7700
|
+
id: "scream",
|
|
7701
|
+
name: "Scream / Shout",
|
|
7702
|
+
icon: "😱"
|
|
7703
|
+
},
|
|
7704
|
+
{
|
|
7705
|
+
id: "crying",
|
|
7706
|
+
name: "Crying / Baby",
|
|
7707
|
+
icon: "😢"
|
|
7708
|
+
},
|
|
7709
|
+
{
|
|
7710
|
+
id: "laughter",
|
|
7711
|
+
name: "Laughter",
|
|
7712
|
+
icon: "😂"
|
|
7713
|
+
},
|
|
7714
|
+
{
|
|
7715
|
+
id: "music",
|
|
7716
|
+
name: "Music",
|
|
7717
|
+
icon: "🎵"
|
|
7718
|
+
},
|
|
7719
|
+
{
|
|
7720
|
+
id: "dog",
|
|
7721
|
+
name: "Dog",
|
|
7722
|
+
icon: "🐕"
|
|
7723
|
+
},
|
|
7724
|
+
{
|
|
7725
|
+
id: "cat",
|
|
7726
|
+
name: "Cat",
|
|
7727
|
+
icon: "🐈"
|
|
7728
|
+
},
|
|
7729
|
+
{
|
|
7730
|
+
id: "bird",
|
|
7731
|
+
name: "Bird",
|
|
7732
|
+
icon: "🐦"
|
|
7733
|
+
},
|
|
7734
|
+
{
|
|
7735
|
+
id: "animal",
|
|
7736
|
+
name: "Animal (other)",
|
|
7737
|
+
icon: "🐾"
|
|
7738
|
+
},
|
|
7739
|
+
{
|
|
7740
|
+
id: "alarm",
|
|
7741
|
+
name: "Alarm / Siren",
|
|
7742
|
+
icon: "🚨"
|
|
7743
|
+
},
|
|
7744
|
+
{
|
|
7745
|
+
id: "doorbell",
|
|
7746
|
+
name: "Doorbell / Knock",
|
|
7747
|
+
icon: "🔔"
|
|
7748
|
+
},
|
|
7749
|
+
{
|
|
7750
|
+
id: "glass_breaking",
|
|
7751
|
+
name: "Glass Breaking",
|
|
7752
|
+
icon: "💥"
|
|
7753
|
+
},
|
|
7754
|
+
{
|
|
7755
|
+
id: "gunshot",
|
|
7756
|
+
name: "Gunshot / Explosion",
|
|
7757
|
+
icon: "💣"
|
|
7758
|
+
},
|
|
7759
|
+
{
|
|
7760
|
+
id: "vehicle",
|
|
7761
|
+
name: "Vehicle",
|
|
7762
|
+
icon: "🚗"
|
|
7763
|
+
},
|
|
7764
|
+
{
|
|
7765
|
+
id: "siren",
|
|
7766
|
+
name: "Emergency Siren",
|
|
7767
|
+
icon: "🚑"
|
|
7768
|
+
},
|
|
7769
|
+
{
|
|
7770
|
+
id: "fire",
|
|
7771
|
+
name: "Fire / Smoke",
|
|
7772
|
+
icon: "🔥"
|
|
7773
|
+
},
|
|
7774
|
+
{
|
|
7775
|
+
id: "water",
|
|
7776
|
+
name: "Water",
|
|
7777
|
+
icon: "💧"
|
|
7778
|
+
},
|
|
7779
|
+
{
|
|
7780
|
+
id: "wind",
|
|
7781
|
+
name: "Wind / Weather",
|
|
7782
|
+
icon: "🌬️"
|
|
7783
|
+
},
|
|
7784
|
+
{
|
|
7785
|
+
id: "door",
|
|
7786
|
+
name: "Door",
|
|
7787
|
+
icon: "🚪"
|
|
7788
|
+
},
|
|
7789
|
+
{
|
|
7790
|
+
id: "footsteps",
|
|
7791
|
+
name: "Footsteps",
|
|
7792
|
+
icon: "👣"
|
|
7793
|
+
},
|
|
7794
|
+
{
|
|
7795
|
+
id: "crowd",
|
|
7796
|
+
name: "Crowd / Chatter",
|
|
7797
|
+
icon: "👥"
|
|
7798
|
+
},
|
|
7799
|
+
{
|
|
7800
|
+
id: "telephone",
|
|
7801
|
+
name: "Telephone",
|
|
7802
|
+
icon: "📞"
|
|
7803
|
+
},
|
|
7804
|
+
{
|
|
7805
|
+
id: "engine",
|
|
7806
|
+
name: "Engine / Motor",
|
|
7807
|
+
icon: "⚙️"
|
|
7808
|
+
},
|
|
7809
|
+
{
|
|
7810
|
+
id: "tools",
|
|
7811
|
+
name: "Tools / Construction",
|
|
7812
|
+
icon: "🔨"
|
|
7813
|
+
},
|
|
7814
|
+
{
|
|
7815
|
+
id: "silence",
|
|
7816
|
+
name: "Silence",
|
|
7817
|
+
icon: "🤫"
|
|
7818
|
+
}
|
|
7819
|
+
];
|
|
7610
7820
|
var YAMNET_TO_MACRO = {
|
|
7611
7821
|
mapping: {
|
|
7612
7822
|
Speech: "speech",
|
|
@@ -7873,6 +8083,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7873
8083
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7874
8084
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7875
8085
|
/**
|
|
8086
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8087
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8088
|
+
* icon }`.
|
|
8089
|
+
*
|
|
8090
|
+
* This dictionary folds together what used to be scattered across four
|
|
8091
|
+
* copies:
|
|
8092
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8093
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8094
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8095
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8096
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8097
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8098
|
+
*
|
|
8099
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8100
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8101
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8102
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8103
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8104
|
+
*
|
|
8105
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8106
|
+
*/
|
|
8107
|
+
var TAXONOMY_COLORS = {
|
|
8108
|
+
motion: "#f59e0b",
|
|
8109
|
+
audio: "#06b6d4",
|
|
8110
|
+
person: "#22c55e",
|
|
8111
|
+
vehicle: "#3b82f6",
|
|
8112
|
+
animal: "#f97316",
|
|
8113
|
+
package: "#a855f7",
|
|
8114
|
+
sensor: "#8b5cf6",
|
|
8115
|
+
control: "#10b981",
|
|
8116
|
+
genericDetection: "#64748b"
|
|
8117
|
+
};
|
|
8118
|
+
var DETECTION_SUB_COLORS = {
|
|
8119
|
+
car: "#f59e0b",
|
|
8120
|
+
truck: "#d97706",
|
|
8121
|
+
bus: "#b45309",
|
|
8122
|
+
motorcycle: "#eab308",
|
|
8123
|
+
bicycle: "#ca8a04",
|
|
8124
|
+
airplane: "#60a5fa",
|
|
8125
|
+
boat: "#2563eb",
|
|
8126
|
+
train: "#1d4ed8",
|
|
8127
|
+
bird: "#14b8a6",
|
|
8128
|
+
dog: "#84cc16",
|
|
8129
|
+
cat: "#f97316",
|
|
8130
|
+
horse: "#a16207",
|
|
8131
|
+
sheep: "#a3a3a3",
|
|
8132
|
+
cow: "#78716c",
|
|
8133
|
+
elephant: "#6b7280",
|
|
8134
|
+
bear: "#7c2d12",
|
|
8135
|
+
zebra: "#404040",
|
|
8136
|
+
giraffe: "#d4a373"
|
|
8137
|
+
};
|
|
8138
|
+
function titleCase(id) {
|
|
8139
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8140
|
+
}
|
|
8141
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8142
|
+
function macro(kind, category, color, iconId, label) {
|
|
8143
|
+
entries.set(kind, {
|
|
8144
|
+
kind,
|
|
8145
|
+
parentKind: null,
|
|
8146
|
+
level: "macro",
|
|
8147
|
+
category,
|
|
8148
|
+
color,
|
|
8149
|
+
iconId,
|
|
8150
|
+
labelKey: `eventKind.${kind}`,
|
|
8151
|
+
label
|
|
8152
|
+
});
|
|
8153
|
+
}
|
|
8154
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8155
|
+
entries.set(kind, {
|
|
8156
|
+
kind,
|
|
8157
|
+
parentKind,
|
|
8158
|
+
level: "sub",
|
|
8159
|
+
category,
|
|
8160
|
+
color,
|
|
8161
|
+
iconId,
|
|
8162
|
+
labelKey: `eventKind.${kind}`,
|
|
8163
|
+
label
|
|
8164
|
+
});
|
|
8165
|
+
}
|
|
8166
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8167
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8168
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8169
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8170
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8171
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8172
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8173
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8174
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8175
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8176
|
+
if (entries.has(cocoClass)) continue;
|
|
8177
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8178
|
+
}
|
|
8179
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8180
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8181
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8182
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8183
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8184
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8185
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8186
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8187
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8188
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8189
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8190
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8191
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8192
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8193
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8194
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8195
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8196
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8197
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8198
|
+
const kind = `audio-${l.id}`;
|
|
8199
|
+
if (entries.has(kind)) continue;
|
|
8200
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8201
|
+
}
|
|
8202
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8203
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8204
|
+
/**
|
|
7876
8205
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7877
8206
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7878
8207
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15867,17 +16196,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15867
16196
|
"audio",
|
|
15868
16197
|
"detection",
|
|
15869
16198
|
"sensor",
|
|
16199
|
+
"control",
|
|
15870
16200
|
"custom",
|
|
15871
16201
|
"package"
|
|
15872
16202
|
]);
|
|
16203
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16204
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15873
16205
|
var EventKindDescriptorSchema = object({
|
|
15874
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16206
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15875
16207
|
kind: string(),
|
|
16208
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16209
|
+
labelKey: string(),
|
|
16210
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15876
16211
|
label: string(),
|
|
15877
16212
|
/** Hex color for timeline/legend rendering. */
|
|
15878
16213
|
color: string(),
|
|
16214
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16215
|
+
iconId: string(),
|
|
16216
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15879
16217
|
icon: EventKindIconSchema,
|
|
15880
16218
|
category: EventKindCategorySchema,
|
|
16219
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16220
|
+
parentKind: string().nullable(),
|
|
16221
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16222
|
+
level: EventKindLevelSchema,
|
|
15881
16223
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15882
16224
|
* itself; for sensor kinds the LINKED source device. */
|
|
15883
16225
|
source: object({
|
|
@@ -15950,11 +16292,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15950
16292
|
firstAt: number(),
|
|
15951
16293
|
lastAt: number()
|
|
15952
16294
|
});
|
|
16295
|
+
/**
|
|
16296
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16297
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16298
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16299
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16300
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16301
|
+
*/
|
|
16302
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15953
16303
|
var TrackSchema = object({
|
|
15954
16304
|
trackId: string(),
|
|
15955
16305
|
deviceId: number(),
|
|
15956
16306
|
className: string(),
|
|
15957
16307
|
label: string().optional(),
|
|
16308
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16309
|
+
source: TrackSourceSchema.optional(),
|
|
15958
16310
|
firstSeen: number(),
|
|
15959
16311
|
lastSeen: number(),
|
|
15960
16312
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16209,6 +16561,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16209
16561
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16210
16562
|
embeddings: number().int()
|
|
16211
16563
|
});
|
|
16564
|
+
/** Event-store footprint for one camera. */
|
|
16565
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16566
|
+
deviceId: number(),
|
|
16567
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16568
|
+
rows: number().int(),
|
|
16569
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16570
|
+
bytes: number().int()
|
|
16571
|
+
});
|
|
16572
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16573
|
+
var EventStoreFootprintSchema = object({
|
|
16574
|
+
totalRows: number().int(),
|
|
16575
|
+
totalBytes: number().int(),
|
|
16576
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16577
|
+
});
|
|
16578
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16579
|
+
var EventPruneCountsSchema = object({
|
|
16580
|
+
motion: number().int(),
|
|
16581
|
+
object: number().int(),
|
|
16582
|
+
audio: number().int()
|
|
16583
|
+
});
|
|
16212
16584
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16213
16585
|
deviceId: number(),
|
|
16214
16586
|
trackId: string()
|
|
@@ -16272,6 +16644,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16272
16644
|
}), {
|
|
16273
16645
|
kind: "mutation",
|
|
16274
16646
|
auth: "admin"
|
|
16647
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16648
|
+
kind: "query",
|
|
16649
|
+
auth: "admin"
|
|
16650
|
+
}), method(object({
|
|
16651
|
+
olderThanMs: number(),
|
|
16652
|
+
reason: OpsLogReasonSchema.optional()
|
|
16653
|
+
}), EventPruneCountsSchema, {
|
|
16654
|
+
kind: "mutation",
|
|
16655
|
+
auth: "admin"
|
|
16656
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16657
|
+
kind: "mutation",
|
|
16658
|
+
auth: "admin"
|
|
16659
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16660
|
+
kind: "query",
|
|
16661
|
+
auth: "admin"
|
|
16275
16662
|
}), method(object({
|
|
16276
16663
|
eventId: string(),
|
|
16277
16664
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16296,6 +16683,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16296
16683
|
eventId: string(),
|
|
16297
16684
|
timestamp: number()
|
|
16298
16685
|
});
|
|
16686
|
+
/**
|
|
16687
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16688
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16689
|
+
* caps into per-camera event-kind descriptors.
|
|
16690
|
+
*
|
|
16691
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16692
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16693
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16694
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16695
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16696
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16697
|
+
* eventful cap is missing.
|
|
16698
|
+
*/
|
|
16699
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16700
|
+
var LEGACY_ICON = {
|
|
16701
|
+
motion: "motion",
|
|
16702
|
+
audio: "audio",
|
|
16703
|
+
person: "person",
|
|
16704
|
+
vehicle: "vehicle",
|
|
16705
|
+
animal: "animal",
|
|
16706
|
+
package: "package",
|
|
16707
|
+
door: "door",
|
|
16708
|
+
pir: "pir",
|
|
16709
|
+
smoke: "smoke",
|
|
16710
|
+
water: "water",
|
|
16711
|
+
button: "button",
|
|
16712
|
+
generic: "generic",
|
|
16713
|
+
gas: "smoke",
|
|
16714
|
+
vibration: "generic",
|
|
16715
|
+
tamper: "generic",
|
|
16716
|
+
presence: "person",
|
|
16717
|
+
lock: "generic",
|
|
16718
|
+
siren: "generic",
|
|
16719
|
+
switch: "generic",
|
|
16720
|
+
doorbell: "button"
|
|
16721
|
+
};
|
|
16722
|
+
function legacyIcon(iconId) {
|
|
16723
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16724
|
+
}
|
|
16725
|
+
/**
|
|
16726
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16727
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16728
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16729
|
+
*/
|
|
16730
|
+
var CAP_TO_KIND = {
|
|
16731
|
+
contact: "contact",
|
|
16732
|
+
motion: "motion-sensor",
|
|
16733
|
+
smoke: "smoke",
|
|
16734
|
+
flood: "flood",
|
|
16735
|
+
gas: "gas",
|
|
16736
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16737
|
+
vibration: "vibration",
|
|
16738
|
+
tamper: "tamper",
|
|
16739
|
+
presence: "presence",
|
|
16740
|
+
"enum-sensor": "enum-sensor",
|
|
16741
|
+
"event-emitter": "device-event",
|
|
16742
|
+
"lock-control": "lock",
|
|
16743
|
+
switch: "switch",
|
|
16744
|
+
button: "button",
|
|
16745
|
+
doorbell: "doorbell"
|
|
16746
|
+
};
|
|
16747
|
+
function buildDescriptor(capName, kind) {
|
|
16748
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16749
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16750
|
+
return {
|
|
16751
|
+
...t,
|
|
16752
|
+
icon: legacyIcon(t.iconId)
|
|
16753
|
+
};
|
|
16754
|
+
}
|
|
16755
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16299
16756
|
var CameraPipelineConfigSchema = object({
|
|
16300
16757
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16301
16758
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19505,13 +19962,29 @@ method(object({
|
|
|
19505
19962
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19506
19963
|
kind: "mutation",
|
|
19507
19964
|
auth: "admin"
|
|
19508
|
-
}), method(object({
|
|
19965
|
+
}), method(object({
|
|
19966
|
+
deviceId: number(),
|
|
19967
|
+
reason: OpsLogReasonSchema.optional()
|
|
19968
|
+
}), object({
|
|
19509
19969
|
floorMs: number().nullable(),
|
|
19510
19970
|
deletedBuckets: number().int(),
|
|
19511
19971
|
reclaimedBytes: number().int()
|
|
19512
19972
|
}), {
|
|
19513
19973
|
kind: "mutation",
|
|
19514
19974
|
auth: "admin"
|
|
19975
|
+
}), method(object({
|
|
19976
|
+
deviceId: number(),
|
|
19977
|
+
fromMs: number().optional(),
|
|
19978
|
+
toMs: number().optional()
|
|
19979
|
+
}), object({
|
|
19980
|
+
deletedBuckets: number().int(),
|
|
19981
|
+
reclaimedBytes: number().int()
|
|
19982
|
+
}), {
|
|
19983
|
+
kind: "mutation",
|
|
19984
|
+
auth: "admin"
|
|
19985
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19986
|
+
kind: "query",
|
|
19987
|
+
auth: "admin"
|
|
19515
19988
|
});
|
|
19516
19989
|
/**
|
|
19517
19990
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22633,6 +23106,12 @@ Object.freeze({
|
|
|
22633
23106
|
addonId: null,
|
|
22634
23107
|
access: "delete"
|
|
22635
23108
|
},
|
|
23109
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23110
|
+
capName: "pipeline-analytics",
|
|
23111
|
+
capScope: "device",
|
|
23112
|
+
addonId: null,
|
|
23113
|
+
access: "delete"
|
|
23114
|
+
},
|
|
22636
23115
|
"pipelineAnalytics.deleteTracks": {
|
|
22637
23116
|
capName: "pipeline-analytics",
|
|
22638
23117
|
capScope: "device",
|
|
@@ -22663,6 +23142,12 @@ Object.freeze({
|
|
|
22663
23142
|
addonId: null,
|
|
22664
23143
|
access: "view"
|
|
22665
23144
|
},
|
|
23145
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23146
|
+
capName: "pipeline-analytics",
|
|
23147
|
+
capScope: "device",
|
|
23148
|
+
addonId: null,
|
|
23149
|
+
access: "view"
|
|
23150
|
+
},
|
|
22666
23151
|
"pipelineAnalytics.getKeyEvents": {
|
|
22667
23152
|
capName: "pipeline-analytics",
|
|
22668
23153
|
capScope: "device",
|
|
@@ -22705,6 +23190,12 @@ Object.freeze({
|
|
|
22705
23190
|
addonId: null,
|
|
22706
23191
|
access: "view"
|
|
22707
23192
|
},
|
|
23193
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23194
|
+
capName: "pipeline-analytics",
|
|
23195
|
+
capScope: "device",
|
|
23196
|
+
addonId: null,
|
|
23197
|
+
access: "view"
|
|
23198
|
+
},
|
|
22708
23199
|
"pipelineAnalytics.listRecentTracks": {
|
|
22709
23200
|
capName: "pipeline-analytics",
|
|
22710
23201
|
capScope: "device",
|
|
@@ -22717,6 +23208,12 @@ Object.freeze({
|
|
|
22717
23208
|
addonId: null,
|
|
22718
23209
|
access: "view"
|
|
22719
23210
|
},
|
|
23211
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23212
|
+
capName: "pipeline-analytics",
|
|
23213
|
+
capScope: "device",
|
|
23214
|
+
addonId: null,
|
|
23215
|
+
access: "create"
|
|
23216
|
+
},
|
|
22720
23217
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22721
23218
|
capName: "pipeline-analytics",
|
|
22722
23219
|
capScope: "device",
|
|
@@ -23479,6 +23976,12 @@ Object.freeze({
|
|
|
23479
23976
|
addonId: null,
|
|
23480
23977
|
access: "create"
|
|
23481
23978
|
},
|
|
23979
|
+
"recording.deleteFootprint": {
|
|
23980
|
+
capName: "recording",
|
|
23981
|
+
capScope: "system",
|
|
23982
|
+
addonId: null,
|
|
23983
|
+
access: "delete"
|
|
23984
|
+
},
|
|
23482
23985
|
"recording.getAvailability": {
|
|
23483
23986
|
capName: "recording",
|
|
23484
23987
|
capScope: "system",
|
|
@@ -23509,6 +24012,12 @@ Object.freeze({
|
|
|
23509
24012
|
addonId: null,
|
|
23510
24013
|
access: "view"
|
|
23511
24014
|
},
|
|
24015
|
+
"recording.listOpsLog": {
|
|
24016
|
+
capName: "recording",
|
|
24017
|
+
capScope: "system",
|
|
24018
|
+
addonId: null,
|
|
24019
|
+
access: "view"
|
|
24020
|
+
},
|
|
23512
24021
|
"recording.locateSegment": {
|
|
23513
24022
|
capName: "recording",
|
|
23514
24023
|
capScope: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|