@camstack/types 1.2.66 → 1.2.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/capabilities/notification-output.cap.d.ts +46 -0
- package/dist/capabilities/notification-rules.cap.d.ts +99 -3
- package/dist/capabilities/osd-manager.cap.d.ts +12 -0
- package/dist/catalogs/coco-classmap.d.ts +21 -0
- package/dist/device/system-mirror.d.ts +37 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +156 -19
- package/dist/index.mjs +155 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10467,11 +10467,33 @@ var NotificationFormatSchema = zod.z.enum([
|
|
|
10467
10467
|
* Named by INTENT, never by glyph. "check" would tie the vocabulary to one
|
|
10468
10468
|
* renderer's icon set; "acknowledge" survives an adapter that draws it
|
|
10469
10469
|
* differently.
|
|
10470
|
+
*
|
|
10471
|
+
* ── A TOKEN IS NOT A WIRE VALUE ─────────────────────────────────────
|
|
10472
|
+
*
|
|
10473
|
+
* These names are for US. **No adapter may forward one verbatim.** Each maps
|
|
10474
|
+
* the whole set onto its own renderer's vocabulary through a
|
|
10475
|
+
* `Record<NotificationActionIcon, string>` — a Record, never a lookup with a
|
|
10476
|
+
* fallback, so adding a member here fails every adapter's build until someone
|
|
10477
|
+
* decides its glyph, which is the only place that decision can be made
|
|
10478
|
+
* honestly.
|
|
10479
|
+
*
|
|
10480
|
+
* This paragraph is the bug. Zentik declared `actionIcons: true` and passed
|
|
10481
|
+
* `disarm` straight through; iOS feeds that string to
|
|
10482
|
+
* `UNNotificationActionIcon(systemImageName:)`, `disarm` is not an SF Symbol,
|
|
10483
|
+
* and every snooze and alarm button arrived BLANK. A pass-through is not a
|
|
10484
|
+
* mapping, and "the field is documented" is not "the value renders".
|
|
10485
|
+
*
|
|
10486
|
+
* Adding a member is TRAIN-BOUND. The enum lives in the published
|
|
10487
|
+
* `@camstack/server` closure and the cap seam validates against the HUB's copy,
|
|
10488
|
+
* so an addon that emits a token the running hub does not know does not lose an
|
|
10489
|
+
* icon — its whole `send` fails Zod validation and the notification never
|
|
10490
|
+
* arrives. Never emit a new token from an addon before the train carrying it.
|
|
10470
10491
|
*/
|
|
10471
10492
|
var NotificationActionIconSchema = zod.z.enum([
|
|
10472
10493
|
"acknowledge",
|
|
10473
10494
|
"dismiss",
|
|
10474
10495
|
"silence",
|
|
10496
|
+
"snooze",
|
|
10475
10497
|
"view",
|
|
10476
10498
|
"play",
|
|
10477
10499
|
"open",
|
|
@@ -10479,9 +10501,13 @@ var NotificationActionIconSchema = zod.z.enum([
|
|
|
10479
10501
|
"lock",
|
|
10480
10502
|
"unlock",
|
|
10481
10503
|
"arm",
|
|
10504
|
+
"arm-home",
|
|
10505
|
+
"arm-away",
|
|
10506
|
+
"arm-night",
|
|
10482
10507
|
"disarm",
|
|
10483
10508
|
"light",
|
|
10484
|
-
"alert"
|
|
10509
|
+
"alert",
|
|
10510
|
+
"camera"
|
|
10485
10511
|
]);
|
|
10486
10512
|
/** A single tap-through action button. */
|
|
10487
10513
|
var NotificationActionSchema = zod.z.object({
|
|
@@ -11039,6 +11065,29 @@ var MACRO_LABELS = [
|
|
|
11039
11065
|
name: "Package"
|
|
11040
11066
|
}
|
|
11041
11067
|
];
|
|
11068
|
+
/**
|
|
11069
|
+
* The class names a per-class COUNT can ever be keyed on — the macro ids, and
|
|
11070
|
+
* only those.
|
|
11071
|
+
*
|
|
11072
|
+
* `preserveOriginal: false` below is the whole reason this set exists: the
|
|
11073
|
+
* executor maps each raw COCO label onto its macro and DROPS everything else,
|
|
11074
|
+
* so a tracked detection's `className` is always one of {@link MACRO_LABELS}.
|
|
11075
|
+
* Any surface that indexes counts by class name — the ZoneAnalytics occupancy
|
|
11076
|
+
* snapshot's `byClass`, and therefore every occupancy rule — can match nothing
|
|
11077
|
+
* else. Derived from the catalog, never hand-listed, so a new macro joins it by
|
|
11078
|
+
* being declared once.
|
|
11079
|
+
*
|
|
11080
|
+
* Cost of not having it, 2026-08-12: the notification rule editor offered the
|
|
11081
|
+
* full taxonomy for an occupancy class (occupancy is the one condition that
|
|
11082
|
+
* does not go through the engine's macro-expanding `expandClassSelector`), two
|
|
11083
|
+
* live rules were authored on `car`, and both counters read 0 forever.
|
|
11084
|
+
*/
|
|
11085
|
+
var DETECTION_MACRO_CLASSES = new Set(MACRO_LABELS.map((l) => l.id));
|
|
11086
|
+
/** True when `className` is a macro the detector can actually emit (and hence a
|
|
11087
|
+
* class a count can be keyed on) — see {@link DETECTION_MACRO_CLASSES}. */
|
|
11088
|
+
function isDetectionMacroClass(className) {
|
|
11089
|
+
return DETECTION_MACRO_CLASSES.has(className.trim().toLowerCase());
|
|
11090
|
+
}
|
|
11042
11091
|
var COCO_TO_MACRO = {
|
|
11043
11092
|
mapping: {
|
|
11044
11093
|
person: "person",
|
|
@@ -11914,6 +11963,8 @@ var NcSystemEventKindSchema = zod.z.enum([
|
|
|
11914
11963
|
"alarm-triggered",
|
|
11915
11964
|
"alarm-armed",
|
|
11916
11965
|
"alarm-disarmed",
|
|
11966
|
+
"alarm-arming",
|
|
11967
|
+
"alarm-arm-refused",
|
|
11917
11968
|
"camera-online",
|
|
11918
11969
|
"camera-offline",
|
|
11919
11970
|
"camera-disabled",
|
|
@@ -11933,16 +11984,22 @@ var NC_LEGACY_SYSTEM_EVENT_KINDS = new Set([
|
|
|
11933
11984
|
*/
|
|
11934
11985
|
var NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NcSystemEventKindSchema.options.filter((kind) => !NC_LEGACY_SYSTEM_EVENT_KINDS.has(kind));
|
|
11935
11986
|
/**
|
|
11936
|
-
* The panel's
|
|
11987
|
+
* The panel's transitions, as ONE list.
|
|
11937
11988
|
*
|
|
11938
11989
|
* Named here rather than spelled out at each of the four sites that need them
|
|
11939
11990
|
* (the emitter, the intake, the editor group, the combined-notification gate),
|
|
11940
|
-
* because a
|
|
11941
|
-
*
|
|
11991
|
+
* because a transition added to the enum and forgotten at one of them is an
|
|
11992
|
+
* alarm state nobody can be notified about. That is exactly what this list
|
|
11993
|
+
* failed to prevent while it held three: `alarm-arming` was the fourth.
|
|
11994
|
+
*
|
|
11995
|
+
* In LIFECYCLE order, which is the order an editor lists them in and the order
|
|
11996
|
+
* a person experiences them — not the order they were added.
|
|
11942
11997
|
*/
|
|
11943
11998
|
var NC_ALARM_SYSTEM_EVENT_KINDS = [
|
|
11944
|
-
"alarm-
|
|
11999
|
+
"alarm-arm-refused",
|
|
12000
|
+
"alarm-arming",
|
|
11945
12001
|
"alarm-armed",
|
|
12002
|
+
"alarm-triggered",
|
|
11946
12003
|
"alarm-disarmed"
|
|
11947
12004
|
];
|
|
11948
12005
|
/**
|
|
@@ -12873,13 +12930,17 @@ var NC_CONDITION_CATALOG = [
|
|
|
12873
12930
|
label: "Server update available"
|
|
12874
12931
|
},
|
|
12875
12932
|
{
|
|
12876
|
-
value: "alarm-
|
|
12877
|
-
label: "Alarm
|
|
12933
|
+
value: "alarm-arming",
|
|
12934
|
+
label: "Alarm arming (exit delay)"
|
|
12878
12935
|
},
|
|
12879
12936
|
{
|
|
12880
12937
|
value: "alarm-armed",
|
|
12881
12938
|
label: "Alarm armed"
|
|
12882
12939
|
},
|
|
12940
|
+
{
|
|
12941
|
+
value: "alarm-triggered",
|
|
12942
|
+
label: "Alarm triggered"
|
|
12943
|
+
},
|
|
12883
12944
|
{
|
|
12884
12945
|
value: "alarm-disarmed",
|
|
12885
12946
|
label: "Alarm disarmed"
|
|
@@ -16350,6 +16411,22 @@ var detectionFpsField = {
|
|
|
16350
16411
|
default: 10,
|
|
16351
16412
|
step: 1
|
|
16352
16413
|
};
|
|
16414
|
+
/**
|
|
16415
|
+
* The occupancy re-check interval. DEFAULT 300 s (2026-08-13 — was 30 s).
|
|
16416
|
+
*
|
|
16417
|
+
* The recheck is now on by default (a parked car is invisible to occupancy
|
|
16418
|
+
* rules until the stationary registry has been rebuilt by motion, which after a
|
|
16419
|
+
* restart may be never on a quiet camera). Each cycle re-subscribes a detection
|
|
16420
|
+
* session — an RTSP re-dial — so the switch is only affordable at a WIDE
|
|
16421
|
+
* interval: 300 s is ~12 re-dials an hour per camera, against 120 at the old
|
|
16422
|
+
* 30 s. A parked car is therefore counted within 5 minutes of a restart.
|
|
16423
|
+
*
|
|
16424
|
+
* Why not wider: `max` is 300 and raising it is TRAIN-BOUND, not addon-bound —
|
|
16425
|
+
* the host validates `attachCamera` against ITS copy of this schema, so a
|
|
16426
|
+
* runner asked for 600 would be rejected by the hub until a `@camstack/server`
|
|
16427
|
+
* carrying the wider bound is installed everywhere. 300 is the widest value
|
|
16428
|
+
* that ships with an addon deploy.
|
|
16429
|
+
*/
|
|
16353
16430
|
var occupancyRecheckSecField = {
|
|
16354
16431
|
min: 0,
|
|
16355
16432
|
max: 300,
|
|
@@ -16551,15 +16628,21 @@ var RunnerCameraConfigSchema = zod.z.object({
|
|
|
16551
16628
|
*/
|
|
16552
16629
|
onboardMotionDrivesAnalyzer: zod.z.boolean().default(true),
|
|
16553
16630
|
/**
|
|
16554
|
-
* Master toggle for the occupancy re-check. When `false`
|
|
16555
|
-
*
|
|
16556
|
-
* this is off by default because the recheck re-subscribes a detection session
|
|
16557
|
-
* every N seconds while `watching`, a major source of pull-decoder re-dial
|
|
16558
|
-
* churn (each cycle creates+tears a session → RTSP re-dial → latency). The
|
|
16631
|
+
* Master toggle for the occupancy re-check. When `false` the runner never arms
|
|
16632
|
+
* the periodic recheck timer, regardless of `occupancyRecheckSec`; the
|
|
16559
16633
|
* `occupancyRecheckSec` / `occupancyRecheckFrames` sliders only take effect
|
|
16560
16634
|
* (and only render) when this is enabled.
|
|
16561
|
-
|
|
16562
|
-
|
|
16635
|
+
*
|
|
16636
|
+
* DEFAULT `true` since 2026-08-13 (was `false`). It was off because the
|
|
16637
|
+
* recheck re-subscribes a detection session every N seconds while `watching`
|
|
16638
|
+
* — each cycle creates+tears a session ⇒ an RTSP re-dial ⇒ latency, a major
|
|
16639
|
+
* pull-decoder churn source. What that bought was a blind spot: a STATIONARY
|
|
16640
|
+
* object is counted only while the stationary registry holds it, and the
|
|
16641
|
+
* registry rebuilds from motion, so after a restart a parked car was invisible
|
|
16642
|
+
* to every occupancy rule until something moved in front of it. The churn is
|
|
16643
|
+
* now paid on the interval instead — see `occupancyRecheckSecField`.
|
|
16644
|
+
*/
|
|
16645
|
+
occupancyRecheckEnabled: zod.z.boolean().default(true),
|
|
16563
16646
|
occupancyRecheckSec: zod.z.number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
|
|
16564
16647
|
occupancyRecheckFrames: zod.z.number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
|
|
16565
16648
|
/**
|
|
@@ -16692,8 +16775,8 @@ var RunnerCameraDeviceUIFields = [
|
|
|
16692
16775
|
type: "boolean",
|
|
16693
16776
|
style: "checkbox",
|
|
16694
16777
|
label: "Occupancy re-check",
|
|
16695
|
-
description: "Periodically re-sample a few frames during the watching phase
|
|
16696
|
-
default:
|
|
16778
|
+
description: "Periodically re-sample a few frames during the watching phase, so objects that are simply parked are still counted (motion gating alone loses them after a restart). On by default at a wide interval; turn it off on cameras where the extra decoder re-dial is expensive.",
|
|
16779
|
+
default: true
|
|
16697
16780
|
},
|
|
16698
16781
|
{
|
|
16699
16782
|
key: "occupancyRecheckSec",
|
|
@@ -31657,11 +31740,40 @@ var SystemMirror = class {
|
|
|
31657
31740
|
cb(deviceId, lastInfo);
|
|
31658
31741
|
} catch {}
|
|
31659
31742
|
}
|
|
31743
|
+
/**
|
|
31744
|
+
* ONE device's bindings, not the fleet's.
|
|
31745
|
+
*
|
|
31746
|
+
* This runs on every `capability.binding-changed` AND on every
|
|
31747
|
+
* `device.registered`, per mirror. It used to answer that with
|
|
31748
|
+
* `getAllBindings` and `.find()` the one row — measured on the live
|
|
31749
|
+
* hub (524 devices): 903 ms and 373 KB per call, against 21 ms and
|
|
31750
|
+
* 613 bytes for `getBindings({deviceId})`.
|
|
31751
|
+
*
|
|
31752
|
+
* Adopting 20 Home Assistant devices registers 166 devices (parents +
|
|
31753
|
+
* accessories), so an operator with the admin UI open bought 166
|
|
31754
|
+
* full-fleet binding sweeps: ~150 s of hub main-thread time inside a
|
|
31755
|
+
* 219 s adoption, with every other RPC — including the adoption's own —
|
|
31756
|
+
* queued behind them. Same defect, same fix, as `refreshDeviceMetadata`
|
|
31757
|
+
* below (`listAll` → `getDevice`).
|
|
31758
|
+
*
|
|
31759
|
+
* Removal is the destructive direction (every proxy handle a consumer
|
|
31760
|
+
* holds goes inert), and an EMPTY binding list is not a claim that the
|
|
31761
|
+
* device is gone — a device can legitimately bind nothing. So it needs
|
|
31762
|
+
* a second read to agree (D49); `device.unregistered` remains the
|
|
31763
|
+
* primary removal path.
|
|
31764
|
+
*/
|
|
31660
31765
|
async refreshBinding(deviceId) {
|
|
31661
31766
|
try {
|
|
31662
|
-
const fresh =
|
|
31663
|
-
if (fresh
|
|
31664
|
-
|
|
31767
|
+
const fresh = await this.api.deviceManager.getBindings.query({ deviceId });
|
|
31768
|
+
if (fresh.entries.length > 0) {
|
|
31769
|
+
this.bindings.set(deviceId, fresh);
|
|
31770
|
+
return;
|
|
31771
|
+
}
|
|
31772
|
+
if (await this.api.deviceManager.getDevice.query({ deviceId }) === null) {
|
|
31773
|
+
this.applyDeviceRemoval(deviceId);
|
|
31774
|
+
return;
|
|
31775
|
+
}
|
|
31776
|
+
this.bindings.set(deviceId, fresh);
|
|
31665
31777
|
} catch {}
|
|
31666
31778
|
}
|
|
31667
31779
|
async refreshDeviceMetadata(deviceId, kind) {
|
|
@@ -39833,6 +39945,21 @@ function toggleAudioLabel(labels, id) {
|
|
|
39833
39945
|
var CLASS_CONDITION_IDS = new Set(["classes", "classesExclude"]);
|
|
39834
39946
|
/** Condition ids that render the sensor/control label picker. */
|
|
39835
39947
|
var LABEL_CONDITION_IDS = new Set(["sensorKinds"]);
|
|
39948
|
+
/**
|
|
39949
|
+
* Condition ids whose class scope is a COUNT, not a match — they get the
|
|
39950
|
+
* MACRO-ONLY vocabulary.
|
|
39951
|
+
*
|
|
39952
|
+
* Every other class condition goes through the engine's `expandClassSelector`,
|
|
39953
|
+
* which expands a macro to its subs and matches a sub against the detection's
|
|
39954
|
+
* own class. Occupancy does not: it reads `byClass[className]` out of the
|
|
39955
|
+
* ZoneAnalytics snapshot, and that record is keyed on MACROS only (the executor
|
|
39956
|
+
* maps COCO onto the macro and drops the rest). A sub-type therefore names a key
|
|
39957
|
+
* that does not exist — the counter is 0 forever and the rule cannot fire.
|
|
39958
|
+
*
|
|
39959
|
+
* Live cost, 2026-08-12: two rules on device 617 were authored with `car`
|
|
39960
|
+
* because this picker offered the whole taxonomy. They were silent for a day.
|
|
39961
|
+
*/
|
|
39962
|
+
var COUNT_CLASS_CONDITION_IDS = new Set(["occupancy"]);
|
|
39836
39963
|
function toOption(entry) {
|
|
39837
39964
|
return {
|
|
39838
39965
|
value: entry.kind,
|
|
@@ -39910,6 +40037,14 @@ function pickerForCondition(conditionId, taxonomy) {
|
|
|
39910
40037
|
});
|
|
39911
40038
|
return groups.length > 0 ? { groups } : null;
|
|
39912
40039
|
}
|
|
40040
|
+
if (COUNT_CLASS_CONDITION_IDS.has(conditionId)) {
|
|
40041
|
+
const options = taxonomy.videoClasses.filter((e) => e.parentKind === null).map(toOption);
|
|
40042
|
+
return options.length > 0 ? { groups: [{
|
|
40043
|
+
key: "macro",
|
|
40044
|
+
fallbackLabel: "Classes",
|
|
40045
|
+
options
|
|
40046
|
+
}] } : null;
|
|
40047
|
+
}
|
|
39913
40048
|
if (LABEL_CONDITION_IDS.has(conditionId)) {
|
|
39914
40049
|
const groups = groupLabels(taxonomy.labels);
|
|
39915
40050
|
return groups.length > 0 ? { groups } : null;
|
|
@@ -42512,6 +42647,7 @@ exports.DETAIL_CROP_PADDING_FIELD = DETAIL_CROP_PADDING_FIELD;
|
|
|
42512
42647
|
exports.DETAIL_CROP_PADDING_KEY = DETAIL_CROP_PADDING_KEY;
|
|
42513
42648
|
exports.DETAIL_CROP_SECTION_ID = DETAIL_CROP_SECTION_ID;
|
|
42514
42649
|
exports.DETAIL_CROP_SQUARE_KEY = DETAIL_CROP_SQUARE_KEY;
|
|
42650
|
+
exports.DETECTION_MACRO_CLASSES = DETECTION_MACRO_CLASSES;
|
|
42515
42651
|
exports.DETECTION_PIPELINE_CAP_NAME = DETECTION_PIPELINE_CAP_NAME;
|
|
42516
42652
|
exports.DEVICE_BACKEND_TO_FORMAT = DEVICE_BACKEND_TO_FORMAT;
|
|
42517
42653
|
exports.DEVICE_CAP_NAMES = DEVICE_CAP_NAMES;
|
|
@@ -43337,6 +43473,7 @@ exports.isAudioLabelSelected = isAudioLabelSelected;
|
|
|
43337
43473
|
exports.isBaseConditionKey = isBaseConditionKey;
|
|
43338
43474
|
exports.isCollectionArrayMethod = isCollectionArrayMethod;
|
|
43339
43475
|
exports.isDeployableToAgent = isDeployableToAgent;
|
|
43476
|
+
exports.isDetectionMacroClass = isDetectionMacroClass;
|
|
43340
43477
|
exports.isDeviceConfigCap = require_sleep.isDeviceConfigCap;
|
|
43341
43478
|
exports.isDeviceScopedCap = require_sleep.isDeviceScopedCap;
|
|
43342
43479
|
exports.isEvent = require_sleep.isEvent;
|