@camstack/addon-export-alexa 1.1.25 → 1.1.27
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-alexa.addon.js +511 -2
- package/dist/export-alexa.addon.mjs +511 -2
- package/package.json +1 -1
|
@@ -7495,6 +7495,62 @@ var RecordingConfigSchema = object({
|
|
|
7495
7495
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7496
7496
|
});
|
|
7497
7497
|
/**
|
|
7498
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7499
|
+
* recordings and events management surfaces.
|
|
7500
|
+
*
|
|
7501
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7502
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7503
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7504
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7505
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7506
|
+
* never fail the operation it records.
|
|
7507
|
+
*/
|
|
7508
|
+
/** Which management domain the operation belongs to. */
|
|
7509
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7510
|
+
/** The kind of management operation performed. */
|
|
7511
|
+
var OpsLogOpSchema = _enum([
|
|
7512
|
+
"prune",
|
|
7513
|
+
"manual-delete",
|
|
7514
|
+
"rescan",
|
|
7515
|
+
"retention-run"
|
|
7516
|
+
]);
|
|
7517
|
+
/** Why the operation ran. */
|
|
7518
|
+
var OpsLogReasonSchema = _enum([
|
|
7519
|
+
"retention",
|
|
7520
|
+
"quota",
|
|
7521
|
+
"manual",
|
|
7522
|
+
"operator"
|
|
7523
|
+
]);
|
|
7524
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7525
|
+
var OpsLogEntrySchema = object({
|
|
7526
|
+
/** Unique row id. */
|
|
7527
|
+
id: string(),
|
|
7528
|
+
/** Epoch ms the operation completed. */
|
|
7529
|
+
at: number(),
|
|
7530
|
+
domain: OpsLogDomainSchema,
|
|
7531
|
+
op: OpsLogOpSchema,
|
|
7532
|
+
reason: OpsLogReasonSchema,
|
|
7533
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7534
|
+
deviceId: number().nullable(),
|
|
7535
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7536
|
+
nodeId: string(),
|
|
7537
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7538
|
+
itemsAffected: number(),
|
|
7539
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7540
|
+
bytesReclaimed: number(),
|
|
7541
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7542
|
+
detail: string().nullable(),
|
|
7543
|
+
/** Who/what triggered the op. */
|
|
7544
|
+
actor: string()
|
|
7545
|
+
});
|
|
7546
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7547
|
+
var OpsLogQueryInputSchema = object({
|
|
7548
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7549
|
+
deviceId: number().optional(),
|
|
7550
|
+
/** Max rows returned, newest-first. */
|
|
7551
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7552
|
+
});
|
|
7553
|
+
/**
|
|
7498
7554
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7499
7555
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7500
7556
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7792,6 +7848,160 @@ function pickClosestResolution(entries, target) {
|
|
|
7792
7848
|
}
|
|
7793
7849
|
return bestAbove?.entry ?? bestBelow?.entry;
|
|
7794
7850
|
}
|
|
7851
|
+
var COCO_TO_MACRO = {
|
|
7852
|
+
mapping: {
|
|
7853
|
+
person: "person",
|
|
7854
|
+
bicycle: "vehicle",
|
|
7855
|
+
car: "vehicle",
|
|
7856
|
+
motorcycle: "vehicle",
|
|
7857
|
+
airplane: "vehicle",
|
|
7858
|
+
bus: "vehicle",
|
|
7859
|
+
train: "vehicle",
|
|
7860
|
+
truck: "vehicle",
|
|
7861
|
+
boat: "vehicle",
|
|
7862
|
+
bird: "animal",
|
|
7863
|
+
cat: "animal",
|
|
7864
|
+
dog: "animal",
|
|
7865
|
+
horse: "animal",
|
|
7866
|
+
sheep: "animal",
|
|
7867
|
+
cow: "animal",
|
|
7868
|
+
elephant: "animal",
|
|
7869
|
+
bear: "animal",
|
|
7870
|
+
zebra: "animal",
|
|
7871
|
+
giraffe: "animal",
|
|
7872
|
+
suitcase: "package",
|
|
7873
|
+
backpack: "package",
|
|
7874
|
+
handbag: "package"
|
|
7875
|
+
},
|
|
7876
|
+
preserveOriginal: false
|
|
7877
|
+
};
|
|
7878
|
+
var AUDIO_MACRO_LABELS = [
|
|
7879
|
+
{
|
|
7880
|
+
id: "speech",
|
|
7881
|
+
name: "Speech",
|
|
7882
|
+
icon: "🗣️"
|
|
7883
|
+
},
|
|
7884
|
+
{
|
|
7885
|
+
id: "scream",
|
|
7886
|
+
name: "Scream / Shout",
|
|
7887
|
+
icon: "😱"
|
|
7888
|
+
},
|
|
7889
|
+
{
|
|
7890
|
+
id: "crying",
|
|
7891
|
+
name: "Crying / Baby",
|
|
7892
|
+
icon: "😢"
|
|
7893
|
+
},
|
|
7894
|
+
{
|
|
7895
|
+
id: "laughter",
|
|
7896
|
+
name: "Laughter",
|
|
7897
|
+
icon: "😂"
|
|
7898
|
+
},
|
|
7899
|
+
{
|
|
7900
|
+
id: "music",
|
|
7901
|
+
name: "Music",
|
|
7902
|
+
icon: "🎵"
|
|
7903
|
+
},
|
|
7904
|
+
{
|
|
7905
|
+
id: "dog",
|
|
7906
|
+
name: "Dog",
|
|
7907
|
+
icon: "🐕"
|
|
7908
|
+
},
|
|
7909
|
+
{
|
|
7910
|
+
id: "cat",
|
|
7911
|
+
name: "Cat",
|
|
7912
|
+
icon: "🐈"
|
|
7913
|
+
},
|
|
7914
|
+
{
|
|
7915
|
+
id: "bird",
|
|
7916
|
+
name: "Bird",
|
|
7917
|
+
icon: "🐦"
|
|
7918
|
+
},
|
|
7919
|
+
{
|
|
7920
|
+
id: "animal",
|
|
7921
|
+
name: "Animal (other)",
|
|
7922
|
+
icon: "🐾"
|
|
7923
|
+
},
|
|
7924
|
+
{
|
|
7925
|
+
id: "alarm",
|
|
7926
|
+
name: "Alarm / Siren",
|
|
7927
|
+
icon: "🚨"
|
|
7928
|
+
},
|
|
7929
|
+
{
|
|
7930
|
+
id: "doorbell",
|
|
7931
|
+
name: "Doorbell / Knock",
|
|
7932
|
+
icon: "🔔"
|
|
7933
|
+
},
|
|
7934
|
+
{
|
|
7935
|
+
id: "glass_breaking",
|
|
7936
|
+
name: "Glass Breaking",
|
|
7937
|
+
icon: "💥"
|
|
7938
|
+
},
|
|
7939
|
+
{
|
|
7940
|
+
id: "gunshot",
|
|
7941
|
+
name: "Gunshot / Explosion",
|
|
7942
|
+
icon: "💣"
|
|
7943
|
+
},
|
|
7944
|
+
{
|
|
7945
|
+
id: "vehicle",
|
|
7946
|
+
name: "Vehicle",
|
|
7947
|
+
icon: "🚗"
|
|
7948
|
+
},
|
|
7949
|
+
{
|
|
7950
|
+
id: "siren",
|
|
7951
|
+
name: "Emergency Siren",
|
|
7952
|
+
icon: "🚑"
|
|
7953
|
+
},
|
|
7954
|
+
{
|
|
7955
|
+
id: "fire",
|
|
7956
|
+
name: "Fire / Smoke",
|
|
7957
|
+
icon: "🔥"
|
|
7958
|
+
},
|
|
7959
|
+
{
|
|
7960
|
+
id: "water",
|
|
7961
|
+
name: "Water",
|
|
7962
|
+
icon: "💧"
|
|
7963
|
+
},
|
|
7964
|
+
{
|
|
7965
|
+
id: "wind",
|
|
7966
|
+
name: "Wind / Weather",
|
|
7967
|
+
icon: "🌬️"
|
|
7968
|
+
},
|
|
7969
|
+
{
|
|
7970
|
+
id: "door",
|
|
7971
|
+
name: "Door",
|
|
7972
|
+
icon: "🚪"
|
|
7973
|
+
},
|
|
7974
|
+
{
|
|
7975
|
+
id: "footsteps",
|
|
7976
|
+
name: "Footsteps",
|
|
7977
|
+
icon: "👣"
|
|
7978
|
+
},
|
|
7979
|
+
{
|
|
7980
|
+
id: "crowd",
|
|
7981
|
+
name: "Crowd / Chatter",
|
|
7982
|
+
icon: "👥"
|
|
7983
|
+
},
|
|
7984
|
+
{
|
|
7985
|
+
id: "telephone",
|
|
7986
|
+
name: "Telephone",
|
|
7987
|
+
icon: "📞"
|
|
7988
|
+
},
|
|
7989
|
+
{
|
|
7990
|
+
id: "engine",
|
|
7991
|
+
name: "Engine / Motor",
|
|
7992
|
+
icon: "⚙️"
|
|
7993
|
+
},
|
|
7994
|
+
{
|
|
7995
|
+
id: "tools",
|
|
7996
|
+
name: "Tools / Construction",
|
|
7997
|
+
icon: "🔨"
|
|
7998
|
+
},
|
|
7999
|
+
{
|
|
8000
|
+
id: "silence",
|
|
8001
|
+
name: "Silence",
|
|
8002
|
+
icon: "🤫"
|
|
8003
|
+
}
|
|
8004
|
+
];
|
|
7795
8005
|
var YAMNET_TO_MACRO = {
|
|
7796
8006
|
mapping: {
|
|
7797
8007
|
Speech: "speech",
|
|
@@ -8058,6 +8268,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
8058
8268
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
8059
8269
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
8060
8270
|
/**
|
|
8271
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8272
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8273
|
+
* icon }`.
|
|
8274
|
+
*
|
|
8275
|
+
* This dictionary folds together what used to be scattered across four
|
|
8276
|
+
* copies:
|
|
8277
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8278
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8279
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8280
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8281
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8282
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8283
|
+
*
|
|
8284
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8285
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8286
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8287
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8288
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8289
|
+
*
|
|
8290
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8291
|
+
*/
|
|
8292
|
+
var TAXONOMY_COLORS = {
|
|
8293
|
+
motion: "#f59e0b",
|
|
8294
|
+
audio: "#06b6d4",
|
|
8295
|
+
person: "#22c55e",
|
|
8296
|
+
vehicle: "#3b82f6",
|
|
8297
|
+
animal: "#f97316",
|
|
8298
|
+
package: "#a855f7",
|
|
8299
|
+
sensor: "#8b5cf6",
|
|
8300
|
+
control: "#10b981",
|
|
8301
|
+
genericDetection: "#64748b"
|
|
8302
|
+
};
|
|
8303
|
+
var DETECTION_SUB_COLORS = {
|
|
8304
|
+
car: "#f59e0b",
|
|
8305
|
+
truck: "#d97706",
|
|
8306
|
+
bus: "#b45309",
|
|
8307
|
+
motorcycle: "#eab308",
|
|
8308
|
+
bicycle: "#ca8a04",
|
|
8309
|
+
airplane: "#60a5fa",
|
|
8310
|
+
boat: "#2563eb",
|
|
8311
|
+
train: "#1d4ed8",
|
|
8312
|
+
bird: "#14b8a6",
|
|
8313
|
+
dog: "#84cc16",
|
|
8314
|
+
cat: "#f97316",
|
|
8315
|
+
horse: "#a16207",
|
|
8316
|
+
sheep: "#a3a3a3",
|
|
8317
|
+
cow: "#78716c",
|
|
8318
|
+
elephant: "#6b7280",
|
|
8319
|
+
bear: "#7c2d12",
|
|
8320
|
+
zebra: "#404040",
|
|
8321
|
+
giraffe: "#d4a373"
|
|
8322
|
+
};
|
|
8323
|
+
function titleCase(id) {
|
|
8324
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8325
|
+
}
|
|
8326
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8327
|
+
function macro(kind, category, color, iconId, label) {
|
|
8328
|
+
entries.set(kind, {
|
|
8329
|
+
kind,
|
|
8330
|
+
parentKind: null,
|
|
8331
|
+
level: "macro",
|
|
8332
|
+
category,
|
|
8333
|
+
color,
|
|
8334
|
+
iconId,
|
|
8335
|
+
labelKey: `eventKind.${kind}`,
|
|
8336
|
+
label
|
|
8337
|
+
});
|
|
8338
|
+
}
|
|
8339
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8340
|
+
entries.set(kind, {
|
|
8341
|
+
kind,
|
|
8342
|
+
parentKind,
|
|
8343
|
+
level: "sub",
|
|
8344
|
+
category,
|
|
8345
|
+
color,
|
|
8346
|
+
iconId,
|
|
8347
|
+
labelKey: `eventKind.${kind}`,
|
|
8348
|
+
label
|
|
8349
|
+
});
|
|
8350
|
+
}
|
|
8351
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8352
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8353
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8354
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8355
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8356
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8357
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8358
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8359
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8360
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8361
|
+
if (entries.has(cocoClass)) continue;
|
|
8362
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8363
|
+
}
|
|
8364
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8365
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8366
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8367
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8368
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8369
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8370
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8371
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8372
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8373
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8374
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8375
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8376
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8377
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8378
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8379
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8380
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8381
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8382
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8383
|
+
const kind = `audio-${l.id}`;
|
|
8384
|
+
if (entries.has(kind)) continue;
|
|
8385
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8386
|
+
}
|
|
8387
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8388
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8389
|
+
/**
|
|
8061
8390
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
8062
8391
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
8063
8392
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -16078,17 +16407,30 @@ var EventKindCategorySchema = _enum([
|
|
|
16078
16407
|
"audio",
|
|
16079
16408
|
"detection",
|
|
16080
16409
|
"sensor",
|
|
16410
|
+
"control",
|
|
16081
16411
|
"custom",
|
|
16082
16412
|
"package"
|
|
16083
16413
|
]);
|
|
16414
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16415
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
16084
16416
|
var EventKindDescriptorSchema = object({
|
|
16085
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16417
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
16086
16418
|
kind: string(),
|
|
16419
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16420
|
+
labelKey: string(),
|
|
16421
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
16087
16422
|
label: string(),
|
|
16088
16423
|
/** Hex color for timeline/legend rendering. */
|
|
16089
16424
|
color: string(),
|
|
16425
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16426
|
+
iconId: string(),
|
|
16427
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
16090
16428
|
icon: EventKindIconSchema,
|
|
16091
16429
|
category: EventKindCategorySchema,
|
|
16430
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16431
|
+
parentKind: string().nullable(),
|
|
16432
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16433
|
+
level: EventKindLevelSchema,
|
|
16092
16434
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
16093
16435
|
* itself; for sensor kinds the LINKED source device. */
|
|
16094
16436
|
source: object({
|
|
@@ -16161,11 +16503,21 @@ var TrackAudioLabelSchema = object({
|
|
|
16161
16503
|
firstAt: number(),
|
|
16162
16504
|
lastAt: number()
|
|
16163
16505
|
});
|
|
16506
|
+
/**
|
|
16507
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16508
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16509
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16510
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16511
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16512
|
+
*/
|
|
16513
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
16164
16514
|
var TrackSchema = object({
|
|
16165
16515
|
trackId: string(),
|
|
16166
16516
|
deviceId: number(),
|
|
16167
16517
|
className: string(),
|
|
16168
16518
|
label: string().optional(),
|
|
16519
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16520
|
+
source: TrackSourceSchema.optional(),
|
|
16169
16521
|
firstSeen: number(),
|
|
16170
16522
|
lastSeen: number(),
|
|
16171
16523
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16420,6 +16772,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16420
16772
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16421
16773
|
embeddings: number().int()
|
|
16422
16774
|
});
|
|
16775
|
+
/** Event-store footprint for one camera. */
|
|
16776
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16777
|
+
deviceId: number(),
|
|
16778
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16779
|
+
rows: number().int(),
|
|
16780
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16781
|
+
bytes: number().int()
|
|
16782
|
+
});
|
|
16783
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16784
|
+
var EventStoreFootprintSchema = object({
|
|
16785
|
+
totalRows: number().int(),
|
|
16786
|
+
totalBytes: number().int(),
|
|
16787
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16788
|
+
});
|
|
16789
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16790
|
+
var EventPruneCountsSchema = object({
|
|
16791
|
+
motion: number().int(),
|
|
16792
|
+
object: number().int(),
|
|
16793
|
+
audio: number().int()
|
|
16794
|
+
});
|
|
16423
16795
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16424
16796
|
deviceId: number(),
|
|
16425
16797
|
trackId: string()
|
|
@@ -16483,6 +16855,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16483
16855
|
}), {
|
|
16484
16856
|
kind: "mutation",
|
|
16485
16857
|
auth: "admin"
|
|
16858
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16859
|
+
kind: "query",
|
|
16860
|
+
auth: "admin"
|
|
16861
|
+
}), method(object({
|
|
16862
|
+
olderThanMs: number(),
|
|
16863
|
+
reason: OpsLogReasonSchema.optional()
|
|
16864
|
+
}), EventPruneCountsSchema, {
|
|
16865
|
+
kind: "mutation",
|
|
16866
|
+
auth: "admin"
|
|
16867
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16868
|
+
kind: "mutation",
|
|
16869
|
+
auth: "admin"
|
|
16870
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16871
|
+
kind: "query",
|
|
16872
|
+
auth: "admin"
|
|
16486
16873
|
}), method(object({
|
|
16487
16874
|
eventId: string(),
|
|
16488
16875
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16507,6 +16894,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16507
16894
|
eventId: string(),
|
|
16508
16895
|
timestamp: number()
|
|
16509
16896
|
});
|
|
16897
|
+
/**
|
|
16898
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16899
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16900
|
+
* caps into per-camera event-kind descriptors.
|
|
16901
|
+
*
|
|
16902
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16903
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16904
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16905
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16906
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16907
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16908
|
+
* eventful cap is missing.
|
|
16909
|
+
*/
|
|
16910
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16911
|
+
var LEGACY_ICON = {
|
|
16912
|
+
motion: "motion",
|
|
16913
|
+
audio: "audio",
|
|
16914
|
+
person: "person",
|
|
16915
|
+
vehicle: "vehicle",
|
|
16916
|
+
animal: "animal",
|
|
16917
|
+
package: "package",
|
|
16918
|
+
door: "door",
|
|
16919
|
+
pir: "pir",
|
|
16920
|
+
smoke: "smoke",
|
|
16921
|
+
water: "water",
|
|
16922
|
+
button: "button",
|
|
16923
|
+
generic: "generic",
|
|
16924
|
+
gas: "smoke",
|
|
16925
|
+
vibration: "generic",
|
|
16926
|
+
tamper: "generic",
|
|
16927
|
+
presence: "person",
|
|
16928
|
+
lock: "generic",
|
|
16929
|
+
siren: "generic",
|
|
16930
|
+
switch: "generic",
|
|
16931
|
+
doorbell: "button"
|
|
16932
|
+
};
|
|
16933
|
+
function legacyIcon(iconId) {
|
|
16934
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16935
|
+
}
|
|
16936
|
+
/**
|
|
16937
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16938
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16939
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16940
|
+
*/
|
|
16941
|
+
var CAP_TO_KIND = {
|
|
16942
|
+
contact: "contact",
|
|
16943
|
+
motion: "motion-sensor",
|
|
16944
|
+
smoke: "smoke",
|
|
16945
|
+
flood: "flood",
|
|
16946
|
+
gas: "gas",
|
|
16947
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16948
|
+
vibration: "vibration",
|
|
16949
|
+
tamper: "tamper",
|
|
16950
|
+
presence: "presence",
|
|
16951
|
+
"enum-sensor": "enum-sensor",
|
|
16952
|
+
"event-emitter": "device-event",
|
|
16953
|
+
"lock-control": "lock",
|
|
16954
|
+
switch: "switch",
|
|
16955
|
+
button: "button",
|
|
16956
|
+
doorbell: "doorbell"
|
|
16957
|
+
};
|
|
16958
|
+
function buildDescriptor(capName, kind) {
|
|
16959
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16960
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16961
|
+
return {
|
|
16962
|
+
...t,
|
|
16963
|
+
icon: legacyIcon(t.iconId)
|
|
16964
|
+
};
|
|
16965
|
+
}
|
|
16966
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16510
16967
|
var CameraPipelineConfigSchema = object({
|
|
16511
16968
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16512
16969
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19716,13 +20173,29 @@ method(object({
|
|
|
19716
20173
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19717
20174
|
kind: "mutation",
|
|
19718
20175
|
auth: "admin"
|
|
19719
|
-
}), method(object({
|
|
20176
|
+
}), method(object({
|
|
20177
|
+
deviceId: number(),
|
|
20178
|
+
reason: OpsLogReasonSchema.optional()
|
|
20179
|
+
}), object({
|
|
19720
20180
|
floorMs: number().nullable(),
|
|
19721
20181
|
deletedBuckets: number().int(),
|
|
19722
20182
|
reclaimedBytes: number().int()
|
|
19723
20183
|
}), {
|
|
19724
20184
|
kind: "mutation",
|
|
19725
20185
|
auth: "admin"
|
|
20186
|
+
}), method(object({
|
|
20187
|
+
deviceId: number(),
|
|
20188
|
+
fromMs: number().optional(),
|
|
20189
|
+
toMs: number().optional()
|
|
20190
|
+
}), object({
|
|
20191
|
+
deletedBuckets: number().int(),
|
|
20192
|
+
reclaimedBytes: number().int()
|
|
20193
|
+
}), {
|
|
20194
|
+
kind: "mutation",
|
|
20195
|
+
auth: "admin"
|
|
20196
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20197
|
+
kind: "query",
|
|
20198
|
+
auth: "admin"
|
|
19726
20199
|
});
|
|
19727
20200
|
/**
|
|
19728
20201
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22844,6 +23317,12 @@ Object.freeze({
|
|
|
22844
23317
|
addonId: null,
|
|
22845
23318
|
access: "delete"
|
|
22846
23319
|
},
|
|
23320
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23321
|
+
capName: "pipeline-analytics",
|
|
23322
|
+
capScope: "device",
|
|
23323
|
+
addonId: null,
|
|
23324
|
+
access: "delete"
|
|
23325
|
+
},
|
|
22847
23326
|
"pipelineAnalytics.deleteTracks": {
|
|
22848
23327
|
capName: "pipeline-analytics",
|
|
22849
23328
|
capScope: "device",
|
|
@@ -22874,6 +23353,12 @@ Object.freeze({
|
|
|
22874
23353
|
addonId: null,
|
|
22875
23354
|
access: "view"
|
|
22876
23355
|
},
|
|
23356
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23357
|
+
capName: "pipeline-analytics",
|
|
23358
|
+
capScope: "device",
|
|
23359
|
+
addonId: null,
|
|
23360
|
+
access: "view"
|
|
23361
|
+
},
|
|
22877
23362
|
"pipelineAnalytics.getKeyEvents": {
|
|
22878
23363
|
capName: "pipeline-analytics",
|
|
22879
23364
|
capScope: "device",
|
|
@@ -22916,6 +23401,12 @@ Object.freeze({
|
|
|
22916
23401
|
addonId: null,
|
|
22917
23402
|
access: "view"
|
|
22918
23403
|
},
|
|
23404
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23405
|
+
capName: "pipeline-analytics",
|
|
23406
|
+
capScope: "device",
|
|
23407
|
+
addonId: null,
|
|
23408
|
+
access: "view"
|
|
23409
|
+
},
|
|
22919
23410
|
"pipelineAnalytics.listRecentTracks": {
|
|
22920
23411
|
capName: "pipeline-analytics",
|
|
22921
23412
|
capScope: "device",
|
|
@@ -22928,6 +23419,12 @@ Object.freeze({
|
|
|
22928
23419
|
addonId: null,
|
|
22929
23420
|
access: "view"
|
|
22930
23421
|
},
|
|
23422
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23423
|
+
capName: "pipeline-analytics",
|
|
23424
|
+
capScope: "device",
|
|
23425
|
+
addonId: null,
|
|
23426
|
+
access: "create"
|
|
23427
|
+
},
|
|
22931
23428
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22932
23429
|
capName: "pipeline-analytics",
|
|
22933
23430
|
capScope: "device",
|
|
@@ -23690,6 +24187,12 @@ Object.freeze({
|
|
|
23690
24187
|
addonId: null,
|
|
23691
24188
|
access: "create"
|
|
23692
24189
|
},
|
|
24190
|
+
"recording.deleteFootprint": {
|
|
24191
|
+
capName: "recording",
|
|
24192
|
+
capScope: "system",
|
|
24193
|
+
addonId: null,
|
|
24194
|
+
access: "delete"
|
|
24195
|
+
},
|
|
23693
24196
|
"recording.getAvailability": {
|
|
23694
24197
|
capName: "recording",
|
|
23695
24198
|
capScope: "system",
|
|
@@ -23720,6 +24223,12 @@ Object.freeze({
|
|
|
23720
24223
|
addonId: null,
|
|
23721
24224
|
access: "view"
|
|
23722
24225
|
},
|
|
24226
|
+
"recording.listOpsLog": {
|
|
24227
|
+
capName: "recording",
|
|
24228
|
+
capScope: "system",
|
|
24229
|
+
addonId: null,
|
|
24230
|
+
access: "view"
|
|
24231
|
+
},
|
|
23723
24232
|
"recording.locateSegment": {
|
|
23724
24233
|
capName: "recording",
|
|
23725
24234
|
capScope: "system",
|
|
@@ -7469,6 +7469,62 @@ var RecordingConfigSchema = object({
|
|
|
7469
7469
|
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7470
7470
|
});
|
|
7471
7471
|
/**
|
|
7472
|
+
* Ops-log — the durable, append-only operations audit shared by the
|
|
7473
|
+
* recordings and events management surfaces.
|
|
7474
|
+
*
|
|
7475
|
+
* ONE row shape is reused for both domains so a single "Activity" view can
|
|
7476
|
+
* merge the recorder's DurableState ring (recordings ops-log) and the
|
|
7477
|
+
* pipeline-analytics SQLite collection (events ops-log). Each row records a
|
|
7478
|
+
* management operation, WHY it ran (reason), and its measurable effect
|
|
7479
|
+
* (itemsAffected + bytesReclaimed). Writes are best-effort — a failed log must
|
|
7480
|
+
* never fail the operation it records.
|
|
7481
|
+
*/
|
|
7482
|
+
/** Which management domain the operation belongs to. */
|
|
7483
|
+
var OpsLogDomainSchema = _enum(["recording", "events"]);
|
|
7484
|
+
/** The kind of management operation performed. */
|
|
7485
|
+
var OpsLogOpSchema = _enum([
|
|
7486
|
+
"prune",
|
|
7487
|
+
"manual-delete",
|
|
7488
|
+
"rescan",
|
|
7489
|
+
"retention-run"
|
|
7490
|
+
]);
|
|
7491
|
+
/** Why the operation ran. */
|
|
7492
|
+
var OpsLogReasonSchema = _enum([
|
|
7493
|
+
"retention",
|
|
7494
|
+
"quota",
|
|
7495
|
+
"manual",
|
|
7496
|
+
"operator"
|
|
7497
|
+
]);
|
|
7498
|
+
/** One audit row, shared verbatim by both domains. */
|
|
7499
|
+
var OpsLogEntrySchema = object({
|
|
7500
|
+
/** Unique row id. */
|
|
7501
|
+
id: string(),
|
|
7502
|
+
/** Epoch ms the operation completed. */
|
|
7503
|
+
at: number(),
|
|
7504
|
+
domain: OpsLogDomainSchema,
|
|
7505
|
+
op: OpsLogOpSchema,
|
|
7506
|
+
reason: OpsLogReasonSchema,
|
|
7507
|
+
/** The camera the op targeted; null for a cluster/global op. */
|
|
7508
|
+
deviceId: number().nullable(),
|
|
7509
|
+
/** Node that performed the op (the log carries nodeId — no cross-node aggregation). */
|
|
7510
|
+
nodeId: string(),
|
|
7511
|
+
/** Buckets / rows deleted (op-specific unit). */
|
|
7512
|
+
itemsAffected: number(),
|
|
7513
|
+
/** Bytes reclaimed by the op (0 when not measurable). */
|
|
7514
|
+
bytesReclaimed: number(),
|
|
7515
|
+
/** Free-text detail (e.g. "floor moved to <ts>"); null when none. */
|
|
7516
|
+
detail: string().nullable(),
|
|
7517
|
+
/** Who/what triggered the op. */
|
|
7518
|
+
actor: string()
|
|
7519
|
+
});
|
|
7520
|
+
/** Shared query input for the per-domain `listOpsLog` cap methods. */
|
|
7521
|
+
var OpsLogQueryInputSchema = object({
|
|
7522
|
+
/** Restrict to a single camera; omit for every row. */
|
|
7523
|
+
deviceId: number().optional(),
|
|
7524
|
+
/** Max rows returned, newest-first. */
|
|
7525
|
+
limit: number().int().min(1).max(1e3).optional()
|
|
7526
|
+
});
|
|
7527
|
+
/**
|
|
7472
7528
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7473
7529
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7474
7530
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7766,6 +7822,160 @@ function pickClosestResolution(entries, target) {
|
|
|
7766
7822
|
}
|
|
7767
7823
|
return bestAbove?.entry ?? bestBelow?.entry;
|
|
7768
7824
|
}
|
|
7825
|
+
var COCO_TO_MACRO = {
|
|
7826
|
+
mapping: {
|
|
7827
|
+
person: "person",
|
|
7828
|
+
bicycle: "vehicle",
|
|
7829
|
+
car: "vehicle",
|
|
7830
|
+
motorcycle: "vehicle",
|
|
7831
|
+
airplane: "vehicle",
|
|
7832
|
+
bus: "vehicle",
|
|
7833
|
+
train: "vehicle",
|
|
7834
|
+
truck: "vehicle",
|
|
7835
|
+
boat: "vehicle",
|
|
7836
|
+
bird: "animal",
|
|
7837
|
+
cat: "animal",
|
|
7838
|
+
dog: "animal",
|
|
7839
|
+
horse: "animal",
|
|
7840
|
+
sheep: "animal",
|
|
7841
|
+
cow: "animal",
|
|
7842
|
+
elephant: "animal",
|
|
7843
|
+
bear: "animal",
|
|
7844
|
+
zebra: "animal",
|
|
7845
|
+
giraffe: "animal",
|
|
7846
|
+
suitcase: "package",
|
|
7847
|
+
backpack: "package",
|
|
7848
|
+
handbag: "package"
|
|
7849
|
+
},
|
|
7850
|
+
preserveOriginal: false
|
|
7851
|
+
};
|
|
7852
|
+
var AUDIO_MACRO_LABELS = [
|
|
7853
|
+
{
|
|
7854
|
+
id: "speech",
|
|
7855
|
+
name: "Speech",
|
|
7856
|
+
icon: "🗣️"
|
|
7857
|
+
},
|
|
7858
|
+
{
|
|
7859
|
+
id: "scream",
|
|
7860
|
+
name: "Scream / Shout",
|
|
7861
|
+
icon: "😱"
|
|
7862
|
+
},
|
|
7863
|
+
{
|
|
7864
|
+
id: "crying",
|
|
7865
|
+
name: "Crying / Baby",
|
|
7866
|
+
icon: "😢"
|
|
7867
|
+
},
|
|
7868
|
+
{
|
|
7869
|
+
id: "laughter",
|
|
7870
|
+
name: "Laughter",
|
|
7871
|
+
icon: "😂"
|
|
7872
|
+
},
|
|
7873
|
+
{
|
|
7874
|
+
id: "music",
|
|
7875
|
+
name: "Music",
|
|
7876
|
+
icon: "🎵"
|
|
7877
|
+
},
|
|
7878
|
+
{
|
|
7879
|
+
id: "dog",
|
|
7880
|
+
name: "Dog",
|
|
7881
|
+
icon: "🐕"
|
|
7882
|
+
},
|
|
7883
|
+
{
|
|
7884
|
+
id: "cat",
|
|
7885
|
+
name: "Cat",
|
|
7886
|
+
icon: "🐈"
|
|
7887
|
+
},
|
|
7888
|
+
{
|
|
7889
|
+
id: "bird",
|
|
7890
|
+
name: "Bird",
|
|
7891
|
+
icon: "🐦"
|
|
7892
|
+
},
|
|
7893
|
+
{
|
|
7894
|
+
id: "animal",
|
|
7895
|
+
name: "Animal (other)",
|
|
7896
|
+
icon: "🐾"
|
|
7897
|
+
},
|
|
7898
|
+
{
|
|
7899
|
+
id: "alarm",
|
|
7900
|
+
name: "Alarm / Siren",
|
|
7901
|
+
icon: "🚨"
|
|
7902
|
+
},
|
|
7903
|
+
{
|
|
7904
|
+
id: "doorbell",
|
|
7905
|
+
name: "Doorbell / Knock",
|
|
7906
|
+
icon: "🔔"
|
|
7907
|
+
},
|
|
7908
|
+
{
|
|
7909
|
+
id: "glass_breaking",
|
|
7910
|
+
name: "Glass Breaking",
|
|
7911
|
+
icon: "💥"
|
|
7912
|
+
},
|
|
7913
|
+
{
|
|
7914
|
+
id: "gunshot",
|
|
7915
|
+
name: "Gunshot / Explosion",
|
|
7916
|
+
icon: "💣"
|
|
7917
|
+
},
|
|
7918
|
+
{
|
|
7919
|
+
id: "vehicle",
|
|
7920
|
+
name: "Vehicle",
|
|
7921
|
+
icon: "🚗"
|
|
7922
|
+
},
|
|
7923
|
+
{
|
|
7924
|
+
id: "siren",
|
|
7925
|
+
name: "Emergency Siren",
|
|
7926
|
+
icon: "🚑"
|
|
7927
|
+
},
|
|
7928
|
+
{
|
|
7929
|
+
id: "fire",
|
|
7930
|
+
name: "Fire / Smoke",
|
|
7931
|
+
icon: "🔥"
|
|
7932
|
+
},
|
|
7933
|
+
{
|
|
7934
|
+
id: "water",
|
|
7935
|
+
name: "Water",
|
|
7936
|
+
icon: "💧"
|
|
7937
|
+
},
|
|
7938
|
+
{
|
|
7939
|
+
id: "wind",
|
|
7940
|
+
name: "Wind / Weather",
|
|
7941
|
+
icon: "🌬️"
|
|
7942
|
+
},
|
|
7943
|
+
{
|
|
7944
|
+
id: "door",
|
|
7945
|
+
name: "Door",
|
|
7946
|
+
icon: "🚪"
|
|
7947
|
+
},
|
|
7948
|
+
{
|
|
7949
|
+
id: "footsteps",
|
|
7950
|
+
name: "Footsteps",
|
|
7951
|
+
icon: "👣"
|
|
7952
|
+
},
|
|
7953
|
+
{
|
|
7954
|
+
id: "crowd",
|
|
7955
|
+
name: "Crowd / Chatter",
|
|
7956
|
+
icon: "👥"
|
|
7957
|
+
},
|
|
7958
|
+
{
|
|
7959
|
+
id: "telephone",
|
|
7960
|
+
name: "Telephone",
|
|
7961
|
+
icon: "📞"
|
|
7962
|
+
},
|
|
7963
|
+
{
|
|
7964
|
+
id: "engine",
|
|
7965
|
+
name: "Engine / Motor",
|
|
7966
|
+
icon: "⚙️"
|
|
7967
|
+
},
|
|
7968
|
+
{
|
|
7969
|
+
id: "tools",
|
|
7970
|
+
name: "Tools / Construction",
|
|
7971
|
+
icon: "🔨"
|
|
7972
|
+
},
|
|
7973
|
+
{
|
|
7974
|
+
id: "silence",
|
|
7975
|
+
name: "Silence",
|
|
7976
|
+
icon: "🤫"
|
|
7977
|
+
}
|
|
7978
|
+
];
|
|
7769
7979
|
var YAMNET_TO_MACRO = {
|
|
7770
7980
|
mapping: {
|
|
7771
7981
|
Speech: "speech",
|
|
@@ -8032,6 +8242,125 @@ var _macroLookup = /* @__PURE__ */ new Map();
|
|
|
8032
8242
|
for (const [k, v] of Object.entries(YAMNET_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
8033
8243
|
for (const [k, v] of Object.entries(APPLE_SA_TO_MACRO.mapping)) _macroLookup.set(k.toLowerCase(), v);
|
|
8034
8244
|
/**
|
|
8245
|
+
* Unified event-kind taxonomy — THE single source of truth for
|
|
8246
|
+
* `kind → { parentKind, category, level, color, iconId, labelKey, label,
|
|
8247
|
+
* icon }`.
|
|
8248
|
+
*
|
|
8249
|
+
* This dictionary folds together what used to be scattered across four
|
|
8250
|
+
* copies:
|
|
8251
|
+
* - `capabilities/sensor-event-kinds.ts` (sensor cap colors)
|
|
8252
|
+
* - `addon-post-analysis/.../services/event-kinds.ts`
|
|
8253
|
+
* (MOTION/PERSON/VEHICLE… _COLOR constants)
|
|
8254
|
+
* - `ui-library/composites/detection-colors.ts` (CLASS_COLORS)
|
|
8255
|
+
* - `addon-post-analysis/shared/frame/box-drawer.ts` (DEFAULT_COLOR)
|
|
8256
|
+
* - the COCO / audio class maps (macro ↔ sub relationships)
|
|
8257
|
+
*
|
|
8258
|
+
* The DATA (serializable — color/iconId/labelKey/parentKind) lives here in
|
|
8259
|
+
* `@camstack/types`. The UI-side mapping `iconId → lucide component` and
|
|
8260
|
+
* `labelKey → t()` lives in `@camstack/ui-library`. UIs never hardcode a
|
|
8261
|
+
* color or an icon: they read this dictionary (server descriptors carry the
|
|
8262
|
+
* fields inline; the client resolves color/icon/label from `iconId`/`kind`).
|
|
8263
|
+
*
|
|
8264
|
+
* Two levels only (v1 YAGNI): macro → sub. `person` is a leaf macro.
|
|
8265
|
+
*/
|
|
8266
|
+
var TAXONOMY_COLORS = {
|
|
8267
|
+
motion: "#f59e0b",
|
|
8268
|
+
audio: "#06b6d4",
|
|
8269
|
+
person: "#22c55e",
|
|
8270
|
+
vehicle: "#3b82f6",
|
|
8271
|
+
animal: "#f97316",
|
|
8272
|
+
package: "#a855f7",
|
|
8273
|
+
sensor: "#8b5cf6",
|
|
8274
|
+
control: "#10b981",
|
|
8275
|
+
genericDetection: "#64748b"
|
|
8276
|
+
};
|
|
8277
|
+
var DETECTION_SUB_COLORS = {
|
|
8278
|
+
car: "#f59e0b",
|
|
8279
|
+
truck: "#d97706",
|
|
8280
|
+
bus: "#b45309",
|
|
8281
|
+
motorcycle: "#eab308",
|
|
8282
|
+
bicycle: "#ca8a04",
|
|
8283
|
+
airplane: "#60a5fa",
|
|
8284
|
+
boat: "#2563eb",
|
|
8285
|
+
train: "#1d4ed8",
|
|
8286
|
+
bird: "#14b8a6",
|
|
8287
|
+
dog: "#84cc16",
|
|
8288
|
+
cat: "#f97316",
|
|
8289
|
+
horse: "#a16207",
|
|
8290
|
+
sheep: "#a3a3a3",
|
|
8291
|
+
cow: "#78716c",
|
|
8292
|
+
elephant: "#6b7280",
|
|
8293
|
+
bear: "#7c2d12",
|
|
8294
|
+
zebra: "#404040",
|
|
8295
|
+
giraffe: "#d4a373"
|
|
8296
|
+
};
|
|
8297
|
+
function titleCase(id) {
|
|
8298
|
+
return id.split(/[-_ ]/).filter((p) => p.length > 0).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
|
|
8299
|
+
}
|
|
8300
|
+
var entries = /* @__PURE__ */ new Map();
|
|
8301
|
+
function macro(kind, category, color, iconId, label) {
|
|
8302
|
+
entries.set(kind, {
|
|
8303
|
+
kind,
|
|
8304
|
+
parentKind: null,
|
|
8305
|
+
level: "macro",
|
|
8306
|
+
category,
|
|
8307
|
+
color,
|
|
8308
|
+
iconId,
|
|
8309
|
+
labelKey: `eventKind.${kind}`,
|
|
8310
|
+
label
|
|
8311
|
+
});
|
|
8312
|
+
}
|
|
8313
|
+
function sub(kind, parentKind, category, color, iconId, label) {
|
|
8314
|
+
entries.set(kind, {
|
|
8315
|
+
kind,
|
|
8316
|
+
parentKind,
|
|
8317
|
+
level: "sub",
|
|
8318
|
+
category,
|
|
8319
|
+
color,
|
|
8320
|
+
iconId,
|
|
8321
|
+
labelKey: `eventKind.${kind}`,
|
|
8322
|
+
label
|
|
8323
|
+
});
|
|
8324
|
+
}
|
|
8325
|
+
macro("motion", "motion", TAXONOMY_COLORS.motion, "motion", "Motion");
|
|
8326
|
+
macro("audio", "audio", TAXONOMY_COLORS.audio, "audio", "Audio");
|
|
8327
|
+
macro("person", "detection", TAXONOMY_COLORS.person, "person", "Person");
|
|
8328
|
+
macro("vehicle", "detection", TAXONOMY_COLORS.vehicle, "vehicle", "Vehicle");
|
|
8329
|
+
macro("animal", "detection", TAXONOMY_COLORS.animal, "animal", "Animal");
|
|
8330
|
+
macro("package", "package", TAXONOMY_COLORS.package, "package", "Package");
|
|
8331
|
+
macro("sensor", "sensor", TAXONOMY_COLORS.sensor, "sensor", "Sensor");
|
|
8332
|
+
macro("control", "control", TAXONOMY_COLORS.control, "control", "Control");
|
|
8333
|
+
for (const [cocoClass, macroClass] of Object.entries(COCO_TO_MACRO.mapping)) {
|
|
8334
|
+
if (macroClass !== "vehicle" && macroClass !== "animal") continue;
|
|
8335
|
+
if (entries.has(cocoClass)) continue;
|
|
8336
|
+
sub(cocoClass, macroClass, "detection", DETECTION_SUB_COLORS[cocoClass] ?? TAXONOMY_COLORS.genericDetection, cocoClass, titleCase(cocoClass));
|
|
8337
|
+
}
|
|
8338
|
+
sub("package-delivered", "package", "package", TAXONOMY_COLORS.package, "package", "Package delivered");
|
|
8339
|
+
sub("package-picked-up", "package", "package", TAXONOMY_COLORS.package, "package", "Package picked up");
|
|
8340
|
+
sub("contact", "sensor", "sensor", "#f59e0b", "door", "Contact");
|
|
8341
|
+
sub("motion-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "pir", "Motion sensor");
|
|
8342
|
+
sub("smoke", "sensor", "sensor", "#ef4444", "smoke", "Smoke");
|
|
8343
|
+
sub("flood", "sensor", "sensor", "#3b82f6", "water", "Water leak");
|
|
8344
|
+
sub("gas", "sensor", "sensor", "#ef4444", "gas", "Gas");
|
|
8345
|
+
sub("carbon-monoxide", "sensor", "sensor", "#dc2626", "smoke", "Carbon monoxide");
|
|
8346
|
+
sub("vibration", "sensor", "sensor", "#eab308", "vibration", "Vibration");
|
|
8347
|
+
sub("tamper", "sensor", "sensor", "#f97316", "tamper", "Tamper");
|
|
8348
|
+
sub("presence", "sensor", "sensor", "#22c55e", "presence", "Presence");
|
|
8349
|
+
sub("enum-sensor", "sensor", "sensor", TAXONOMY_COLORS.sensor, "generic", "Sensor state");
|
|
8350
|
+
sub("device-event", "sensor", "sensor", "#10b981", "button", "Device event");
|
|
8351
|
+
sub("lock", "control", "control", "#0ea5e9", "lock", "Lock");
|
|
8352
|
+
sub("switch", "control", "control", TAXONOMY_COLORS.control, "switch", "Switch");
|
|
8353
|
+
sub("siren", "control", "control", "#dc2626", "siren", "Siren");
|
|
8354
|
+
sub("button", "control", "control", "#10b981", "button", "Button");
|
|
8355
|
+
sub("doorbell", "control", "control", "#a855f7", "doorbell", "Doorbell");
|
|
8356
|
+
for (const l of AUDIO_MACRO_LABELS) {
|
|
8357
|
+
const kind = `audio-${l.id}`;
|
|
8358
|
+
if (entries.has(kind)) continue;
|
|
8359
|
+
sub(kind, "audio", "audio", TAXONOMY_COLORS.audio, kind, l.name);
|
|
8360
|
+
}
|
|
8361
|
+
/** The complete taxonomy dictionary, keyed by kind. */
|
|
8362
|
+
var EVENT_TAXONOMY = Object.freeze(Object.fromEntries(entries));
|
|
8363
|
+
/**
|
|
8035
8364
|
* Error types for the safe expression engine. Two distinct classes so callers
|
|
8036
8365
|
* can tell a compile-time (grammar) failure from a runtime (evaluation)
|
|
8037
8366
|
* failure — both are non-fatal to the host: read paths degrade to "skip link".
|
|
@@ -16052,17 +16381,30 @@ var EventKindCategorySchema = _enum([
|
|
|
16052
16381
|
"audio",
|
|
16053
16382
|
"detection",
|
|
16054
16383
|
"sensor",
|
|
16384
|
+
"control",
|
|
16055
16385
|
"custom",
|
|
16056
16386
|
"package"
|
|
16057
16387
|
]);
|
|
16388
|
+
/** Taxonomy level — macro (timeline lane) vs sub (events-page leaf). */
|
|
16389
|
+
var EventKindLevelSchema = _enum(["macro", "sub"]);
|
|
16058
16390
|
var EventKindDescriptorSchema = object({
|
|
16059
|
-
/** Stable kind id (e.g. 'motion', '
|
|
16391
|
+
/** Stable kind id (e.g. 'motion', 'vehicle', 'car', 'lock'). */
|
|
16060
16392
|
kind: string(),
|
|
16393
|
+
/** i18n key resolved on the UI side; `label` is the English fallback. */
|
|
16394
|
+
labelKey: string(),
|
|
16395
|
+
/** English fallback label (kept for clients that don't translate). */
|
|
16061
16396
|
label: string(),
|
|
16062
16397
|
/** Hex color for timeline/legend rendering. */
|
|
16063
16398
|
color: string(),
|
|
16399
|
+
/** Dictionary id → lucide component on the UI side. */
|
|
16400
|
+
iconId: string(),
|
|
16401
|
+
/** Legacy closed-vocab glyph — fallback for `iconId`. */
|
|
16064
16402
|
icon: EventKindIconSchema,
|
|
16065
16403
|
category: EventKindCategorySchema,
|
|
16404
|
+
/** Macro parent for this kind ('car' → 'vehicle'); null for a macro. */
|
|
16405
|
+
parentKind: string().nullable(),
|
|
16406
|
+
/** Derived from `parentKind`, explicit for the client tree. */
|
|
16407
|
+
level: EventKindLevelSchema,
|
|
16066
16408
|
/** Which cap + device contributes this kind. For built-ins the camera
|
|
16067
16409
|
* itself; for sensor kinds the LINKED source device. */
|
|
16068
16410
|
source: object({
|
|
@@ -16135,11 +16477,21 @@ var TrackAudioLabelSchema = object({
|
|
|
16135
16477
|
firstAt: number(),
|
|
16136
16478
|
lastAt: number()
|
|
16137
16479
|
});
|
|
16480
|
+
/**
|
|
16481
|
+
* How a track was produced. `pipeline` (default / absent) = the spatial
|
|
16482
|
+
* detection+tracking pipeline. `sensor` = a SYNTHETIC track projected from a
|
|
16483
|
+
* linked sensor/control state change (no positions; carries a snapshot). The
|
|
16484
|
+
* spatial subsystems (tracker association, occupancy count, re-id/embedding,
|
|
16485
|
+
* resurrection) MUST skip `sensor` tracks — they have no bbox trajectory.
|
|
16486
|
+
*/
|
|
16487
|
+
var TrackSourceSchema = _enum(["pipeline", "sensor"]);
|
|
16138
16488
|
var TrackSchema = object({
|
|
16139
16489
|
trackId: string(),
|
|
16140
16490
|
deviceId: number(),
|
|
16141
16491
|
className: string(),
|
|
16142
16492
|
label: string().optional(),
|
|
16493
|
+
/** Track provenance. Absent ⇒ `pipeline` (legacy rows). */
|
|
16494
|
+
source: TrackSourceSchema.optional(),
|
|
16143
16495
|
firstSeen: number(),
|
|
16144
16496
|
lastSeen: number(),
|
|
16145
16497
|
/** Frame-rate position history (subject to maxPositionHistory cap). */
|
|
@@ -16394,6 +16746,26 @@ var TrackCascadeCountsSchema = object({
|
|
|
16394
16746
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
16395
16747
|
embeddings: number().int()
|
|
16396
16748
|
});
|
|
16749
|
+
/** Event-store footprint for one camera. */
|
|
16750
|
+
var EventStoreDeviceFootprintSchema = object({
|
|
16751
|
+
deviceId: number(),
|
|
16752
|
+
/** Persisted event rows (motion + object + audio) for the camera. */
|
|
16753
|
+
rows: number().int(),
|
|
16754
|
+
/** Event-owned media bytes on disk for the camera. */
|
|
16755
|
+
bytes: number().int()
|
|
16756
|
+
});
|
|
16757
|
+
/** Aggregate event-store footprint: global totals + per-camera breakdown. */
|
|
16758
|
+
var EventStoreFootprintSchema = object({
|
|
16759
|
+
totalRows: number().int(),
|
|
16760
|
+
totalBytes: number().int(),
|
|
16761
|
+
devices: array(EventStoreDeviceFootprintSchema).readonly()
|
|
16762
|
+
});
|
|
16763
|
+
/** Per-kind counts returned by the event-prune / device-delete mutations. */
|
|
16764
|
+
var EventPruneCountsSchema = object({
|
|
16765
|
+
motion: number().int(),
|
|
16766
|
+
object: number().int(),
|
|
16767
|
+
audio: number().int()
|
|
16768
|
+
});
|
|
16397
16769
|
DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).readonly()), method(object({
|
|
16398
16770
|
deviceId: number(),
|
|
16399
16771
|
trackId: string()
|
|
@@ -16457,6 +16829,21 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16457
16829
|
}), {
|
|
16458
16830
|
kind: "mutation",
|
|
16459
16831
|
auth: "admin"
|
|
16832
|
+
}), method(object({}), EventStoreFootprintSchema, {
|
|
16833
|
+
kind: "query",
|
|
16834
|
+
auth: "admin"
|
|
16835
|
+
}), method(object({
|
|
16836
|
+
olderThanMs: number(),
|
|
16837
|
+
reason: OpsLogReasonSchema.optional()
|
|
16838
|
+
}), EventPruneCountsSchema, {
|
|
16839
|
+
kind: "mutation",
|
|
16840
|
+
auth: "admin"
|
|
16841
|
+
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
16842
|
+
kind: "mutation",
|
|
16843
|
+
auth: "admin"
|
|
16844
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
16845
|
+
kind: "query",
|
|
16846
|
+
auth: "admin"
|
|
16460
16847
|
}), method(object({
|
|
16461
16848
|
eventId: string(),
|
|
16462
16849
|
kind: MediaFileKindEnum.optional()
|
|
@@ -16481,6 +16868,76 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
16481
16868
|
eventId: string(),
|
|
16482
16869
|
timestamp: number()
|
|
16483
16870
|
});
|
|
16871
|
+
/**
|
|
16872
|
+
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
16873
|
+
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
16874
|
+
* caps into per-camera event-kind descriptors.
|
|
16875
|
+
*
|
|
16876
|
+
* The descriptor DATA (color / iconId / labelKey / parentKind / category)
|
|
16877
|
+
* is NOT duplicated here — every entry is derived from the single
|
|
16878
|
+
* `EVENT_TAXONOMY` dictionary (`catalogs/event-taxonomy.ts`). This file owns
|
|
16879
|
+
* ONLY the cap-name → taxonomy-kind mapping. Adding a new eventful sensor /
|
|
16880
|
+
* control cap means adding one line here (and a taxonomy entry); the anti-
|
|
16881
|
+
* drift guard `scripts/check-event-kind-coverage.ts` fails the build if an
|
|
16882
|
+
* eventful cap is missing.
|
|
16883
|
+
*/
|
|
16884
|
+
/** Map a taxonomy `iconId` onto the legacy closed `EventKindIcon` enum. */
|
|
16885
|
+
var LEGACY_ICON = {
|
|
16886
|
+
motion: "motion",
|
|
16887
|
+
audio: "audio",
|
|
16888
|
+
person: "person",
|
|
16889
|
+
vehicle: "vehicle",
|
|
16890
|
+
animal: "animal",
|
|
16891
|
+
package: "package",
|
|
16892
|
+
door: "door",
|
|
16893
|
+
pir: "pir",
|
|
16894
|
+
smoke: "smoke",
|
|
16895
|
+
water: "water",
|
|
16896
|
+
button: "button",
|
|
16897
|
+
generic: "generic",
|
|
16898
|
+
gas: "smoke",
|
|
16899
|
+
vibration: "generic",
|
|
16900
|
+
tamper: "generic",
|
|
16901
|
+
presence: "person",
|
|
16902
|
+
lock: "generic",
|
|
16903
|
+
siren: "generic",
|
|
16904
|
+
switch: "generic",
|
|
16905
|
+
doorbell: "button"
|
|
16906
|
+
};
|
|
16907
|
+
function legacyIcon(iconId) {
|
|
16908
|
+
return LEGACY_ICON[iconId] ?? "generic";
|
|
16909
|
+
}
|
|
16910
|
+
/**
|
|
16911
|
+
* Cap name → taxonomy kind id. Covers EVERY eventful sensor / control cap.
|
|
16912
|
+
* The anti-drift guard cross-checks this against the eventful caps declared
|
|
16913
|
+
* in `packages/types/src/capabilities/*.cap.ts`.
|
|
16914
|
+
*/
|
|
16915
|
+
var CAP_TO_KIND = {
|
|
16916
|
+
contact: "contact",
|
|
16917
|
+
motion: "motion-sensor",
|
|
16918
|
+
smoke: "smoke",
|
|
16919
|
+
flood: "flood",
|
|
16920
|
+
gas: "gas",
|
|
16921
|
+
"carbon-monoxide": "carbon-monoxide",
|
|
16922
|
+
vibration: "vibration",
|
|
16923
|
+
tamper: "tamper",
|
|
16924
|
+
presence: "presence",
|
|
16925
|
+
"enum-sensor": "enum-sensor",
|
|
16926
|
+
"event-emitter": "device-event",
|
|
16927
|
+
"lock-control": "lock",
|
|
16928
|
+
switch: "switch",
|
|
16929
|
+
button: "button",
|
|
16930
|
+
doorbell: "doorbell"
|
|
16931
|
+
};
|
|
16932
|
+
function buildDescriptor(capName, kind) {
|
|
16933
|
+
const t = EVENT_TAXONOMY[kind];
|
|
16934
|
+
if (t === void 0) throw new Error(`EVENT_KIND_BY_CAP: cap '${capName}' maps to unknown taxonomy kind '${kind}'`);
|
|
16935
|
+
return {
|
|
16936
|
+
...t,
|
|
16937
|
+
icon: legacyIcon(t.iconId)
|
|
16938
|
+
};
|
|
16939
|
+
}
|
|
16940
|
+
Object.freeze(Object.fromEntries(Object.entries(CAP_TO_KIND).map(([capName, kind]) => [capName, buildDescriptor(capName, kind)])));
|
|
16484
16941
|
var CameraPipelineConfigSchema = object({
|
|
16485
16942
|
engine: PipelineEngineChoiceSchema.optional(),
|
|
16486
16943
|
steps: array(PipelineStepInputSchema).readonly(),
|
|
@@ -19690,13 +20147,29 @@ method(object({
|
|
|
19690
20147
|
}), method(object({ deviceId: number() }), RecordingStatusSchema, {
|
|
19691
20148
|
kind: "mutation",
|
|
19692
20149
|
auth: "admin"
|
|
19693
|
-
}), method(object({
|
|
20150
|
+
}), method(object({
|
|
20151
|
+
deviceId: number(),
|
|
20152
|
+
reason: OpsLogReasonSchema.optional()
|
|
20153
|
+
}), object({
|
|
19694
20154
|
floorMs: number().nullable(),
|
|
19695
20155
|
deletedBuckets: number().int(),
|
|
19696
20156
|
reclaimedBytes: number().int()
|
|
19697
20157
|
}), {
|
|
19698
20158
|
kind: "mutation",
|
|
19699
20159
|
auth: "admin"
|
|
20160
|
+
}), method(object({
|
|
20161
|
+
deviceId: number(),
|
|
20162
|
+
fromMs: number().optional(),
|
|
20163
|
+
toMs: number().optional()
|
|
20164
|
+
}), object({
|
|
20165
|
+
deletedBuckets: number().int(),
|
|
20166
|
+
reclaimedBytes: number().int()
|
|
20167
|
+
}), {
|
|
20168
|
+
kind: "mutation",
|
|
20169
|
+
auth: "admin"
|
|
20170
|
+
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20171
|
+
kind: "query",
|
|
20172
|
+
auth: "admin"
|
|
19700
20173
|
});
|
|
19701
20174
|
/**
|
|
19702
20175
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -22818,6 +23291,12 @@ Object.freeze({
|
|
|
22818
23291
|
addonId: null,
|
|
22819
23292
|
access: "delete"
|
|
22820
23293
|
},
|
|
23294
|
+
"pipelineAnalytics.deleteDeviceEvents": {
|
|
23295
|
+
capName: "pipeline-analytics",
|
|
23296
|
+
capScope: "device",
|
|
23297
|
+
addonId: null,
|
|
23298
|
+
access: "delete"
|
|
23299
|
+
},
|
|
22821
23300
|
"pipelineAnalytics.deleteTracks": {
|
|
22822
23301
|
capName: "pipeline-analytics",
|
|
22823
23302
|
capScope: "device",
|
|
@@ -22848,6 +23327,12 @@ Object.freeze({
|
|
|
22848
23327
|
addonId: null,
|
|
22849
23328
|
access: "view"
|
|
22850
23329
|
},
|
|
23330
|
+
"pipelineAnalytics.getEventStoreFootprint": {
|
|
23331
|
+
capName: "pipeline-analytics",
|
|
23332
|
+
capScope: "device",
|
|
23333
|
+
addonId: null,
|
|
23334
|
+
access: "view"
|
|
23335
|
+
},
|
|
22851
23336
|
"pipelineAnalytics.getKeyEvents": {
|
|
22852
23337
|
capName: "pipeline-analytics",
|
|
22853
23338
|
capScope: "device",
|
|
@@ -22890,6 +23375,12 @@ Object.freeze({
|
|
|
22890
23375
|
addonId: null,
|
|
22891
23376
|
access: "view"
|
|
22892
23377
|
},
|
|
23378
|
+
"pipelineAnalytics.listOpsLog": {
|
|
23379
|
+
capName: "pipeline-analytics",
|
|
23380
|
+
capScope: "device",
|
|
23381
|
+
addonId: null,
|
|
23382
|
+
access: "view"
|
|
23383
|
+
},
|
|
22893
23384
|
"pipelineAnalytics.listRecentTracks": {
|
|
22894
23385
|
capName: "pipeline-analytics",
|
|
22895
23386
|
capScope: "device",
|
|
@@ -22902,6 +23393,12 @@ Object.freeze({
|
|
|
22902
23393
|
addonId: null,
|
|
22903
23394
|
access: "view"
|
|
22904
23395
|
},
|
|
23396
|
+
"pipelineAnalytics.pruneEvents": {
|
|
23397
|
+
capName: "pipeline-analytics",
|
|
23398
|
+
capScope: "device",
|
|
23399
|
+
addonId: null,
|
|
23400
|
+
access: "create"
|
|
23401
|
+
},
|
|
22905
23402
|
"pipelineAnalytics.pruneEventsBefore": {
|
|
22906
23403
|
capName: "pipeline-analytics",
|
|
22907
23404
|
capScope: "device",
|
|
@@ -23664,6 +24161,12 @@ Object.freeze({
|
|
|
23664
24161
|
addonId: null,
|
|
23665
24162
|
access: "create"
|
|
23666
24163
|
},
|
|
24164
|
+
"recording.deleteFootprint": {
|
|
24165
|
+
capName: "recording",
|
|
24166
|
+
capScope: "system",
|
|
24167
|
+
addonId: null,
|
|
24168
|
+
access: "delete"
|
|
24169
|
+
},
|
|
23667
24170
|
"recording.getAvailability": {
|
|
23668
24171
|
capName: "recording",
|
|
23669
24172
|
capScope: "system",
|
|
@@ -23694,6 +24197,12 @@ Object.freeze({
|
|
|
23694
24197
|
addonId: null,
|
|
23695
24198
|
access: "view"
|
|
23696
24199
|
},
|
|
24200
|
+
"recording.listOpsLog": {
|
|
24201
|
+
capName: "recording",
|
|
24202
|
+
capScope: "system",
|
|
24203
|
+
addonId: null,
|
|
24204
|
+
access: "view"
|
|
24205
|
+
},
|
|
23697
24206
|
"recording.locateSegment": {
|
|
23698
24207
|
capName: "recording",
|
|
23699
24208
|
capScope: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-alexa",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.27",
|
|
4
4
|
"description": "Alexa Smart Home Skill export — hub-side OAuth provider + directive handler. The companion AWS Lambda forwards Alexa directives to this addon's /addon/export-alexa/directive endpoint.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|