@camstack/addon-export-hap 1.1.26 → 1.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/export-hap.addon.js +511 -2
- package/dist/export-hap.addon.mjs +511 -2
- package/package.json +1 -1
package/dist/export-hap.addon.js
CHANGED
|
@@ -7364,6 +7364,62 @@ var RecordingConfigSchema = object({
|
|
|
7364
7364
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7365
7365
|
});
|
|
7366
7366
|
/**
|
|
7367
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7368
|
+
* recordings and events management surfaces.
|
|
7369
|
+
*
|
|
7370
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7371
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7372
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7373
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7374
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7375
|
+
* never fail the operation it records.
|
|
7376
|
+
*/
|
|
7377
|
+
/** Which management domain the operation belongs to. */
|
|
7378
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7379
|
+
/** The kind of management operation performed. */
|
|
7380
|
+
var OpsLogOpSchema = _enum([
|
|
7381
|
+
"prune",
|
|
7382
|
+
"manual-delete",
|
|
7383
|
+
"rescan",
|
|
7384
|
+
"retention-run"
|
|
7385
|
+
]);
|
|
7386
|
+
/** Why the operation ran. */
|
|
7387
|
+
var OpsLogReasonSchema = _enum([
|
|
7388
|
+
"retention",
|
|
7389
|
+
"quota",
|
|
7390
|
+
"manual",
|
|
7391
|
+
"operator"
|
|
7392
|
+
]);
|
|
7393
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7394
|
+
var OpsLogEntrySchema = object({
|
|
7395
|
+
/** Unique row id. */
|
|
7396
|
+
id: string(),
|
|
7397
|
+
/** Epoch ms the operation completed. */
|
|
7398
|
+
at: number(),
|
|
7399
|
+
domain: OpsLogDomainSchema,
|
|
7400
|
+
op: OpsLogOpSchema,
|
|
7401
|
+
reason: OpsLogReasonSchema,
|
|
7402
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7403
|
+
deviceId: number().nullable(),
|
|
7404
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7405
|
+
nodeId: string(),
|
|
7406
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7407
|
+
itemsAffected: number(),
|
|
7408
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7409
|
+
bytesReclaimed: number(),
|
|
7410
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7411
|
+
detail: string().nullable(),
|
|
7412
|
+
/** Who/what triggered the op. */
|
|
7413
|
+
actor: string()
|
|
7414
|
+
});
|
|
7415
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7416
|
+
var OpsLogQueryInputSchema = object({
|
|
7417
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7418
|
+
deviceId: number().optional(),
|
|
7419
|
+
/** Max rows returned, newest-first. */
|
|
7420
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7421
|
+
});
|
|
7422
|
+
/**
|
|
7367
7423
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7368
7424
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7369
7425
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7661,6 +7717,160 @@ function pickClosestResolution(entries, target) {
|
|
|
7661
7717
|
}
|
|
7662
7718
|
return bestAbove?.entry ?? bestBelow?.entry;
|
|
7663
7719
|
}
|
|
7720
|
+
var COCO_TO_MACRO = {
|
|
7721
|
+
mapping: {
|
|
7722
|
+
person: "person",
|
|
7723
|
+
bicycle: "vehicle",
|
|
7724
|
+
car: "vehicle",
|
|
7725
|
+
motorcycle: "vehicle",
|
|
7726
|
+
airplane: "vehicle",
|
|
7727
|
+
bus: "vehicle",
|
|
7728
|
+
train: "vehicle",
|
|
7729
|
+
truck: "vehicle",
|
|
7730
|
+
boat: "vehicle",
|
|
7731
|
+
bird: "animal",
|
|
7732
|
+
cat: "animal",
|
|
7733
|
+
dog: "animal",
|
|
7734
|
+
horse: "animal",
|
|
7735
|
+
sheep: "animal",
|
|
7736
|
+
cow: "animal",
|
|
7737
|
+
elephant: "animal",
|
|
7738
|
+
bear: "animal",
|
|
7739
|
+
zebra: "animal",
|
|
7740
|
+
giraffe: "animal",
|
|
7741
|
+
suitcase: "package",
|
|
7742
|
+
backpack: "package",
|
|
7743
|
+
handbag: "package"
|
|
7744
|
+
},
|
|
7745
|
+
preserveOriginal: false
|
|
7746
|
+
};
|
|
7747
|
+
var AUDIO_MACRO_LABELS = [
|
|
7748
|
+
{
|
|
7749
|
+
id: "speech",
|
|
7750
|
+
name: "Speech",
|
|
7751
|
+
icon: "🗣️"
|
|
7752
|
+
},
|
|
7753
|
+
{
|
|
7754
|
+
id: "scream",
|
|
7755
|
+
name: "Scream / Shout",
|
|
7756
|
+
icon: "😱"
|
|
7757
|
+
},
|
|
7758
|
+
{
|
|
7759
|
+
id: "crying",
|
|
7760
|
+
name: "Crying / Baby",
|
|
7761
|
+
icon: "😢"
|
|
7762
|
+
},
|
|
7763
|
+
{
|
|
7764
|
+
id: "laughter",
|
|
7765
|
+
name: "Laughter",
|
|
7766
|
+
icon: "😂"
|
|
7767
|
+
},
|
|
7768
|
+
{
|
|
7769
|
+
id: "music",
|
|
7770
|
+
name: "Music",
|
|
7771
|
+
icon: "🎵"
|
|
7772
|
+
},
|
|
7773
|
+
{
|
|
7774
|
+
id: "dog",
|
|
7775
|
+
name: "Dog",
|
|
7776
|
+
icon: "🐕"
|
|
7777
|
+
},
|
|
7778
|
+
{
|
|
7779
|
+
id: "cat",
|
|
7780
|
+
name: "Cat",
|
|
7781
|
+
icon: "🐈"
|
|
7782
|
+
},
|
|
7783
|
+
{
|
|
7784
|
+
id: "bird",
|
|
7785
|
+
name: "Bird",
|
|
7786
|
+
icon: "🐦"
|
|
7787
|
+
},
|
|
7788
|
+
{
|
|
7789
|
+
id: "animal",
|
|
7790
|
+
name: "Animal (other)",
|
|
7791
|
+
icon: "🐾"
|
|
7792
|
+
},
|
|
7793
|
+
{
|
|
7794
|
+
id: "alarm",
|
|
7795
|
+
name: "Alarm / Siren",
|
|
7796
|
+
icon: "🚨"
|
|
7797
|
+
},
|
|
7798
|
+
{
|
|
7799
|
+
id: "doorbell",
|
|
7800
|
+
name: "Doorbell / Knock",
|
|
7801
|
+
icon: "🔔"
|
|
7802
|
+
},
|
|
7803
|
+
{
|
|
7804
|
+
id: "glass_breaking",
|
|
7805
|
+
name: "Glass Breaking",
|
|
7806
|
+
icon: "💥"
|
|
7807
|
+
},
|
|
7808
|
+
{
|
|
7809
|
+
id: "gunshot",
|
|
7810
|
+
name: "Gunshot / Explosion",
|
|
7811
|
+
icon: "💣"
|
|
7812
|
+
},
|
|
7813
|
+
{
|
|
7814
|
+
id: "vehicle",
|
|
7815
|
+
name: "Vehicle",
|
|
7816
|
+
icon: "🚗"
|
|
7817
|
+
},
|
|
7818
|
+
{
|
|
7819
|
+
id: "siren",
|
|
7820
|
+
name: "Emergency Siren",
|
|
7821
|
+
icon: "🚑"
|
|
7822
|
+
},
|
|
7823
|
+
{
|
|
7824
|
+
id: "fire",
|
|
7825
|
+
name: "Fire / Smoke",
|
|
7826
|
+
icon: "🔥"
|
|
7827
|
+
},
|
|
7828
|
+
{
|
|
7829
|
+
id: "water",
|
|
7830
|
+
name: "Water",
|
|
7831
|
+
icon: "💧"
|
|
7832
|
+
},
|
|
7833
|
+
{
|
|
7834
|
+
id: "wind",
|
|
7835
|
+
name: "Wind / Weather",
|
|
7836
|
+
icon: "🌬️"
|
|
7837
|
+
},
|
|
7838
|
+
{
|
|
7839
|
+
id: "door",
|
|
7840
|
+
name: "Door",
|
|
7841
|
+
icon: "🚪"
|
|
7842
|
+
},
|
|
7843
|
+
{
|
|
7844
|
+
id: "footsteps",
|
|
7845
|
+
name: "Footsteps",
|
|
7846
|
+
icon: "👣"
|
|
7847
|
+
},
|
|
7848
|
+
{
|
|
7849
|
+
id: "crowd",
|
|
7850
|
+
name: "Crowd / Chatter",
|
|
7851
|
+
icon: "👥"
|
|
7852
|
+
},
|
|
7853
|
+
{
|
|
7854
|
+
id: "telephone",
|
|
7855
|
+
name: "Telephone",
|
|
7856
|
+
icon: "📞"
|
|
7857
|
+
},
|
|
7858
|
+
{
|
|
7859
|
+
id: "engine",
|
|
7860
|
+
name: "Engine / Motor",
|
|
7861
|
+
icon: "⚙️"
|
|
7862
|
+
},
|
|
7863
|
+
{
|
|
7864
|
+
id: "tools",
|
|
7865
|
+
name: "Tools / Construction",
|
|
7866
|
+
icon: "🔨"
|
|
7867
|
+
},
|
|
7868
|
+
{
|
|
7869
|
+
id: "silence",
|
|
7870
|
+
name: "Silence",
|
|
7871
|
+
icon: "🤫"
|
|
7872
|
+
}
|
|
7873
|
+
];
|
|
7664
7874
|
var YAMNET_TO_MACRO = {
|
|
7665
7875
|
mapping: {
|
|
7666
7876
|
Speech: "speech",
|
|
@@ -7927,6 +8137,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7927
8137
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7928
8138
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7929
8139
|
/**
|
|
8140
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8141
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8142
|
+
* icon }`.
|
|
8143
|
+
*
|
|
8144
|
+
* This dictionary folds together what used to be scattered across four
|
|
8145
|
+
* copies:
|
|
8146
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8147
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8148
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8149
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8150
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8151
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8152
|
+
*
|
|
8153
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8154
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8155
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8156
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8157
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8158
|
+
*
|
|
8159
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8160
|
+
*/
|
|
8161
|
+
var TAXONOMY_COLORS = {
|
|
8162
|
+
motion: "#f59e0b",
|
|
8163
|
+
audio: "#06b6d4",
|
|
8164
|
+
person: "#22c55e",
|
|
8165
|
+
vehicle: "#3b82f6",
|
|
8166
|
+
animal: "#f97316",
|
|
8167
|
+
package: "#a855f7",
|
|
8168
|
+
sensor: "#8b5cf6",
|
|
8169
|
+
control: "#10b981",
|
|
8170
|
+
genericDetection: "#64748b"
|
|
8171
|
+
};
|
|
8172
|
+
var DETECTION_SUB_COLORS = {
|
|
8173
|
+
car: "#f59e0b",
|
|
8174
|
+
truck: "#d97706",
|
|
8175
|
+
bus: "#b45309",
|
|
8176
|
+
motorcycle: "#eab308",
|
|
8177
|
+
bicycle: "#ca8a04",
|
|
8178
|
+
airplane: "#60a5fa",
|
|
8179
|
+
boat: "#2563eb",
|
|
8180
|
+
train: "#1d4ed8",
|
|
8181
|
+
bird: "#14b8a6",
|
|
8182
|
+
dog: "#84cc16",
|
|
8183
|
+
cat: "#f97316",
|
|
8184
|
+
horse: "#a16207",
|
|
8185
|
+
sheep: "#a3a3a3",
|
|
8186
|
+
cow: "#78716c",
|
|
8187
|
+
elephant: "#6b7280",
|
|
8188
|
+
bear: "#7c2d12",
|
|
8189
|
+
zebra: "#404040",
|
|
8190
|
+
giraffe: "#d4a373"
|
|
8191
|
+
};
|
|
8192
|
+
function titleCase(id) {
|
|
8193
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8194
|
+
}
|
|
8195
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8196
|
+
function macro(kind, category, color, iconId, label) {
|
|
8197
|
+
entries.set(kind, {
|
|
8198
|
+
kind,
|
|
8199
|
+
parentKind: null,
|
|
8200
|
+
level: "macro",
|
|
8201
|
+
category,
|
|
8202
|
+
color,
|
|
8203
|
+
iconId,
|
|
8204
|
+
labelKey: `eventKind.${kind}`,
|
|
8205
|
+
label
|
|
8206
|
+
});
|
|
8207
|
+
}
|
|
8208
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8209
|
+
entries.set(kind, {
|
|
8210
|
+
kind,
|
|
8211
|
+
parentKind,
|
|
8212
|
+
level: "sub",
|
|
8213
|
+
category,
|
|
8214
|
+
color,
|
|
8215
|
+
iconId,
|
|
8216
|
+
labelKey: `eventKind.${kind}`,
|
|
8217
|
+
label
|
|
8218
|
+
});
|
|
8219
|
+
}
|
|
8220
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8221
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8222
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8223
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8224
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8225
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8226
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8227
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8228
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8229
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8230
|
+
if (entries.has(cocoClass)) continue;
|
|
8231
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8232
|
+
}
|
|
8233
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8234
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8235
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8236
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8237
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8238
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8239
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8240
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8241
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8242
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8243
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8244
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8245
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8246
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8247
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8248
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8249
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8250
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8251
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8252
|
+
const kind = `audio-${l.id}`;
|
|
8253
|
+
if (entries.has(kind)) continue;
|
|
8254
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8255
|
+
}
|
|
8256
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8257
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8258
|
+
/**
|
|
7930
8259
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7931
8260
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7932
8261
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15901,17 +16230,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15901
16230
|
"audio",
|
|
15902
16231
|
"detection",
|
|
15903
16232
|
"sensor",
|
|
16233
|
+
"control",
|
|
15904
16234
|
"custom",
|
|
15905
16235
|
"package"
|
|
15906
16236
|
]);
|
|
16237
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16238
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15907
16239
|
var EventKindDescriptorSchema = object({
|
|
15908
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16240
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15909
16241
|
kind: string(),
|
|
16242
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16243
|
+
labelKey: string(),
|
|
16244
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15910
16245
|
label: string(),
|
|
15911
16246
|
/** Hex color for timeline/legend rendering. */
|
|
15912
16247
|
color: string(),
|
|
16248
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16249
|
+
iconId: string(),
|
|
16250
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15913
16251
|
icon: EventKindIconSchema,
|
|
15914
16252
|
category: EventKindCategorySchema,
|
|
16253
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16254
|
+
parentKind: string().nullable(),
|
|
16255
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16256
|
+
level: EventKindLevelSchema,
|
|
15915
16257
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15916
16258
|
* itself; for sensor kinds the LINKED source device. */
|
|
15917
16259
|
source: object({
|
|
@@ -15984,11 +16326,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15984
16326
|
firstAt: number(),
|
|
15985
16327
|
lastAt: number()
|
|
15986
16328
|
});
|
|
16329
|
+
/**
|
|
16330
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16331
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16332
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16333
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16334
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16335
|
+
*/
|
|
16336
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15987
16337
|
var TrackSchema = object({
|
|
15988
16338
|
trackId: string(),
|
|
15989
16339
|
deviceId: number(),
|
|
15990
16340
|
className: string(),
|
|
15991
16341
|
label: string().optional(),
|
|
16342
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16343
|
+
source: TrackSourceSchema.optional(),
|
|
15992
16344
|
firstSeen: number(),
|
|
15993
16345
|
lastSeen: number(),
|
|
15994
16346
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16243,6 +16595,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16243
16595
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16244
16596
|
embeddings: number().int()
|
|
16245
16597
|
});
|
|
16598
|
+
/** Event-store footprint for one camera. */
|
|
16599
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16600
|
+
deviceId: number(),
|
|
16601
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16602
|
+
rows: number().int(),
|
|
16603
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16604
|
+
bytes: number().int()
|
|
16605
|
+
});
|
|
16606
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16607
|
+
var EventStoreFootprintSchema = object({
|
|
16608
|
+
totalRows: number().int(),
|
|
16609
|
+
totalBytes: number().int(),
|
|
16610
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16611
|
+
});
|
|
16612
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16613
|
+
var EventPruneCountsSchema = object({
|
|
16614
|
+
motion: number().int(),
|
|
16615
|
+
object: number().int(),
|
|
16616
|
+
audio: number().int()
|
|
16617
|
+
});
|
|
16246
16618
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16247
16619
|
deviceId: number(),
|
|
16248
16620
|
trackId: string()
|
|
@@ -16306,6 +16678,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16306
16678
|
}), {
|
|
16307
16679
|
kind: "mutation",
|
|
16308
16680
|
auth: "admin"
|
|
16681
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16682
|
+
kind: "query",
|
|
16683
|
+
auth: "admin"
|
|
16684
|
+
}), method(object({
|
|
16685
|
+
olderThanMs: number(),
|
|
16686
|
+
reason: OpsLogReasonSchema.optional()
|
|
16687
|
+
}), EventPruneCountsSchema, {
|
|
16688
|
+
kind: "mutation",
|
|
16689
|
+
auth: "admin"
|
|
16690
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16691
|
+
kind: "mutation",
|
|
16692
|
+
auth: "admin"
|
|
16693
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16694
|
+
kind: "query",
|
|
16695
|
+
auth: "admin"
|
|
16309
16696
|
}), method(object({
|
|
16310
16697
|
eventId: string(),
|
|
16311
16698
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16330,6 +16717,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16330
16717
|
eventId: string(),
|
|
16331
16718
|
timestamp: number()
|
|
16332
16719
|
});
|
|
16720
|
+
/**
|
|
16721
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16722
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16723
|
+
* caps into per-camera event-kind descriptors.
|
|
16724
|
+
*
|
|
16725
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16726
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16727
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16728
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16729
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16730
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16731
|
+
* eventful cap is missing.
|
|
16732
|
+
*/
|
|
16733
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16734
|
+
var LEGACY_ICON = {
|
|
16735
|
+
motion: "motion",
|
|
16736
|
+
audio: "audio",
|
|
16737
|
+
person: "person",
|
|
16738
|
+
vehicle: "vehicle",
|
|
16739
|
+
animal: "animal",
|
|
16740
|
+
package: "package",
|
|
16741
|
+
door: "door",
|
|
16742
|
+
pir: "pir",
|
|
16743
|
+
smoke: "smoke",
|
|
16744
|
+
water: "water",
|
|
16745
|
+
button: "button",
|
|
16746
|
+
generic: "generic",
|
|
16747
|
+
gas: "smoke",
|
|
16748
|
+
vibration: "generic",
|
|
16749
|
+
tamper: "generic",
|
|
16750
|
+
presence: "person",
|
|
16751
|
+
lock: "generic",
|
|
16752
|
+
siren: "generic",
|
|
16753
|
+
switch: "generic",
|
|
16754
|
+
doorbell: "button"
|
|
16755
|
+
};
|
|
16756
|
+
function legacyIcon(iconId) {
|
|
16757
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16758
|
+
}
|
|
16759
|
+
/**
|
|
16760
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16761
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16762
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16763
|
+
*/
|
|
16764
|
+
var CAP_TO_KIND = {
|
|
16765
|
+
contact: "contact",
|
|
16766
|
+
motion: "motion-sensor",
|
|
16767
|
+
smoke: "smoke",
|
|
16768
|
+
flood: "flood",
|
|
16769
|
+
gas: "gas",
|
|
16770
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16771
|
+
vibration: "vibration",
|
|
16772
|
+
tamper: "tamper",
|
|
16773
|
+
presence: "presence",
|
|
16774
|
+
"enum-sensor": "enum-sensor",
|
|
16775
|
+
"event-emitter": "device-event",
|
|
16776
|
+
"lock-control": "lock",
|
|
16777
|
+
switch: "switch",
|
|
16778
|
+
button: "button",
|
|
16779
|
+
doorbell: "doorbell"
|
|
16780
|
+
};
|
|
16781
|
+
function buildDescriptor(capName, kind) {
|
|
16782
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16783
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16784
|
+
return {
|
|
16785
|
+
...t,
|
|
16786
|
+
icon: legacyIcon(t.iconId)
|
|
16787
|
+
};
|
|
16788
|
+
}
|
|
16789
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16333
16790
|
var CameraPipelineConfigSchema = object({
|
|
16334
16791
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16335
16792
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19539,13 +19996,29 @@ method(object({
|
|
|
19539
19996
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19540
19997
|
kind: "mutation",
|
|
19541
19998
|
auth: "admin"
|
|
19542
|
-
}), method(object({
|
|
19999
|
+
}), method(object({
|
|
20000
|
+
deviceId: number(),
|
|
20001
|
+
reason: OpsLogReasonSchema.optional()
|
|
20002
|
+
}), object({
|
|
19543
20003
|
floorMs: number().nullable(),
|
|
19544
20004
|
deletedBuckets: number().int(),
|
|
19545
20005
|
reclaimedBytes: number().int()
|
|
19546
20006
|
}), {
|
|
19547
20007
|
kind: "mutation",
|
|
19548
20008
|
auth: "admin"
|
|
20009
|
+
}), method(object({
|
|
20010
|
+
deviceId: number(),
|
|
20011
|
+
fromMs: number().optional(),
|
|
20012
|
+
toMs: number().optional()
|
|
20013
|
+
}), object({
|
|
20014
|
+
deletedBuckets: number().int(),
|
|
20015
|
+
reclaimedBytes: number().int()
|
|
20016
|
+
}), {
|
|
20017
|
+
kind: "mutation",
|
|
20018
|
+
auth: "admin"
|
|
20019
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20020
|
+
kind: "query",
|
|
20021
|
+
auth: "admin"
|
|
19549
20022
|
});
|
|
19550
20023
|
/**
|
|
19551
20024
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22667,6 +23140,12 @@ Object.freeze({
|
|
|
22667
23140
|
addonId: null,
|
|
22668
23141
|
access: "delete"
|
|
22669
23142
|
},
|
|
23143
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23144
|
+
capName: "pipeline-analytics",
|
|
23145
|
+
capScope: "device",
|
|
23146
|
+
addonId: null,
|
|
23147
|
+
access: "delete"
|
|
23148
|
+
},
|
|
22670
23149
|
"pipelineAnalytics.deleteTracks": {
|
|
22671
23150
|
capName: "pipeline-analytics",
|
|
22672
23151
|
capScope: "device",
|
|
@@ -22697,6 +23176,12 @@ Object.freeze({
|
|
|
22697
23176
|
addonId: null,
|
|
22698
23177
|
access: "view"
|
|
22699
23178
|
},
|
|
23179
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23180
|
+
capName: "pipeline-analytics",
|
|
23181
|
+
capScope: "device",
|
|
23182
|
+
addonId: null,
|
|
23183
|
+
access: "view"
|
|
23184
|
+
},
|
|
22700
23185
|
"pipelineAnalytics.getKeyEvents": {
|
|
22701
23186
|
capName: "pipeline-analytics",
|
|
22702
23187
|
capScope: "device",
|
|
@@ -22739,6 +23224,12 @@ Object.freeze({
|
|
|
22739
23224
|
addonId: null,
|
|
22740
23225
|
access: "view"
|
|
22741
23226
|
},
|
|
23227
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23228
|
+
capName: "pipeline-analytics",
|
|
23229
|
+
capScope: "device",
|
|
23230
|
+
addonId: null,
|
|
23231
|
+
access: "view"
|
|
23232
|
+
},
|
|
22742
23233
|
"pipelineAnalytics.listRecentTracks": {
|
|
22743
23234
|
capName: "pipeline-analytics",
|
|
22744
23235
|
capScope: "device",
|
|
@@ -22751,6 +23242,12 @@ Object.freeze({
|
|
|
22751
23242
|
addonId: null,
|
|
22752
23243
|
access: "view"
|
|
22753
23244
|
},
|
|
23245
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23246
|
+
capName: "pipeline-analytics",
|
|
23247
|
+
capScope: "device",
|
|
23248
|
+
addonId: null,
|
|
23249
|
+
access: "create"
|
|
23250
|
+
},
|
|
22754
23251
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22755
23252
|
capName: "pipeline-analytics",
|
|
22756
23253
|
capScope: "device",
|
|
@@ -23513,6 +24010,12 @@ Object.freeze({
|
|
|
23513
24010
|
addonId: null,
|
|
23514
24011
|
access: "create"
|
|
23515
24012
|
},
|
|
24013
|
+
"recording.deleteFootprint": {
|
|
24014
|
+
capName: "recording",
|
|
24015
|
+
capScope: "system",
|
|
24016
|
+
addonId: null,
|
|
24017
|
+
access: "delete"
|
|
24018
|
+
},
|
|
23516
24019
|
"recording.getAvailability": {
|
|
23517
24020
|
capName: "recording",
|
|
23518
24021
|
capScope: "system",
|
|
@@ -23543,6 +24046,12 @@ Object.freeze({
|
|
|
23543
24046
|
addonId: null,
|
|
23544
24047
|
access: "view"
|
|
23545
24048
|
},
|
|
24049
|
+
"recording.listOpsLog": {
|
|
24050
|
+
capName: "recording",
|
|
24051
|
+
capScope: "system",
|
|
24052
|
+
addonId: null,
|
|
24053
|
+
access: "view"
|
|
24054
|
+
},
|
|
23546
24055
|
"recording.locateSegment": {
|
|
23547
24056
|
capName: "recording",
|
|
23548
24057
|
capScope: "system",
|
|
@@ -7339,6 +7339,62 @@ var RecordingConfigSchema = object({
|
|
|
7339
7339
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7340
7340
|
});
|
|
7341
7341
|
/**
|
|
7342
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7343
|
+
* recordings and events management surfaces.
|
|
7344
|
+
*
|
|
7345
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7346
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7347
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7348
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7349
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7350
|
+
* never fail the operation it records.
|
|
7351
|
+
*/
|
|
7352
|
+
/** Which management domain the operation belongs to. */
|
|
7353
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7354
|
+
/** The kind of management operation performed. */
|
|
7355
|
+
var OpsLogOpSchema = _enum([
|
|
7356
|
+
"prune",
|
|
7357
|
+
"manual-delete",
|
|
7358
|
+
"rescan",
|
|
7359
|
+
"retention-run"
|
|
7360
|
+
]);
|
|
7361
|
+
/** Why the operation ran. */
|
|
7362
|
+
var OpsLogReasonSchema = _enum([
|
|
7363
|
+
"retention",
|
|
7364
|
+
"quota",
|
|
7365
|
+
"manual",
|
|
7366
|
+
"operator"
|
|
7367
|
+
]);
|
|
7368
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7369
|
+
var OpsLogEntrySchema = object({
|
|
7370
|
+
/** Unique row id. */
|
|
7371
|
+
id: string(),
|
|
7372
|
+
/** Epoch ms the operation completed. */
|
|
7373
|
+
at: number(),
|
|
7374
|
+
domain: OpsLogDomainSchema,
|
|
7375
|
+
op: OpsLogOpSchema,
|
|
7376
|
+
reason: OpsLogReasonSchema,
|
|
7377
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7378
|
+
deviceId: number().nullable(),
|
|
7379
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7380
|
+
nodeId: string(),
|
|
7381
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7382
|
+
itemsAffected: number(),
|
|
7383
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7384
|
+
bytesReclaimed: number(),
|
|
7385
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7386
|
+
detail: string().nullable(),
|
|
7387
|
+
/** Who/what triggered the op. */
|
|
7388
|
+
actor: string()
|
|
7389
|
+
});
|
|
7390
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7391
|
+
var OpsLogQueryInputSchema = object({
|
|
7392
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7393
|
+
deviceId: number().optional(),
|
|
7394
|
+
/** Max rows returned, newest-first. */
|
|
7395
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7396
|
+
});
|
|
7397
|
+
/**
|
|
7342
7398
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7343
7399
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7344
7400
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7636,6 +7692,160 @@ function pickClosestResolution(entries, target) {
|
|
|
7636
7692
|
}
|
|
7637
7693
|
return bestAbove?.entry ?? bestBelow?.entry;
|
|
7638
7694
|
}
|
|
7695
|
+
var COCO_TO_MACRO = {
|
|
7696
|
+
mapping: {
|
|
7697
|
+
person: "person",
|
|
7698
|
+
bicycle: "vehicle",
|
|
7699
|
+
car: "vehicle",
|
|
7700
|
+
motorcycle: "vehicle",
|
|
7701
|
+
airplane: "vehicle",
|
|
7702
|
+
bus: "vehicle",
|
|
7703
|
+
train: "vehicle",
|
|
7704
|
+
truck: "vehicle",
|
|
7705
|
+
boat: "vehicle",
|
|
7706
|
+
bird: "animal",
|
|
7707
|
+
cat: "animal",
|
|
7708
|
+
dog: "animal",
|
|
7709
|
+
horse: "animal",
|
|
7710
|
+
sheep: "animal",
|
|
7711
|
+
cow: "animal",
|
|
7712
|
+
elephant: "animal",
|
|
7713
|
+
bear: "animal",
|
|
7714
|
+
zebra: "animal",
|
|
7715
|
+
giraffe: "animal",
|
|
7716
|
+
suitcase: "package",
|
|
7717
|
+
backpack: "package",
|
|
7718
|
+
handbag: "package"
|
|
7719
|
+
},
|
|
7720
|
+
preserveOriginal: false
|
|
7721
|
+
};
|
|
7722
|
+
var AUDIO_MACRO_LABELS = [
|
|
7723
|
+
{
|
|
7724
|
+
id: "speech",
|
|
7725
|
+
name: "Speech",
|
|
7726
|
+
icon: "🗣️"
|
|
7727
|
+
},
|
|
7728
|
+
{
|
|
7729
|
+
id: "scream",
|
|
7730
|
+
name: "Scream / Shout",
|
|
7731
|
+
icon: "😱"
|
|
7732
|
+
},
|
|
7733
|
+
{
|
|
7734
|
+
id: "crying",
|
|
7735
|
+
name: "Crying / Baby",
|
|
7736
|
+
icon: "😢"
|
|
7737
|
+
},
|
|
7738
|
+
{
|
|
7739
|
+
id: "laughter",
|
|
7740
|
+
name: "Laughter",
|
|
7741
|
+
icon: "😂"
|
|
7742
|
+
},
|
|
7743
|
+
{
|
|
7744
|
+
id: "music",
|
|
7745
|
+
name: "Music",
|
|
7746
|
+
icon: "🎵"
|
|
7747
|
+
},
|
|
7748
|
+
{
|
|
7749
|
+
id: "dog",
|
|
7750
|
+
name: "Dog",
|
|
7751
|
+
icon: "🐕"
|
|
7752
|
+
},
|
|
7753
|
+
{
|
|
7754
|
+
id: "cat",
|
|
7755
|
+
name: "Cat",
|
|
7756
|
+
icon: "🐈"
|
|
7757
|
+
},
|
|
7758
|
+
{
|
|
7759
|
+
id: "bird",
|
|
7760
|
+
name: "Bird",
|
|
7761
|
+
icon: "🐦"
|
|
7762
|
+
},
|
|
7763
|
+
{
|
|
7764
|
+
id: "animal",
|
|
7765
|
+
name: "Animal (other)",
|
|
7766
|
+
icon: "🐾"
|
|
7767
|
+
},
|
|
7768
|
+
{
|
|
7769
|
+
id: "alarm",
|
|
7770
|
+
name: "Alarm / Siren",
|
|
7771
|
+
icon: "🚨"
|
|
7772
|
+
},
|
|
7773
|
+
{
|
|
7774
|
+
id: "doorbell",
|
|
7775
|
+
name: "Doorbell / Knock",
|
|
7776
|
+
icon: "🔔"
|
|
7777
|
+
},
|
|
7778
|
+
{
|
|
7779
|
+
id: "glass_breaking",
|
|
7780
|
+
name: "Glass Breaking",
|
|
7781
|
+
icon: "💥"
|
|
7782
|
+
},
|
|
7783
|
+
{
|
|
7784
|
+
id: "gunshot",
|
|
7785
|
+
name: "Gunshot / Explosion",
|
|
7786
|
+
icon: "💣"
|
|
7787
|
+
},
|
|
7788
|
+
{
|
|
7789
|
+
id: "vehicle",
|
|
7790
|
+
name: "Vehicle",
|
|
7791
|
+
icon: "🚗"
|
|
7792
|
+
},
|
|
7793
|
+
{
|
|
7794
|
+
id: "siren",
|
|
7795
|
+
name: "Emergency Siren",
|
|
7796
|
+
icon: "🚑"
|
|
7797
|
+
},
|
|
7798
|
+
{
|
|
7799
|
+
id: "fire",
|
|
7800
|
+
name: "Fire / Smoke",
|
|
7801
|
+
icon: "🔥"
|
|
7802
|
+
},
|
|
7803
|
+
{
|
|
7804
|
+
id: "water",
|
|
7805
|
+
name: "Water",
|
|
7806
|
+
icon: "💧"
|
|
7807
|
+
},
|
|
7808
|
+
{
|
|
7809
|
+
id: "wind",
|
|
7810
|
+
name: "Wind / Weather",
|
|
7811
|
+
icon: "🌬️"
|
|
7812
|
+
},
|
|
7813
|
+
{
|
|
7814
|
+
id: "door",
|
|
7815
|
+
name: "Door",
|
|
7816
|
+
icon: "🚪"
|
|
7817
|
+
},
|
|
7818
|
+
{
|
|
7819
|
+
id: "footsteps",
|
|
7820
|
+
name: "Footsteps",
|
|
7821
|
+
icon: "👣"
|
|
7822
|
+
},
|
|
7823
|
+
{
|
|
7824
|
+
id: "crowd",
|
|
7825
|
+
name: "Crowd / Chatter",
|
|
7826
|
+
icon: "👥"
|
|
7827
|
+
},
|
|
7828
|
+
{
|
|
7829
|
+
id: "telephone",
|
|
7830
|
+
name: "Telephone",
|
|
7831
|
+
icon: "📞"
|
|
7832
|
+
},
|
|
7833
|
+
{
|
|
7834
|
+
id: "engine",
|
|
7835
|
+
name: "Engine / Motor",
|
|
7836
|
+
icon: "⚙️"
|
|
7837
|
+
},
|
|
7838
|
+
{
|
|
7839
|
+
id: "tools",
|
|
7840
|
+
name: "Tools / Construction",
|
|
7841
|
+
icon: "🔨"
|
|
7842
|
+
},
|
|
7843
|
+
{
|
|
7844
|
+
id: "silence",
|
|
7845
|
+
name: "Silence",
|
|
7846
|
+
icon: "🤫"
|
|
7847
|
+
}
|
|
7848
|
+
];
|
|
7639
7849
|
var YAMNET_TO_MACRO = {
|
|
7640
7850
|
mapping: {
|
|
7641
7851
|
Speech: "speech",
|
|
@@ -7902,6 +8112,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
7902
8112
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7903
8113
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
7904
8114
|
/**
|
|
8115
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8116
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8117
|
+
* icon }`.
|
|
8118
|
+
*
|
|
8119
|
+
* This dictionary folds together what used to be scattered across four
|
|
8120
|
+
* copies:
|
|
8121
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8122
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8123
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8124
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8125
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8126
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8127
|
+
*
|
|
8128
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8129
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8130
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8131
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8132
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8133
|
+
*
|
|
8134
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8135
|
+
*/
|
|
8136
|
+
var TAXONOMY_COLORS = {
|
|
8137
|
+
motion: "#f59e0b",
|
|
8138
|
+
audio: "#06b6d4",
|
|
8139
|
+
person: "#22c55e",
|
|
8140
|
+
vehicle: "#3b82f6",
|
|
8141
|
+
animal: "#f97316",
|
|
8142
|
+
package: "#a855f7",
|
|
8143
|
+
sensor: "#8b5cf6",
|
|
8144
|
+
control: "#10b981",
|
|
8145
|
+
genericDetection: "#64748b"
|
|
8146
|
+
};
|
|
8147
|
+
var DETECTION_SUB_COLORS = {
|
|
8148
|
+
car: "#f59e0b",
|
|
8149
|
+
truck: "#d97706",
|
|
8150
|
+
bus: "#b45309",
|
|
8151
|
+
motorcycle: "#eab308",
|
|
8152
|
+
bicycle: "#ca8a04",
|
|
8153
|
+
airplane: "#60a5fa",
|
|
8154
|
+
boat: "#2563eb",
|
|
8155
|
+
train: "#1d4ed8",
|
|
8156
|
+
bird: "#14b8a6",
|
|
8157
|
+
dog: "#84cc16",
|
|
8158
|
+
cat: "#f97316",
|
|
8159
|
+
horse: "#a16207",
|
|
8160
|
+
sheep: "#a3a3a3",
|
|
8161
|
+
cow: "#78716c",
|
|
8162
|
+
elephant: "#6b7280",
|
|
8163
|
+
bear: "#7c2d12",
|
|
8164
|
+
zebra: "#404040",
|
|
8165
|
+
giraffe: "#d4a373"
|
|
8166
|
+
};
|
|
8167
|
+
function titleCase(id) {
|
|
8168
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8169
|
+
}
|
|
8170
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8171
|
+
function macro(kind, category, color, iconId, label) {
|
|
8172
|
+
entries.set(kind, {
|
|
8173
|
+
kind,
|
|
8174
|
+
parentKind: null,
|
|
8175
|
+
level: "macro",
|
|
8176
|
+
category,
|
|
8177
|
+
color,
|
|
8178
|
+
iconId,
|
|
8179
|
+
labelKey: `eventKind.${kind}`,
|
|
8180
|
+
label
|
|
8181
|
+
});
|
|
8182
|
+
}
|
|
8183
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8184
|
+
entries.set(kind, {
|
|
8185
|
+
kind,
|
|
8186
|
+
parentKind,
|
|
8187
|
+
level: "sub",
|
|
8188
|
+
category,
|
|
8189
|
+
color,
|
|
8190
|
+
iconId,
|
|
8191
|
+
labelKey: `eventKind.${kind}`,
|
|
8192
|
+
label
|
|
8193
|
+
});
|
|
8194
|
+
}
|
|
8195
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8196
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8197
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8198
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8199
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8200
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8201
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8202
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8203
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8204
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8205
|
+
if (entries.has(cocoClass)) continue;
|
|
8206
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8207
|
+
}
|
|
8208
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8209
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8210
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8211
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8212
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8213
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8214
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8215
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8216
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8217
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8218
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8219
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8220
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8221
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8222
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8223
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8224
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8225
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8226
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8227
|
+
const kind = `audio-${l.id}`;
|
|
8228
|
+
if (entries.has(kind)) continue;
|
|
8229
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8230
|
+
}
|
|
8231
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8232
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8233
|
+
/**
|
|
7905
8234
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
7906
8235
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
7907
8236
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -15876,17 +16205,30 @@ var EventKindCategorySchema = _enum([
|
|
|
15876
16205
|
"audio",
|
|
15877
16206
|
"detection",
|
|
15878
16207
|
"sensor",
|
|
16208
|
+
"control",
|
|
15879
16209
|
"custom",
|
|
15880
16210
|
"package"
|
|
15881
16211
|
]);
|
|
16212
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16213
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
15882
16214
|
var EventKindDescriptorSchema = object({
|
|
15883
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16215
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
15884
16216
|
kind: string(),
|
|
16217
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16218
|
+
labelKey: string(),
|
|
16219
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
15885
16220
|
label: string(),
|
|
15886
16221
|
/** Hex color for timeline/legend rendering. */
|
|
15887
16222
|
color: string(),
|
|
16223
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16224
|
+
iconId: string(),
|
|
16225
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
15888
16226
|
icon: EventKindIconSchema,
|
|
15889
16227
|
category: EventKindCategorySchema,
|
|
16228
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16229
|
+
parentKind: string().nullable(),
|
|
16230
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16231
|
+
level: EventKindLevelSchema,
|
|
15890
16232
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
15891
16233
|
* itself; for sensor kinds the LINKED source device. */
|
|
15892
16234
|
source: object({
|
|
@@ -15959,11 +16301,21 @@ var TrackAudioLabelSchema = object({
|
|
|
15959
16301
|
firstAt: number(),
|
|
15960
16302
|
lastAt: number()
|
|
15961
16303
|
});
|
|
16304
|
+
/**
|
|
16305
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16306
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16307
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16308
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16309
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16310
|
+
*/
|
|
16311
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
15962
16312
|
var TrackSchema = object({
|
|
15963
16313
|
trackId: string(),
|
|
15964
16314
|
deviceId: number(),
|
|
15965
16315
|
className: string(),
|
|
15966
16316
|
label: string().optional(),
|
|
16317
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16318
|
+
source: TrackSourceSchema.optional(),
|
|
15967
16319
|
firstSeen: number(),
|
|
15968
16320
|
lastSeen: number(),
|
|
15969
16321
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16218,6 +16570,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16218
16570
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16219
16571
|
embeddings: number().int()
|
|
16220
16572
|
});
|
|
16573
|
+
/** Event-store footprint for one camera. */
|
|
16574
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16575
|
+
deviceId: number(),
|
|
16576
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16577
|
+
rows: number().int(),
|
|
16578
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16579
|
+
bytes: number().int()
|
|
16580
|
+
});
|
|
16581
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16582
|
+
var EventStoreFootprintSchema = object({
|
|
16583
|
+
totalRows: number().int(),
|
|
16584
|
+
totalBytes: number().int(),
|
|
16585
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16586
|
+
});
|
|
16587
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16588
|
+
var EventPruneCountsSchema = object({
|
|
16589
|
+
motion: number().int(),
|
|
16590
|
+
object: number().int(),
|
|
16591
|
+
audio: number().int()
|
|
16592
|
+
});
|
|
16221
16593
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16222
16594
|
deviceId: number(),
|
|
16223
16595
|
trackId: string()
|
|
@@ -16281,6 +16653,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16281
16653
|
}), {
|
|
16282
16654
|
kind: "mutation",
|
|
16283
16655
|
auth: "admin"
|
|
16656
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16657
|
+
kind: "query",
|
|
16658
|
+
auth: "admin"
|
|
16659
|
+
}), method(object({
|
|
16660
|
+
olderThanMs: number(),
|
|
16661
|
+
reason: OpsLogReasonSchema.optional()
|
|
16662
|
+
}), EventPruneCountsSchema, {
|
|
16663
|
+
kind: "mutation",
|
|
16664
|
+
auth: "admin"
|
|
16665
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16666
|
+
kind: "mutation",
|
|
16667
|
+
auth: "admin"
|
|
16668
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16669
|
+
kind: "query",
|
|
16670
|
+
auth: "admin"
|
|
16284
16671
|
}), method(object({
|
|
16285
16672
|
eventId: string(),
|
|
16286
16673
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16305,6 +16692,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16305
16692
|
eventId: string(),
|
|
16306
16693
|
timestamp: number()
|
|
16307
16694
|
});
|
|
16695
|
+
/**
|
|
16696
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16697
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16698
|
+
* caps into per-camera event-kind descriptors.
|
|
16699
|
+
*
|
|
16700
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16701
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16702
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16703
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16704
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16705
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16706
|
+
* eventful cap is missing.
|
|
16707
|
+
*/
|
|
16708
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16709
|
+
var LEGACY_ICON = {
|
|
16710
|
+
motion: "motion",
|
|
16711
|
+
audio: "audio",
|
|
16712
|
+
person: "person",
|
|
16713
|
+
vehicle: "vehicle",
|
|
16714
|
+
animal: "animal",
|
|
16715
|
+
package: "package",
|
|
16716
|
+
door: "door",
|
|
16717
|
+
pir: "pir",
|
|
16718
|
+
smoke: "smoke",
|
|
16719
|
+
water: "water",
|
|
16720
|
+
button: "button",
|
|
16721
|
+
generic: "generic",
|
|
16722
|
+
gas: "smoke",
|
|
16723
|
+
vibration: "generic",
|
|
16724
|
+
tamper: "generic",
|
|
16725
|
+
presence: "person",
|
|
16726
|
+
lock: "generic",
|
|
16727
|
+
siren: "generic",
|
|
16728
|
+
switch: "generic",
|
|
16729
|
+
doorbell: "button"
|
|
16730
|
+
};
|
|
16731
|
+
function legacyIcon(iconId) {
|
|
16732
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16733
|
+
}
|
|
16734
|
+
/**
|
|
16735
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16736
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16737
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16738
|
+
*/
|
|
16739
|
+
var CAP_TO_KIND = {
|
|
16740
|
+
contact: "contact",
|
|
16741
|
+
motion: "motion-sensor",
|
|
16742
|
+
smoke: "smoke",
|
|
16743
|
+
flood: "flood",
|
|
16744
|
+
gas: "gas",
|
|
16745
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16746
|
+
vibration: "vibration",
|
|
16747
|
+
tamper: "tamper",
|
|
16748
|
+
presence: "presence",
|
|
16749
|
+
"enum-sensor": "enum-sensor",
|
|
16750
|
+
"event-emitter": "device-event",
|
|
16751
|
+
"lock-control": "lock",
|
|
16752
|
+
switch: "switch",
|
|
16753
|
+
button: "button",
|
|
16754
|
+
doorbell: "doorbell"
|
|
16755
|
+
};
|
|
16756
|
+
function buildDescriptor(capName, kind) {
|
|
16757
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16758
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16759
|
+
return {
|
|
16760
|
+
...t,
|
|
16761
|
+
icon: legacyIcon(t.iconId)
|
|
16762
|
+
};
|
|
16763
|
+
}
|
|
16764
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16308
16765
|
var CameraPipelineConfigSchema = object({
|
|
16309
16766
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16310
16767
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19514,13 +19971,29 @@ method(object({
|
|
|
19514
19971
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19515
19972
|
kind: "mutation",
|
|
19516
19973
|
auth: "admin"
|
|
19517
|
-
}), method(object({
|
|
19974
|
+
}), method(object({
|
|
19975
|
+
deviceId: number(),
|
|
19976
|
+
reason: OpsLogReasonSchema.optional()
|
|
19977
|
+
}), object({
|
|
19518
19978
|
floorMs: number().nullable(),
|
|
19519
19979
|
deletedBuckets: number().int(),
|
|
19520
19980
|
reclaimedBytes: number().int()
|
|
19521
19981
|
}), {
|
|
19522
19982
|
kind: "mutation",
|
|
19523
19983
|
auth: "admin"
|
|
19984
|
+
}), method(object({
|
|
19985
|
+
deviceId: number(),
|
|
19986
|
+
fromMs: number().optional(),
|
|
19987
|
+
toMs: number().optional()
|
|
19988
|
+
}), object({
|
|
19989
|
+
deletedBuckets: number().int(),
|
|
19990
|
+
reclaimedBytes: number().int()
|
|
19991
|
+
}), {
|
|
19992
|
+
kind: "mutation",
|
|
19993
|
+
auth: "admin"
|
|
19994
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19995
|
+
kind: "query",
|
|
19996
|
+
auth: "admin"
|
|
19524
19997
|
});
|
|
19525
19998
|
/**
|
|
19526
19999
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22642,6 +23115,12 @@ Object.freeze({
|
|
|
22642
23115
|
addonId: null,
|
|
22643
23116
|
access: "delete"
|
|
22644
23117
|
},
|
|
23118
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23119
|
+
capName: "pipeline-analytics",
|
|
23120
|
+
capScope: "device",
|
|
23121
|
+
addonId: null,
|
|
23122
|
+
access: "delete"
|
|
23123
|
+
},
|
|
22645
23124
|
"pipelineAnalytics.deleteTracks": {
|
|
22646
23125
|
capName: "pipeline-analytics",
|
|
22647
23126
|
capScope: "device",
|
|
@@ -22672,6 +23151,12 @@ Object.freeze({
|
|
|
22672
23151
|
addonId: null,
|
|
22673
23152
|
access: "view"
|
|
22674
23153
|
},
|
|
23154
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23155
|
+
capName: "pipeline-analytics",
|
|
23156
|
+
capScope: "device",
|
|
23157
|
+
addonId: null,
|
|
23158
|
+
access: "view"
|
|
23159
|
+
},
|
|
22675
23160
|
"pipelineAnalytics.getKeyEvents": {
|
|
22676
23161
|
capName: "pipeline-analytics",
|
|
22677
23162
|
capScope: "device",
|
|
@@ -22714,6 +23199,12 @@ Object.freeze({
|
|
|
22714
23199
|
addonId: null,
|
|
22715
23200
|
access: "view"
|
|
22716
23201
|
},
|
|
23202
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23203
|
+
capName: "pipeline-analytics",
|
|
23204
|
+
capScope: "device",
|
|
23205
|
+
addonId: null,
|
|
23206
|
+
access: "view"
|
|
23207
|
+
},
|
|
22717
23208
|
"pipelineAnalytics.listRecentTracks": {
|
|
22718
23209
|
capName: "pipeline-analytics",
|
|
22719
23210
|
capScope: "device",
|
|
@@ -22726,6 +23217,12 @@ Object.freeze({
|
|
|
22726
23217
|
addonId: null,
|
|
22727
23218
|
access: "view"
|
|
22728
23219
|
},
|
|
23220
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23221
|
+
capName: "pipeline-analytics",
|
|
23222
|
+
capScope: "device",
|
|
23223
|
+
addonId: null,
|
|
23224
|
+
access: "create"
|
|
23225
|
+
},
|
|
22729
23226
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22730
23227
|
capName: "pipeline-analytics",
|
|
22731
23228
|
capScope: "device",
|
|
@@ -23488,6 +23985,12 @@ Object.freeze({
|
|
|
23488
23985
|
addonId: null,
|
|
23489
23986
|
access: "create"
|
|
23490
23987
|
},
|
|
23988
|
+
"recording.deleteFootprint": {
|
|
23989
|
+
capName: "recording",
|
|
23990
|
+
capScope: "system",
|
|
23991
|
+
addonId: null,
|
|
23992
|
+
access: "delete"
|
|
23993
|
+
},
|
|
23491
23994
|
"recording.getAvailability": {
|
|
23492
23995
|
capName: "recording",
|
|
23493
23996
|
capScope: "system",
|
|
@@ -23518,6 +24021,12 @@ Object.freeze({
|
|
|
23518
24021
|
addonId: null,
|
|
23519
24022
|
access: "view"
|
|
23520
24023
|
},
|
|
24024
|
+
"recording.listOpsLog": {
|
|
24025
|
+
capName: "recording",
|
|
24026
|
+
capScope: "system",
|
|
24027
|
+
addonId: null,
|
|
24028
|
+
access: "view"
|
|
24029
|
+
},
|
|
23521
24030
|
"recording.locateSegment": {
|
|
23522
24031
|
capName: "recording",
|
|
23523
24032
|
capScope: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-hap",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.28",
|
|
4
4
|
"description": "HomeKit (HAP) bridge exporter for CamStack devices. Publishes a bridged accessory per exposed device — MotionSensor in this MVP; Camera/Doorbell/Switch/Light follow.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|