@camstack/addon-post-analysis 1.2.281 → 1.2.283

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.
@@ -5360,7 +5360,7 @@ var ZodIssueCode = {
5360
5360
  var ZodFirstPartyTypeKind;
5361
5361
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5362
5362
  //#endregion
5363
- //#region ../types/dist/sleep-D_4W7xuQ.mjs
5363
+ //#region ../types/dist/sleep-DU7mu4wb.mjs
5364
5364
  /**
5365
5365
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5366
5366
  * window to float samples (D455).
@@ -17925,6 +17925,9 @@ var NcSystemEventKindSchema = _enum([
17925
17925
  "device-battery-normal",
17926
17926
  "device-consumable-low",
17927
17927
  "device-consumable-normal",
17928
+ "device-tank-low",
17929
+ "device-tank-full",
17930
+ "device-tank-normal",
17928
17931
  "stream-online",
17929
17932
  "stream-offline",
17930
17933
  "node-online",
@@ -17985,6 +17988,18 @@ var NC_ALARM_SYSTEM_EVENT_KINDS = [
17985
17988
  "alarm-disarmed"
17986
17989
  ];
17987
17990
  /**
17991
+ * The two kinds a RULE's consumable threshold speaks about (D642). Named once:
17992
+ * the filter scoping (`systemEventFilterApplies`), the hub's threshold census
17993
+ * and both editors read it.
17994
+ */
17995
+ var NC_CONSUMABLE_SYSTEM_EVENT_KINDS = ["device-consumable-low", "device-consumable-normal"];
17996
+ /** A vacuum's tank alerts (D642) — raised on the provider's own verdict. */
17997
+ var NC_TANK_SYSTEM_EVENT_KINDS = [
17998
+ "device-tank-low",
17999
+ "device-tank-full",
18000
+ "device-tank-normal"
18001
+ ];
18002
+ /**
17988
18003
  * One coherent system-event condition. `kinds` is the required opt-in safety
17989
18004
  * gate; the remaining lists are optional narrowing filters relevant to the
17990
18005
  * selected kinds.
@@ -18018,8 +18033,27 @@ var NcSystemEventConditionSchema = object({
18018
18033
  */
18019
18034
  excludeDeviceIds: array(number().int()).min(1).optional(),
18020
18035
  nodeIds: array(string().min(1)).min(1).optional(),
18021
- packageNames: array(string().min(1)).min(1).optional()
18036
+ packageNames: array(string().min(1)).min(1).optional(),
18037
+ /**
18038
+ * At or below this remaining-life %, a consumable is LOW for THIS rule
18039
+ * (D642). Absent = {@link NC_CONSUMABLE_LOW_PERCENT_DEFAULT}; at most
18040
+ * {@link NC_CONSUMABLE_LOW_PERCENT_MAX}, so every episode can recover. Scoped to the
18041
+ * consumable kinds (`systemEventFilterApplies`) and to the device-events
18042
+ * family; ignored on every other kind.
18043
+ *
18044
+ * It is a property of the RULE because the operator decided so: a rule at
18045
+ * 25 must be told about a filter at 20 %, a rule at 10 must not. The hub
18046
+ * keeps one episode per (threshold, device, item) — its own hysteresis, its
18047
+ * own reminder — and a rule hears only the episode judged at ITS threshold,
18048
+ * exactly as an occupancy rule hears only the edge of its own count. A
18049
+ * provider's own `replace` verdict is low at every threshold.
18050
+ */
18051
+ consumableLowPercent: number().int().min(1).max(95).optional()
18022
18052
  });
18053
+ /** The consumable threshold a system-event condition judges at (D642). */
18054
+ function consumableLowPercentOf(condition) {
18055
+ return condition.consumableLowPercent ?? 15;
18056
+ }
18023
18057
  /** Hard ceiling on a window (24h). A snooze that could not expire would be an
18024
18058
  * outage the operator asked for once and forgot. */
18025
18059
  var NC_SNOOZE_MAX_MINUTES = 1440;
@@ -18178,6 +18212,16 @@ var NcCrossingSchema = _enum([
18178
18212
  "exit",
18179
18213
  "any"
18180
18214
  ]);
18215
+ /**
18216
+ * Which edge of a BOOLEAN sensor fires a device-event rule (D640).
18217
+ * - `raised` — the sensor went high: water detected, smoke, open, tampered.
18218
+ * - `cleared` — it went back: dry, clear, closed.
18219
+ * - absent — both edges, which is what every rule authored before this did.
18220
+ *
18221
+ * There is no third member for "both": absence already says it, and a value
18222
+ * that means the same as absence is a second way to write one rule.
18223
+ */
18224
+ var NcSensorTransitionSchema = _enum(["raised", "cleared"]);
18181
18225
  /** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
18182
18226
  var NcZoneConditionSchema = object({
18183
18227
  ids: array(string().min(1)).min(1),
@@ -18367,6 +18411,20 @@ var NcConditionsSchema = object({
18367
18411
  scene: NcSceneConditionSchema.optional(),
18368
18412
  /** Device scope — absent = all devices. */
18369
18413
  devices: array(number()).optional(),
18414
+ /**
18415
+ * Device EXCLUSION (D641) — "every device except these". Judged on the SAME
18416
+ * subject ids {@link devices} is judged on (the camera, the sensor that
18417
+ * fired, a linked set's sensor and row cameras), so a sensor fanned out per
18418
+ * linked camera is excluded exactly where an include would have tested it.
18419
+ * `min(1)`: an empty exclusion excludes nothing and is written as absent.
18420
+ *
18421
+ * Not for `system-event` rules — those carry their own
18422
+ * `systemEvent.excludeDeviceIds` (D636), and the hub refuses this key there.
18423
+ * Editors present the two lists as ONE field (All | Only these | All except
18424
+ * these); the engine evaluates each independently, so a legacy rule
18425
+ * carrying both still means "these, minus those".
18426
+ */
18427
+ devicesExclude: array(number()).min(1).optional(),
18370
18428
  /** Detector class names (any overlap with the record's class set). */
18371
18429
  classes: array(string().min(1)).optional(),
18372
18430
  /** Veto classes — any overlap fails the rule. */
@@ -18500,6 +18558,16 @@ var NcConditionsSchema = object({
18500
18558
  */
18501
18559
  sensorKinds: array(string().min(1)).optional(),
18502
18560
  /**
18561
+ * DEVICE-EVENT only (D640). Fire on one edge of a boolean sensor —
18562
+ * {@link NcSensorTransitionSchema}. Which field of the slice means "raised"
18563
+ * is `@camstack/types` → `notification/sensor-raised.ts`. A reading the
18564
+ * engine cannot place (a kind with no raise, an unreadable slice) PASSES:
18565
+ * the condition fails open towards notifying, never towards silence. Editors
18566
+ * offer it only when every chosen {@link sensorKinds} member has a raise
18567
+ * (`sensorTransitionOffered`), and the hub refuses it on any other delivery.
18568
+ */
18569
+ sensorTransition: NcSensorTransitionSchema.optional(),
18570
+ /**
18503
18571
  * PACKAGE-EVENT only. Which package phase fires the rule — `delivered`
18504
18572
  * (a parked parcel appeared), `picked-up` (it departed), or `both`. Fails
18505
18573
  * when the subject's phase does not match (a subject always carries a phase
@@ -19118,6 +19186,7 @@ var NcConditionDescriptorSchema = object({
19118
19186
  /** Editor widget the UI renders — never hardcode per-condition forms. */
19119
19187
  valueType: _enum([
19120
19188
  "deviceIdList",
19189
+ "deviceIdExcludeList",
19121
19190
  "stringList",
19122
19191
  "number01",
19123
19192
  "number",
@@ -19128,6 +19197,7 @@ var NcConditionDescriptorSchema = object({
19128
19197
  "plateMatcher",
19129
19198
  "packagePhase",
19130
19199
  "crossingSelect",
19200
+ "sensorTransition",
19131
19201
  "polygonDraw",
19132
19202
  "occupancy",
19133
19203
  "audio",
@@ -19261,6 +19331,18 @@ var NC_CONDITION_CATALOG = [
19261
19331
  value: "device-consumable-normal",
19262
19332
  label: "Consumable replaced"
19263
19333
  },
19334
+ {
19335
+ value: "device-tank-low",
19336
+ label: "Tank low (water, detergent)"
19337
+ },
19338
+ {
19339
+ value: "device-tank-full",
19340
+ label: "Tank full (dirty water, dust)"
19341
+ },
19342
+ {
19343
+ value: "device-tank-normal",
19344
+ label: "Tank back to normal"
19345
+ },
19264
19346
  {
19265
19347
  value: "export-completed",
19266
19348
  label: "Export completed"
@@ -19326,6 +19408,21 @@ var NC_CONDITION_CATALOG = [
19326
19408
  phase: "P1",
19327
19409
  description: "Restrict the rule to these devices; absent = all devices. A sensor event matches either the SENSOR that fired or the camera it is attributed to, so a rule may name either one."
19328
19410
  },
19411
+ {
19412
+ id: "devicesExclude",
19413
+ group: "scope",
19414
+ label: "Excluded devices",
19415
+ valueType: "deviceIdExcludeList",
19416
+ operator: "notIn",
19417
+ appliesTo: [
19418
+ "immediate",
19419
+ "track-end",
19420
+ "device-event",
19421
+ "package-event"
19422
+ ],
19423
+ phase: "P1",
19424
+ description: "Every device except these. Judged on the same device ids as Devices: a sensor event is excluded by the SENSOR that fired or by the camera it is attributed to."
19425
+ },
19329
19426
  {
19330
19427
  id: "classes",
19331
19428
  group: "class",
@@ -19582,6 +19679,33 @@ var NC_CONDITION_CATALOG = [
19582
19679
  phase: "P1",
19583
19680
  description: "Raw device event-type tokens (e.g. doorbell press / press_long) from the event-emitter slice; absent on doorbell-pulse / passive sensors."
19584
19681
  },
19682
+ {
19683
+ id: "sensorTransition",
19684
+ group: "device",
19685
+ label: "Notify when",
19686
+ valueType: "sensorTransition",
19687
+ options: [
19688
+ {
19689
+ value: "",
19690
+ label: "It triggers and when it clears",
19691
+ hint: "Every change: water detected, and back to dry."
19692
+ },
19693
+ {
19694
+ value: "raised",
19695
+ label: "Only when it triggers",
19696
+ hint: "Water detected, smoke, a contact opening — never the return to normal."
19697
+ },
19698
+ {
19699
+ value: "cleared",
19700
+ label: "Only when it clears",
19701
+ hint: "Back to dry, smoke gone, a contact closing — never the alert itself."
19702
+ }
19703
+ ],
19704
+ operator: "in",
19705
+ appliesTo: ["device-event"],
19706
+ phase: "P2",
19707
+ description: "Fire on one edge of a boolean sensor. Offered only when every chosen sensor kind raises and clears; a reading that cannot be placed still notifies."
19708
+ },
19585
19709
  {
19586
19710
  id: "packagePhase",
19587
19711
  group: "package",
@@ -19765,6 +19889,28 @@ var NcHistoryFilterSchema = object({
19765
19889
  limit: number().int().min(1).max(500).default(100)
19766
19890
  });
19767
19891
  /**
19892
+ * Every rule's last run, in one answer.
19893
+ *
19894
+ * A rule ABSENT from `runs` produced no delivery inside `horizonMs` — how far
19895
+ * back this answer looked, in ms before the hub's now. It is the outbox prune
19896
+ * window (7 days by default, operator-configurable), NARROWED when the read hit
19897
+ * its row bound: the answer never claims a window it did not read. `null` means
19898
+ * the operator keeps the outbox forever AND the read reached its end, so absent
19899
+ * means "never on record". A UI derives its "not in the last N days" from this
19900
+ * value, never from a constant — and only when the call ANSWERED (D315).
19901
+ */
19902
+ var NcRuleLastRunsSchema = object({
19903
+ runs: array(object({
19904
+ ruleId: string(),
19905
+ /** Fire time of the newest row (`createdAt`, epoch ms). */
19906
+ lastAt: number(),
19907
+ status: NcHistoryStatusSchema,
19908
+ /** The camera/device of that row (a digest row files under its first camera). */
19909
+ deviceId: number()
19910
+ })),
19911
+ horizonMs: number().nonnegative().nullable()
19912
+ });
19913
+ /**
19768
19914
  * What a snooze covers. Broader scopes win when several overlap, so one window
19769
19915
  * leaves ONE digest rather than a rule snooze and a whole-feed snooze both
19770
19916
  * summarising the same silence.
@@ -19946,6 +20092,14 @@ var NcAlarmModeCoverageSchema = object({
19946
20092
  /** Ids named by the covering rules. A SUBSET when `allDevices` is true. */
19947
20093
  deviceIds: array(number().int()),
19948
20094
  /**
20095
+ * D641: the ids NOT covered although `allDevices` is true — every unscoped
20096
+ * covering rule EXCLUDES them (`conditions.devicesExclude`) and no named rule
20097
+ * covers them. Always `[]` when `allDevices` is false. Excluded by the rules,
20098
+ * which is not the same as skipped by a switch: never in `skippedDevices`.
20099
+ * Defaulted so an answer computed before this field parses as "none".
20100
+ */
20101
+ allDevicesExcept: array(number().int()).default([]),
20102
+ /**
19949
20103
  * Devices this mode NAMES but cannot actually arm, each with the switch that
19950
20104
  * excludes it.
19951
20105
  *
@@ -20169,6 +20323,15 @@ var notificationRulesCapability = {
20169
20323
  */
20170
20324
  getHistory: method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" }),
20171
20325
  /**
20326
+ * The newest delivery of every rule, in ONE bounded read of the outbox —
20327
+ * the "Last run" column. Never a `getHistory` per rule. A rule with no
20328
+ * delivery inside `horizonMs` is absent from `runs`; see
20329
+ * {@link NcRuleLastRunsSchema} for what absent means. A store that cannot
20330
+ * answer FAILS the call rather than answering "nothing ran". Admin-only,
20331
+ * like `getHistory`, of which it is a projection.
20332
+ */
20333
+ getRuleLastRuns: method(object({}), NcRuleLastRunsSchema, { auth: "admin" }),
20334
+ /**
20172
20335
  * Mint a fresh, externally-reachable URL for one artefact a history row
20173
20336
  * named in {@link NcHistoryEntrySchema.shape.artifactIds} — the SAME
20174
20337
  * signed-link mechanism the dispatcher uses to attach media to an
@@ -29575,12 +29738,20 @@ reset: method(object({
29575
29738
  },
29576
29739
  runtimeState: ConsumablesStatusSchema.extend({ lastFetchedAt: number() }),
29577
29740
  /**
29578
- * Runtime-state durability: **session** — the authority is the appliance; the provider re-reads the whole item array on connect.
29741
+ * Runtime-state durability: **restored** — nothing else holds the value
29742
+ * (D642). A consumable can often be read only in a device's wake window (the
29743
+ * Dreame mower's CMS counters answer only while it charges), so a restart
29744
+ * that wiped the slice left the panel empty and the alerts blind until the
29745
+ * next wake — 2026-09-26, mower 503 idle with `items: []`. A restored item is
29746
+ * the previous observation, not a claim about now; the provider overwrites it
29747
+ * the moment it reads the device again.
29579
29748
  *
29580
29749
  * See `RuntimeStateDurability`. Enforced by
29581
29750
  * `scripts/check-runtime-state-durability.ts`.
29582
29751
  */
29583
- durability: "session"
29752
+ durability: "restored",
29753
+ /** Clocks, not content: a re-read that changed no item costs no commit. */
29754
+ volatileStateFields: ["lastChangedAt", "lastFetchedAt"]
29584
29755
  };
29585
29756
  /**
29586
29757
  * Door / window / opening / garage / valve contact sensor. Boolean
@@ -44946,6 +45117,12 @@ Object.freeze({
44946
45117
  addonId: null,
44947
45118
  access: "view"
44948
45119
  },
45120
+ "notificationRules.getRuleLastRuns": {
45121
+ capName: "notification-rules",
45122
+ capScope: "system",
45123
+ addonId: null,
45124
+ access: "view"
45125
+ },
44949
45126
  "notificationRules.getTemplateCatalog": {
44950
45127
  capName: "notification-rules",
44951
45128
  capScope: "system",
@@ -50562,12 +50739,55 @@ function audioModeOf(value) {
50562
50739
  return null;
50563
50740
  }
50564
50741
  new Set(["devices", "classes"]);
50565
- /** Every filter, for the callers that must cover all four (guards, tests). */
50742
+ /**
50743
+ * WHICH narrowing filter speaks about WHICH system-event kind — one predicate,
50744
+ * consumed by the rule ENGINE and by every rule EDITOR.
50745
+ *
50746
+ * ── The failure this file exists for ───────────────────────────────────────
50747
+ * `NcSystemEventConditionSchema` carries four optional narrowing lists
50748
+ * (`deviceIds`, `deviceTypes`, `nodeIds`, `packageNames`) beside a required
50749
+ * `kinds` gate. They are not four filters over one vocabulary: each belongs to
50750
+ * a FAMILY of kinds and is meaningless outside it. A node going away has no
50751
+ * device type; a completed export has no package; `stream-offline` deliberately
50752
+ * carries no device type at all (a stream belongs to a camera by construction).
50753
+ *
50754
+ * The engine applied all four to every kind, so a filter from one family failed
50755
+ * a kind from another family CLOSED. The operator's live rule "Eventi di
50756
+ * sistema" selected eleven kinds and set `deviceTypes: ['camera']` — the only
50757
+ * way to say "only my cameras" about the two liveness kinds — and NINE of the
50758
+ * eleven silently stopped being deliverable. Four days of history contained
50759
+ * `device-online` and `device-offline` and nothing else, across a window in
50760
+ * which agents were restarted and addons were updated.
50761
+ *
50762
+ * Both editors already computed this scoping, to decide which filter boxes to
50763
+ * render; the cap's own docblock already promised it ("Narrow a `device-*` kind
50764
+ * to these device TYPES"). Only the engine disagreed, and it disagreed in the
50765
+ * destructive direction. So the rule is stated ONCE, here, and the engine and
50766
+ * the editors are readers of it rather than three independent authors.
50767
+ *
50768
+ * ── The direction ─────────────────────────────────────────────────────────
50769
+ * Out of family ⇒ the filter is IGNORED, never fail-closed. An editor that
50770
+ * hides a box has already told the operator this filter does not speak about
50771
+ * these kinds, so honouring it as an exclusion contradicts the only
50772
+ * explanation the operator was ever given. Inside its family the filter still
50773
+ * narrows, and still fails CLOSED on a subject that cannot produce the identity
50774
+ * it tests (a device the mirror cannot name is not evidence of a camera).
50775
+ */
50776
+ /**
50777
+ * Every filter, for the callers that must cover all of them (guards, tests).
50778
+ *
50779
+ * `consumableLowPercent` (D642) is not a list but it is a filter in exactly
50780
+ * this sense: it belongs to a family of kinds (the consumable pair) and the
50781
+ * engine consults it only there. It differs in one way the readers must know —
50782
+ * its ABSENCE is not "no narrowing" but the default threshold, because a
50783
+ * consumable episode is always judged at SOME threshold.
50784
+ */
50566
50785
  var NC_SYSTEM_EVENT_FILTER_KEYS = [
50567
50786
  "deviceIds",
50568
50787
  "deviceTypes",
50569
50788
  "nodeIds",
50570
- "packageNames"
50789
+ "packageNames",
50790
+ "consumableLowPercent"
50571
50791
  ];
50572
50792
  /**
50573
50793
  * Does `filter` say anything about `kind`?
@@ -50581,6 +50801,7 @@ function systemEventFilterApplies(kind, filter) {
50581
50801
  case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind";
50582
50802
  case "nodeIds": return kind.startsWith("node-") || kind === "addon-crash-loop" || kind === "addon-update-available" || kind === "addon-updated" || kind === "server-update-available" || kind === "wrapper-update-available" || kind === "server-updated";
50583
50803
  case "packageNames": return kind.endsWith("update-available") || kind === "addon-updated" || kind === "server-updated";
50804
+ case "consumableLowPercent": return NC_CONSUMABLE_SYSTEM_EVENT_KINDS.includes(kind);
50584
50805
  }
50585
50806
  }
50586
50807
  /**
@@ -50616,6 +50837,9 @@ var NC_SYSTEM_EVENT_FAMILY = {
50616
50837
  "device-battery-normal": "device-events",
50617
50838
  "device-consumable-low": "device-events",
50618
50839
  "device-consumable-normal": "device-events",
50840
+ "device-tank-low": "device-events",
50841
+ "device-tank-full": "device-events",
50842
+ "device-tank-normal": "device-events",
50619
50843
  "stream-online": "device-events",
50620
50844
  "stream-offline": "device-events",
50621
50845
  "detection-blind": "device-events",
@@ -50647,7 +50871,7 @@ var NC_SYSTEM_EVENT_FAMILY = {
50647
50871
  new Map(Object.entries(NC_SYSTEM_EVENT_FAMILY));
50648
50872
  var NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS = [...NC_SYSTEM_EVENT_FILTER_KEYS, "excludeDeviceIds"];
50649
50873
  /**
50650
- * The filters a family may carry. The four base filters are the union of
50874
+ * The filters a family may carry. The base filters are the union of
50651
50875
  * `systemEventFilterApplies` over the family's kinds (the spec pins that
50652
50876
  * equality). `excludeDeviceIds` is a device-events filter only: an alarm is
50653
50877
  * narrowed to the camera that triggered it and excludes nothing.
@@ -50656,7 +50880,8 @@ var NC_SYSTEM_EVENT_FAMILY_FILTERS = {
50656
50880
  "device-events": [
50657
50881
  "deviceIds",
50658
50882
  "excludeDeviceIds",
50659
- "deviceTypes"
50883
+ "deviceTypes",
50884
+ "consumableLowPercent"
50660
50885
  ],
50661
50886
  system: ["nodeIds", "packageNames"],
50662
50887
  alarm: ["deviceIds"]
@@ -50691,6 +50916,16 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
50691
50916
  label: "Consumables",
50692
50917
  kinds: ["device-consumable-low", "device-consumable-normal"]
50693
50918
  },
50919
+ {
50920
+ id: "tanks",
50921
+ family: "device-events",
50922
+ label: "Tanks",
50923
+ kinds: [
50924
+ "device-tank-low",
50925
+ "device-tank-full",
50926
+ "device-tank-normal"
50927
+ ]
50928
+ },
50694
50929
  {
50695
50930
  id: "detection-blind",
50696
50931
  family: "device-events",
@@ -50870,10 +51105,75 @@ function isScheduleActive(schedule, atMs) {
50870
51105
  }
50871
51106
  return schedule.invert === true ? !inside : inside;
50872
51107
  }
51108
+ var ARMED_WORD_PREFIX = "armed_";
51109
+ var ALARM_PANEL_CAP = "alarm-panel";
51110
+ var ALARM_PANEL_TRIGGER_METHOD = "trigger";
51111
+ /**
51112
+ * A rule belongs to the alarm when its `deviceState` gate names ANY device's
51113
+ * `armed_*` word, or an ENABLED `onTrigger` sequence pulls the alarm panel's
51114
+ * trigger (D630).
51115
+ */
51116
+ function ruleBelongsToAlarm(rule) {
51117
+ if ((rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX))) return true;
51118
+ return (rule.onTrigger ?? []).some((sequence) => sequence.enabled && sequence.actions.some((step) => step.kind === "cap" && step.cap === ALARM_PANEL_CAP && step.method === ALARM_PANEL_TRIGGER_METHOD));
51119
+ }
51120
+ /**
51121
+ * WHICH WAY A BOOLEAN SENSOR MOVED — read off the one slice a sensor event
51122
+ * persists (D640 "a sensor rule fires on the raise, the clear, or both").
51123
+ *
51124
+ * A device-event rule over a flood sensor notified on BOTH edges: water
51125
+ * detected, and back to dry. `NcConditions.sensorTransition` lets the rule
51126
+ * name one edge; this file answers, for one `SensorEvent`, which edge it is.
51127
+ *
51128
+ * NOT A SECOND TABLE. The "which boolean of this cap counts as HIGH" question
51129
+ * already has one answer, `SOURCE_CAP_ACTIVE_FIELD`
51130
+ * (`catalogs/sensor-active-state.ts`, the doorbell's and the recorder's edge
51131
+ * table), and a sensor event names its kind, not its cap. So the table here is
51132
+ * DERIVED: event kind → cap (`EVENT_KIND_BY_CAP`) → that cap's active field.
51133
+ * Only kinds whose taxonomy category is `sensor` take part — a switch has an
51134
+ * `on` boolean too, but "it triggers / it clears" is not a sentence about a
51135
+ * light, and offering it there would be a knob with a misleading label.
51136
+ * `presence` is a WORD (`home` / `not_home` / a zone), not a boolean, and is
51137
+ * absent from the source table, so it is absent here.
51138
+ *
51139
+ * `undefined` = never guessed: a kind with no raise (a doorbell press, a
51140
+ * button, a cover), or a slice whose field is missing or not a boolean. The
51141
+ * engine then does NOT filter — a flood alert must not go silent because one
51142
+ * read came back unreadable (the same stance as the alarm's `sensorEdgeOf`).
51143
+ *
51144
+ * Pure, RN-safe: the viewer imports the support rule from here.
51145
+ */
51146
+ /** Event kind → the boolean field of its cap slice that means "raised". */
51147
+ var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
51148
+ const field = SOURCE_CAP_ACTIVE_FIELD[capName];
51149
+ if (field === void 0 || descriptor.category !== "sensor") return [];
51150
+ return [[descriptor.kind, field]];
51151
+ })));
51152
+ /** The sensor kinds `sensorTransition` means something for. */
51153
+ var NC_SENSOR_TRANSITION_KINDS = Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
51154
+ function normaliseKind(kind) {
51155
+ return kind.trim().toLowerCase();
51156
+ }
51157
+ /**
51158
+ * true = the sensor is raised (water, smoke, open, tampered…), false = it
51159
+ * cleared, undefined = this kind has no raise or the slice cannot say.
51160
+ */
51161
+ function sensorRaisedOf(kind, value) {
51162
+ if (value === null) return void 0;
51163
+ const field = NC_SENSOR_RAISED_FIELD_BY_KIND[normaliseKind(kind)];
51164
+ if (field === void 0) return void 0;
51165
+ const raw = Object.entries(value).find(([key]) => key === field)?.[1];
51166
+ return typeof raw === "boolean" ? raw : void 0;
51167
+ }
50873
51168
  var RULE_BODY_ONLY = ["body"];
50874
51169
  var RULE_TEXT = ["title", "body"];
50875
51170
  var BATTERY = ["device-battery-low", "device-battery-normal"];
50876
51171
  var CONSUMABLE = ["device-consumable-low", "device-consumable-normal"];
51172
+ var TANK = [
51173
+ "device-tank-low",
51174
+ "device-tank-full",
51175
+ "device-tank-normal"
51176
+ ];
50877
51177
  var UPDATES = [
50878
51178
  "addon-update-available",
50879
51179
  "server-update-available",
@@ -50899,6 +51199,7 @@ var DEVICE_EVENTS = [
50899
51199
  "device-enabled",
50900
51200
  ...BATTERY,
50901
51201
  ...CONSUMABLE,
51202
+ ...TANK,
50902
51203
  "stream-online",
50903
51204
  "stream-offline",
50904
51205
  "detection-blind",
@@ -51196,6 +51497,17 @@ var NC_TEMPLATE_VARS = [
51196
51497
  kinds: ["system"],
51197
51498
  systemEventKinds: [...CONSUMABLE]
51198
51499
  },
51500
+ {
51501
+ name: "tank",
51502
+ label: "Tank",
51503
+ description: "Which tank: clean water, dirty water, detergent or dust bin.",
51504
+ example: "clean water",
51505
+ group: "system",
51506
+ families: ["rule"],
51507
+ fields: [...RULE_TEXT],
51508
+ kinds: ["system"],
51509
+ systemEventKinds: [...TANK]
51510
+ },
51199
51511
  {
51200
51512
  name: "profile",
51201
51513
  label: "Stream profile",
@@ -51588,6 +51900,38 @@ var NC_TEMPLATE_VARS = [
51588
51900
  fields: [...RULE_TEXT]
51589
51901
  }
51590
51902
  ];
51903
+ /**
51904
+ * System-event kinds the SERVED catalog holds back (D642): the kinds the hub
51905
+ * produces before the installed viewers can parse them.
51906
+ *
51907
+ * The viewer parses `getTemplateCatalog` WHOLE, with its own strict
51908
+ * `NcSystemEventKindSchema` on every descriptor's `systemEventKinds`, so one
51909
+ * kind it does not know — in `{{deviceName}}`, which every device event names —
51910
+ * empties every {{var}} picker on every phone (the same trap
51911
+ * `NcTemplateVarKindSchema` froze the rule kinds for). The in-process catalog
51912
+ * keeps them: the producer parity and the preview render read it.
51913
+ *
51914
+ * SELF-EXPIRING: `scripts/check-nc-mirrors-in-sync.ts` reads this list as the
51915
+ * viewer's allowance and fails the day the viewer mirrors one of these kinds —
51916
+ * delete it from here then, and the served catalog names it again.
51917
+ */
51918
+ var NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS = [
51919
+ "device-tank-low",
51920
+ "device-tank-full",
51921
+ "device-tank-normal"
51922
+ ];
51923
+ /**
51924
+ * The catalog as `getTemplateCatalog` SERVES it: every descriptor, with the
51925
+ * held-back kinds removed from its `systemEventKinds`. A descriptor that named
51926
+ * only held-back kinds is served with an empty list — offered to no system
51927
+ * rule an installed viewer can author, which is exactly true.
51928
+ */
51929
+ function servedTemplateVars() {
51930
+ return NC_TEMPLATE_VARS.map((d) => d.systemEventKinds === void 0 ? d : {
51931
+ ...d,
51932
+ systemEventKinds: d.systemEventKinds.filter((kind) => !NC_TEMPLATE_HELD_BACK_SYSTEM_EVENT_KINDS.includes(kind))
51933
+ });
51934
+ }
51591
51935
  /** The caption fields see a fixed, smaller vocabulary (`timelapsePreviewText`,
51592
51936
  * `summaryCaptionText`). Declared here rather than as `fields` on every
51593
51937
  * descriptor so the whole rule stays in one line of code. */
@@ -52662,4 +53006,4 @@ function vectorDimFromBase64(encoded) {
52662
53006
  return Math.floor(Buffer.from(encoded, "base64").byteLength / 4);
52663
53007
  }
52664
53008
  //#endregion
52665
- export { RECORDING_EXPORT_MAX_READ_BYTES as $, vectorDimFromBase64 as $t, NC_SNOOZE_MAX_MINUTES as A, isKnownTemplateVar as At, NcRuleTargetSchema as B, pickClusterStepModels as Bt, MAX_BIRTH_DECISION_RECORDS as C, unknown as Cn, evaluateSensorEdge as Ct, NC_ALARM_SYSTEM_EVENT_KINDS as D, hfModelUrl as Dt, MediaFileKindEnum as E, failureContributionCapability as Et, NcConditionDescriptorSchema as F, kebabToCamel as Ft, NcSnoozeSuppressedSchema as G, resolveLocationMode as Gt, NcScheduleSchema as H, plateGalleryCapability as Ht, NcConditionsSchema as I, mayWriteToLocation as It, NcTemplatePreviewInputSchema as J, storageOccupancyCapability as Jt, NcSystemEventKindSchema as K, resolvePoolMemoryPolicy as Kt, NcRuleInputSchema as L, notificationRulesCapability as Lt, NC_TEMPLATE_VARS as M, isScheduleActive as Mt, NcAlarmConfigSchema as N, isSourceCap as Nt, NC_CONDITION_CATALOG as O, isDetectionMacroClass as Ot, NcAlarmSettingsPatchSchema as P, isSystemDelivery as Pt, PoolMemoryWatchdog as Q, templateVarsFor as Qt, NcRulePatchSchema as R, occupancyScope as Rt, MAX_ARCHIVED_DEBUG_NOTES as S, string as Sn, encodeVectorBase64 as St, MOTION_CLOSE_AFTER_MS as T, faceGalleryCapability as Tt, NcSnoozeInputSchema as U, readDeviceStateFrom as Ut, NcRuleUpdateInputSchema as V, pipelineAnalyticsCapability as Vt, NcSnoozeSchema as W, readTimelapseGeneratedAt as Wt, NcTemplateVarDescriptorSchema as X, systemEventFamilyProblems as Xt, NcTemplatePreviewSchema as Y, subKindsOf as Yt, OpsLogEntrySchema as Z, systemEventFilterApplies as Zt, FIRST_LEVEL_MACRO_CLASSES as _, literal as _n, buildEventKindDescriptor as _t, BirthDecisionRecordSchema as a, DeviceType as an, SCENE_DIVERGED as at, LabelAttributionSchema as b, partialRecord as bn, describeSystemEventFamilyProblem as bt, CoverStateSchema as c, defineCustomActions as cn, TimelapseRuleInputSchema as ct, DEFAULT_TIMELAPSE_PREVIEW_TEXT as d, nodePin as dn, TrackSourceSchema as dt, zoneAnalyticsCapability as en, RECORDING_SOURCE_CAMSTACK_ADDON as et, DETECTION_MACRO_CLASSES as f, sleep as fn, addonWidgetsSourceCapability as ft, EVENT_OWNER_TYPES as g, discriminatedUnion as gn, audioModeOf as gt, EVENT_KIND_BY_CAP as h, boolean as hn, audioMetricsCapability as ht, BaseDevice as i, CamProfileSchema as in, SCENE_DEFAULT_UNCOVERED_POLICY as it, NC_TAXONOMY as j, isMediaOwnerType as jt, NC_DEFAULT_SNOOZE_MINUTES as k, isEventOwnerType as kt, DEFAULT_EVENT_COLOR as l, hydrateSchema as ln, TimelapseRulePatchSchema as lt, DeclaredDevices as m, array as mn, assertTimelapseCadences as mt, AlarmArmModeSchema as n, canonicalHash as nn, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as nt, CLUSTER_MODEL_SCOPED_STEPS as o, createEvent as on, SceneMonitorSchema as ot, DETECTION_PIPELINE_CAP_NAME as p, _enum as pn, alarmPanelCapability as pt, NcTaxonomySchema as q, sceneMonitorCapability as qt, ArchivedDebugNoteSchema as r, BaseAddon as rn, SCENE_DEFAULT_ANCHOR_THRESHOLD as rt, COCO_TO_MACRO as s, customAction as sn, TIMELAPSE_DENSE_FLOOR_SEC as st, AUDIO_MACRO_LABELS as t, errMsg as tn, RetrainStatusSchema as tt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as u, isDeviceScopedCap as un, TimelapseRuleSchema as ut, FULL_IMAGE_BBOX as v, number as vn, cosineSimilarity as vt, MAX_BIRTH_LATENCY_PROXY_MS as w, EventCategory as wn, evictionPolicyOfLocation as wt, LockStateSchema as x, record as xn, embeddingEncoderCapability as xt, FailureCounters as y, object as yn, deriveRecordingMode as yt, NcRuleSchema as z, parseProcStatus as zt };
53009
+ export { NcTemplateVarDescriptorSchema as $, sensorRaisedOf as $t, NC_DEFAULT_SNOOZE_MINUTES as A, unknown as An, failureContributionCapability as At, NcRuleInputSchema as B, mayWriteToLocation as Bt, MAX_BIRTH_DECISION_RECORDS as C, discriminatedUnion as Cn, deriveRecordingMode as Ct, NC_ALARM_SYSTEM_EVENT_KINDS as D, partialRecord as Dn, evaluateSensorEdge as Dt, MediaFileKindEnum as E, object as En, encodeVectorBase64 as Et, NC_TEMPLATE_VARS as F, isMediaOwnerType as Ft, NcScheduleSchema as G, pipelineAnalyticsCapability as Gt, NcRuleSchema as H, occupancyScope as Ht, NcAlarmConfigSchema as I, isScheduleActive as It, NcSnoozeSuppressedSchema as J, readTimelapseGeneratedAt as Jt, NcSnoozeInputSchema as K, plateGalleryCapability as Kt, NcAlarmSettingsPatchSchema as L, isSourceCap as Lt, NC_SNOOZE_MAX_MINUTES as M, isDetectionMacroClass as Mt, NC_TANK_SYSTEM_EVENT_KINDS as N, isEventOwnerType as Nt, NC_CONDITION_CATALOG as O, record as On, evictionPolicyOfLocation as Ot, NC_TAXONOMY as P, isKnownTemplateVar as Pt, NcTemplatePreviewSchema as Q, sceneMonitorCapability as Qt, NcConditionDescriptorSchema as R, isSystemDelivery as Rt, MAX_ARCHIVED_DEBUG_NOTES as S, boolean as Sn, cosineSimilarity as St, MOTION_CLOSE_AFTER_MS as T, number as Tn, embeddingEncoderCapability as Tt, NcRuleTargetSchema as U, parseProcStatus as Ut, NcRulePatchSchema as V, notificationRulesCapability as Vt, NcRuleUpdateInputSchema as W, pickClusterStepModels as Wt, NcTaxonomySchema as X, resolvePoolMemoryPolicy as Xt, NcSystemEventKindSchema as Y, resolveLocationMode as Yt, NcTemplatePreviewInputSchema as Z, ruleBelongsToAlarm as Zt, FIRST_LEVEL_MACRO_CLASSES as _, isDeviceScopedCap as _n, assertTimelapseCadences as _t, BirthDecisionRecordSchema as a, templateVarsFor as an, SCENE_CONFIRM_DEFAULT_TIMEOUT_MS as at, LabelAttributionSchema as b, _enum as bn, buildEventKindDescriptor as bt, CoverStateSchema as c, errMsg as cn, SCENE_DIVERGED as ct, DEFAULT_TIMELAPSE_PREVIEW_TEXT as d, CamProfileSchema as dn, TimelapseRuleInputSchema as dt, servedTemplateVars as en, OpsLogEntrySchema as et, DETECTION_MACRO_CLASSES as f, DeviceType as fn, TimelapseRulePatchSchema as ft, EVENT_OWNER_TYPES as g, hydrateSchema as gn, alarmPanelCapability as gt, EVENT_KIND_BY_CAP as h, defineCustomActions as hn, addonWidgetsSourceCapability as ht, BaseDevice as i, systemEventFilterApplies as in, RetrainStatusSchema as it, NC_SENSOR_TRANSITION_KINDS as j, EventCategory as jn, hfModelUrl as jt, NC_CONSUMABLE_SYSTEM_EVENT_KINDS as k, string as kn, faceGalleryCapability as kt, DEFAULT_EVENT_COLOR as l, canonicalHash as ln, SceneMonitorSchema as lt, DeclaredDevices as m, customAction as mn, TrackSourceSchema as mt, AlarmArmModeSchema as n, subKindsOf as nn, RECORDING_EXPORT_MAX_READ_BYTES as nt, CLUSTER_MODEL_SCOPED_STEPS as o, vectorDimFromBase64 as on, SCENE_DEFAULT_ANCHOR_THRESHOLD as ot, DETECTION_PIPELINE_CAP_NAME as p, createEvent as pn, TimelapseRuleSchema as pt, NcSnoozeSchema as q, readDeviceStateFrom as qt, ArchivedDebugNoteSchema as r, systemEventFamilyProblems as rn, RECORDING_SOURCE_CAMSTACK_ADDON as rt, COCO_TO_MACRO as s, zoneAnalyticsCapability as sn, SCENE_DEFAULT_UNCOVERED_POLICY as st, AUDIO_MACRO_LABELS as t, storageOccupancyCapability as tn, PoolMemoryWatchdog as tt, DEFAULT_FIRST_SIGHTING_FRESHNESS_MS as u, BaseAddon as un, TIMELAPSE_DENSE_FLOOR_SEC as ut, FULL_IMAGE_BBOX as v, nodePin as vn, audioMetricsCapability as vt, MAX_BIRTH_LATENCY_PROXY_MS as w, literal as wn, describeSystemEventFamilyProblem as wt, LockStateSchema as x, array as xn, consumableLowPercentOf as xt, FailureCounters as y, sleep as yn, audioModeOf as yt, NcConditionsSchema as z, kebabToCamel as zt };
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-BtqlSCQT.js");
5
+ const require_dist = require("../dist-CT5xOY86.js");
6
6
  let node_fs = require("node:fs");
7
7
  node_fs = require_dist.__toESM(node_fs);
8
8
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Dt as hfModelUrl, Kt as resolvePoolMemoryPolicy, Q as PoolMemoryWatchdog, rn as BaseAddon, xt as embeddingEncoderCapability, zt as parseProcStatus } from "../dist-DkERzZfY.mjs";
1
+ import { Tt as embeddingEncoderCapability, Ut as parseProcStatus, Xt as resolvePoolMemoryPolicy, jt as hfModelUrl, tt as PoolMemoryWatchdog, un as BaseAddon } from "../dist-zp1v7cCp.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import * as fs from "node:fs";
4
4
  import * as path$1 from "node:path";
@@ -1,8 +1,8 @@
1
1
  import { a as e, i as t, n, o as r, r as i, t as a } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs";
2
2
  import { t as o } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-B3Wx5J80.mjs";
3
- import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BA7N1yDM.mjs";
3
+ import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DWPDYuJS.mjs";
4
4
  import { n as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs";
5
- import { t as _ } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-OkXjMLHG.mjs";
5
+ import { t as _ } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-CZkZhroP.mjs";
6
6
  //#region ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
7
7
  var v = (...e) => e.filter((e, t, n) => !!e && e.trim() !== "" && n.indexOf(e) === t).join(" ").trim(), y = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), b = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), x = (e) => {
8
8
  let t = b(e);
@@ -18,7 +18,7 @@ var e = {
18
18
  },
19
19
  "@camstack/types": {
20
20
  name: "@camstack/types",
21
- version: "1.2.255",
21
+ version: "1.2.257",
22
22
  scope: ["default"],
23
23
  loaded: !1,
24
24
  from: "addon_pipeline_analytics_widgets",
@@ -33,7 +33,7 @@ var e = {
33
33
  },
34
34
  "@camstack/ui-library": {
35
35
  name: "@camstack/ui-library",
36
- version: "1.2.204",
36
+ version: "1.2.205",
37
37
  scope: ["default"],
38
38
  loaded: !1,
39
39
  from: "addon_pipeline_analytics_widgets",