@camstack/types 1.2.254 → 1.2.256
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/index.d.ts +2 -2
- package/dist/capabilities/nodes.cap.d.ts +50 -0
- package/dist/capabilities/notification-rules.cap.d.ts +182 -3
- package/dist/capabilities/osd-manager.cap.d.ts +32 -0
- package/dist/generated/addon-api.d.ts +14 -0
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +841 -59
- package/dist/index.mjs +803 -58
- package/dist/notification/alarm-membership.d.ts +43 -0
- package/dist/notification/rule-kinds.d.ts +71 -14
- package/dist/notification/scope-picker-items.d.ts +49 -0
- package/dist/notification/sensor-raised.d.ts +45 -0
- package/dist/notification/system-event-families.d.ts +76 -0
- package/dist/notification/template-vars.d.ts +22 -1
- package/dist/{sleep-D_4W7xuQ.mjs → sleep-DU7mu4wb.mjs} +1 -0
- package/dist/{sleep-BAgDk7I9.js → sleep-DtomDrRW.js} +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
2
|
+
const require_sleep = require("./sleep-DtomDrRW.js");
|
|
3
3
|
const require_event_category = require("./event-category-BVfsrBYA.js");
|
|
4
4
|
const require_canonical_hash = require("./canonical-hash-CSE4ioRi.js");
|
|
5
5
|
const require_enums = require("./enums.js");
|
|
@@ -17495,6 +17495,16 @@ var NcCrossingSchema = zod.z.enum([
|
|
|
17495
17495
|
"exit",
|
|
17496
17496
|
"any"
|
|
17497
17497
|
]);
|
|
17498
|
+
/**
|
|
17499
|
+
* Which edge of a BOOLEAN sensor fires a device-event rule (D640).
|
|
17500
|
+
* - `raised` — the sensor went high: water detected, smoke, open, tampered.
|
|
17501
|
+
* - `cleared` — it went back: dry, clear, closed.
|
|
17502
|
+
* - absent — both edges, which is what every rule authored before this did.
|
|
17503
|
+
*
|
|
17504
|
+
* There is no third member for "both": absence already says it, and a value
|
|
17505
|
+
* that means the same as absence is a second way to write one rule.
|
|
17506
|
+
*/
|
|
17507
|
+
var NcSensorTransitionSchema = zod.z.enum(["raised", "cleared"]);
|
|
17498
17508
|
/** Admin-zone membership condition (zone IDs as stamped by the ZoneEngine). */
|
|
17499
17509
|
var NcZoneConditionSchema = zod.z.object({
|
|
17500
17510
|
ids: zod.z.array(zod.z.string().min(1)).min(1),
|
|
@@ -17684,6 +17694,20 @@ var NcConditionsSchema = zod.z.object({
|
|
|
17684
17694
|
scene: NcSceneConditionSchema.optional(),
|
|
17685
17695
|
/** Device scope — absent = all devices. */
|
|
17686
17696
|
devices: zod.z.array(zod.z.number()).optional(),
|
|
17697
|
+
/**
|
|
17698
|
+
* Device EXCLUSION (D641) — "every device except these". Judged on the SAME
|
|
17699
|
+
* subject ids {@link devices} is judged on (the camera, the sensor that
|
|
17700
|
+
* fired, a linked set's sensor and row cameras), so a sensor fanned out per
|
|
17701
|
+
* linked camera is excluded exactly where an include would have tested it.
|
|
17702
|
+
* `min(1)`: an empty exclusion excludes nothing and is written as absent.
|
|
17703
|
+
*
|
|
17704
|
+
* Not for `system-event` rules — those carry their own
|
|
17705
|
+
* `systemEvent.excludeDeviceIds` (D636), and the hub refuses this key there.
|
|
17706
|
+
* Editors present the two lists as ONE field (All | Only these | All except
|
|
17707
|
+
* these); the engine evaluates each independently, so a legacy rule
|
|
17708
|
+
* carrying both still means "these, minus those".
|
|
17709
|
+
*/
|
|
17710
|
+
devicesExclude: zod.z.array(zod.z.number()).min(1).optional(),
|
|
17687
17711
|
/** Detector class names (any overlap with the record's class set). */
|
|
17688
17712
|
classes: zod.z.array(zod.z.string().min(1)).optional(),
|
|
17689
17713
|
/** Veto classes — any overlap fails the rule. */
|
|
@@ -17817,6 +17841,16 @@ var NcConditionsSchema = zod.z.object({
|
|
|
17817
17841
|
*/
|
|
17818
17842
|
sensorKinds: zod.z.array(zod.z.string().min(1)).optional(),
|
|
17819
17843
|
/**
|
|
17844
|
+
* DEVICE-EVENT only (D640). Fire on one edge of a boolean sensor —
|
|
17845
|
+
* {@link NcSensorTransitionSchema}. Which field of the slice means "raised"
|
|
17846
|
+
* is `@camstack/types` → `notification/sensor-raised.ts`. A reading the
|
|
17847
|
+
* engine cannot place (a kind with no raise, an unreadable slice) PASSES:
|
|
17848
|
+
* the condition fails open towards notifying, never towards silence. Editors
|
|
17849
|
+
* offer it only when every chosen {@link sensorKinds} member has a raise
|
|
17850
|
+
* (`sensorTransitionOffered`), and the hub refuses it on any other delivery.
|
|
17851
|
+
*/
|
|
17852
|
+
sensorTransition: NcSensorTransitionSchema.optional(),
|
|
17853
|
+
/**
|
|
17820
17854
|
* PACKAGE-EVENT only. Which package phase fires the rule — `delivered`
|
|
17821
17855
|
* (a parked parcel appeared), `picked-up` (it departed), or `both`. Fails
|
|
17822
17856
|
* when the subject's phase does not match (a subject always carries a phase
|
|
@@ -18328,9 +18362,29 @@ var NcTestResultSchema = zod.z.object({
|
|
|
18328
18362
|
className: zod.z.string().optional(),
|
|
18329
18363
|
label: zod.z.string().optional()
|
|
18330
18364
|
});
|
|
18331
|
-
/** The
|
|
18332
|
-
*
|
|
18365
|
+
/** The rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts` is the
|
|
18366
|
+
* same union; the template-vars spec pins the two together. `mixed` is DERIVED
|
|
18367
|
+
* (a stored system rule whose kinds span families, D637) and never authored. */
|
|
18333
18368
|
var NcRuleKindSchema = zod.z.enum([
|
|
18369
|
+
"detection",
|
|
18370
|
+
"sensor",
|
|
18371
|
+
"occupancy",
|
|
18372
|
+
"sound",
|
|
18373
|
+
"device-events",
|
|
18374
|
+
"system",
|
|
18375
|
+
"alarm",
|
|
18376
|
+
"mixed"
|
|
18377
|
+
]);
|
|
18378
|
+
/**
|
|
18379
|
+
* The kinds a SERVED template-variable descriptor may name: the five that
|
|
18380
|
+
* existed before D637, frozen. `getTemplateCatalog` ships `kinds` to every
|
|
18381
|
+
* installed viewer, and a viewer at `@camstack/types` 1.2.25x parses them with a
|
|
18382
|
+
* strict five-member enum — one `device-events` in one descriptor fails the
|
|
18383
|
+
* whole catalog parse. So the WIRE says `system`, and the MATCH widens it:
|
|
18384
|
+
* `templateVarKindApplies` reads a `system` descriptor as applying to every
|
|
18385
|
+
* system rule kind (`device-events`, `system`, `alarm`, `mixed`).
|
|
18386
|
+
*/
|
|
18387
|
+
var NcTemplateVarKindSchema = zod.z.enum([
|
|
18334
18388
|
"detection",
|
|
18335
18389
|
"sensor",
|
|
18336
18390
|
"occupancy",
|
|
@@ -18368,7 +18422,7 @@ var NcTemplateVarGroupSchema = zod.z.enum([
|
|
|
18368
18422
|
*
|
|
18369
18423
|
* `families` / `fields` / `kinds` / `deliveries` / `systemEventKinds` say WHERE
|
|
18370
18424
|
* it has a value; absent = no restriction on that axis. `systemEventKinds` is
|
|
18371
|
-
* read only for a
|
|
18425
|
+
* read only for a system-event rule (any family, or `mixed`). `dynamic` declares a FAMILY of names
|
|
18372
18426
|
* (`count_<class>`): the descriptor's `name` is the example member.
|
|
18373
18427
|
*/
|
|
18374
18428
|
var NcTemplateVarDescriptorSchema = zod.z.object({
|
|
@@ -18379,7 +18433,7 @@ var NcTemplateVarDescriptorSchema = zod.z.object({
|
|
|
18379
18433
|
group: NcTemplateVarGroupSchema,
|
|
18380
18434
|
families: zod.z.array(NcTemplateFamilySchema).min(1),
|
|
18381
18435
|
fields: zod.z.array(NcTemplateFieldSchema).optional(),
|
|
18382
|
-
kinds: zod.z.array(
|
|
18436
|
+
kinds: zod.z.array(NcTemplateVarKindSchema).optional(),
|
|
18383
18437
|
deliveries: zod.z.array(NcDeliverySchema).optional(),
|
|
18384
18438
|
systemEventKinds: zod.z.array(NcSystemEventKindSchema).optional(),
|
|
18385
18439
|
dynamic: zod.z.object({
|
|
@@ -18429,6 +18483,7 @@ var NcConditionDescriptorSchema = zod.z.object({
|
|
|
18429
18483
|
/** Editor widget the UI renders — never hardcode per-condition forms. */
|
|
18430
18484
|
valueType: zod.z.enum([
|
|
18431
18485
|
"deviceIdList",
|
|
18486
|
+
"deviceIdExcludeList",
|
|
18432
18487
|
"stringList",
|
|
18433
18488
|
"number01",
|
|
18434
18489
|
"number",
|
|
@@ -18439,6 +18494,7 @@ var NcConditionDescriptorSchema = zod.z.object({
|
|
|
18439
18494
|
"plateMatcher",
|
|
18440
18495
|
"packagePhase",
|
|
18441
18496
|
"crossingSelect",
|
|
18497
|
+
"sensorTransition",
|
|
18442
18498
|
"polygonDraw",
|
|
18443
18499
|
"occupancy",
|
|
18444
18500
|
"audio",
|
|
@@ -18637,6 +18693,21 @@ var NC_CONDITION_CATALOG = [
|
|
|
18637
18693
|
phase: "P1",
|
|
18638
18694
|
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."
|
|
18639
18695
|
},
|
|
18696
|
+
{
|
|
18697
|
+
id: "devicesExclude",
|
|
18698
|
+
group: "scope",
|
|
18699
|
+
label: "Excluded devices",
|
|
18700
|
+
valueType: "deviceIdExcludeList",
|
|
18701
|
+
operator: "notIn",
|
|
18702
|
+
appliesTo: [
|
|
18703
|
+
"immediate",
|
|
18704
|
+
"track-end",
|
|
18705
|
+
"device-event",
|
|
18706
|
+
"package-event"
|
|
18707
|
+
],
|
|
18708
|
+
phase: "P1",
|
|
18709
|
+
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."
|
|
18710
|
+
},
|
|
18640
18711
|
{
|
|
18641
18712
|
id: "classes",
|
|
18642
18713
|
group: "class",
|
|
@@ -18893,6 +18964,33 @@ var NC_CONDITION_CATALOG = [
|
|
|
18893
18964
|
phase: "P1",
|
|
18894
18965
|
description: "Raw device event-type tokens (e.g. doorbell press / press_long) from the event-emitter slice; absent on doorbell-pulse / passive sensors."
|
|
18895
18966
|
},
|
|
18967
|
+
{
|
|
18968
|
+
id: "sensorTransition",
|
|
18969
|
+
group: "device",
|
|
18970
|
+
label: "Notify when",
|
|
18971
|
+
valueType: "sensorTransition",
|
|
18972
|
+
options: [
|
|
18973
|
+
{
|
|
18974
|
+
value: "",
|
|
18975
|
+
label: "It triggers and when it clears",
|
|
18976
|
+
hint: "Every change: water detected, and back to dry."
|
|
18977
|
+
},
|
|
18978
|
+
{
|
|
18979
|
+
value: "raised",
|
|
18980
|
+
label: "Only when it triggers",
|
|
18981
|
+
hint: "Water detected, smoke, a contact opening — never the return to normal."
|
|
18982
|
+
},
|
|
18983
|
+
{
|
|
18984
|
+
value: "cleared",
|
|
18985
|
+
label: "Only when it clears",
|
|
18986
|
+
hint: "Back to dry, smoke gone, a contact closing — never the alert itself."
|
|
18987
|
+
}
|
|
18988
|
+
],
|
|
18989
|
+
operator: "in",
|
|
18990
|
+
appliesTo: ["device-event"],
|
|
18991
|
+
phase: "P2",
|
|
18992
|
+
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."
|
|
18993
|
+
},
|
|
18896
18994
|
{
|
|
18897
18995
|
id: "packagePhase",
|
|
18898
18996
|
group: "package",
|
|
@@ -19079,6 +19177,39 @@ var NcHistoryFilterSchema = zod.z.object({
|
|
|
19079
19177
|
limit: zod.z.number().int().min(1).max(500).default(100)
|
|
19080
19178
|
});
|
|
19081
19179
|
/**
|
|
19180
|
+
* The newest delivery row of ONE rule — the "Last run" of a rules table.
|
|
19181
|
+
*
|
|
19182
|
+
* A projection of the same outbox rows `getHistory` returns, so it records
|
|
19183
|
+
* DELIVERIES only: a throttled or unmatched evaluation never produced a row
|
|
19184
|
+
* and is not a run here. When one fire reached several targets (several rows
|
|
19185
|
+
* at the same `lastAt`), `status` is the least successful of them
|
|
19186
|
+
* (`dead` > `pending` > `sent`): "the last run delivered" must be true for
|
|
19187
|
+
* every target it names.
|
|
19188
|
+
*/
|
|
19189
|
+
var NcRuleLastRunSchema = zod.z.object({
|
|
19190
|
+
ruleId: zod.z.string(),
|
|
19191
|
+
/** Fire time of the newest row (`createdAt`, epoch ms). */
|
|
19192
|
+
lastAt: zod.z.number(),
|
|
19193
|
+
status: NcHistoryStatusSchema,
|
|
19194
|
+
/** The camera/device of that row (a digest row files under its first camera). */
|
|
19195
|
+
deviceId: zod.z.number()
|
|
19196
|
+
});
|
|
19197
|
+
/**
|
|
19198
|
+
* Every rule's last run, in one answer.
|
|
19199
|
+
*
|
|
19200
|
+
* A rule ABSENT from `runs` produced no delivery inside `horizonMs` — how far
|
|
19201
|
+
* back this answer looked, in ms before the hub's now. It is the outbox prune
|
|
19202
|
+
* window (7 days by default, operator-configurable), NARROWED when the read hit
|
|
19203
|
+
* its row bound: the answer never claims a window it did not read. `null` means
|
|
19204
|
+
* the operator keeps the outbox forever AND the read reached its end, so absent
|
|
19205
|
+
* means "never on record". A UI derives its "not in the last N days" from this
|
|
19206
|
+
* value, never from a constant — and only when the call ANSWERED (D315).
|
|
19207
|
+
*/
|
|
19208
|
+
var NcRuleLastRunsSchema = zod.z.object({
|
|
19209
|
+
runs: zod.z.array(NcRuleLastRunSchema),
|
|
19210
|
+
horizonMs: zod.z.number().nonnegative().nullable()
|
|
19211
|
+
});
|
|
19212
|
+
/**
|
|
19082
19213
|
* What a snooze covers. Broader scopes win when several overlap, so one window
|
|
19083
19214
|
* leaves ONE digest rather than a rule snooze and a whole-feed snooze both
|
|
19084
19215
|
* summarising the same silence.
|
|
@@ -19265,6 +19396,14 @@ var NcAlarmModeCoverageSchema = zod.z.object({
|
|
|
19265
19396
|
/** Ids named by the covering rules. A SUBSET when `allDevices` is true. */
|
|
19266
19397
|
deviceIds: zod.z.array(zod.z.number().int()),
|
|
19267
19398
|
/**
|
|
19399
|
+
* D641: the ids NOT covered although `allDevices` is true — every unscoped
|
|
19400
|
+
* covering rule EXCLUDES them (`conditions.devicesExclude`) and no named rule
|
|
19401
|
+
* covers them. Always `[]` when `allDevices` is false. Excluded by the rules,
|
|
19402
|
+
* which is not the same as skipped by a switch: never in `skippedDevices`.
|
|
19403
|
+
* Defaulted so an answer computed before this field parses as "none".
|
|
19404
|
+
*/
|
|
19405
|
+
allDevicesExcept: zod.z.array(zod.z.number().int()).default([]),
|
|
19406
|
+
/**
|
|
19268
19407
|
* Devices this mode NAMES but cannot actually arm, each with the switch that
|
|
19269
19408
|
* excludes it.
|
|
19270
19409
|
*
|
|
@@ -19506,6 +19645,15 @@ var notificationRulesCapability = {
|
|
|
19506
19645
|
*/
|
|
19507
19646
|
getHistory: require_sleep.method(zod.z.object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), zod.z.object({ entries: zod.z.array(NcHistoryEntrySchema) }), { auth: "admin" }),
|
|
19508
19647
|
/**
|
|
19648
|
+
* The newest delivery of every rule, in ONE bounded read of the outbox —
|
|
19649
|
+
* the "Last run" column. Never a `getHistory` per rule. A rule with no
|
|
19650
|
+
* delivery inside `horizonMs` is absent from `runs`; see
|
|
19651
|
+
* {@link NcRuleLastRunsSchema} for what absent means. A store that cannot
|
|
19652
|
+
* answer FAILS the call rather than answering "nothing ran". Admin-only,
|
|
19653
|
+
* like `getHistory`, of which it is a projection.
|
|
19654
|
+
*/
|
|
19655
|
+
getRuleLastRuns: require_sleep.method(zod.z.object({}), NcRuleLastRunsSchema, { auth: "admin" }),
|
|
19656
|
+
/**
|
|
19509
19657
|
* Mint a fresh, externally-reachable URL for one artefact a history row
|
|
19510
19658
|
* named in {@link NcHistoryEntrySchema.shape.artifactIds} — the SAME
|
|
19511
19659
|
* signed-link mechanism the dispatcher uses to attach media to an
|
|
@@ -35747,6 +35895,35 @@ var RenameNodeResultSchema = zod.z.object({
|
|
|
35747
35895
|
name: zod.z.string()
|
|
35748
35896
|
});
|
|
35749
35897
|
/**
|
|
35898
|
+
* One row of the CHEAP node list (D637): what a node picker needs and nothing
|
|
35899
|
+
* else. Read from the hub's in-memory registry plus the durable node history.
|
|
35900
|
+
* No per-node RPC, unlike `topology`, which walks the whole cluster (32–51 s).
|
|
35901
|
+
*/
|
|
35902
|
+
var NodeDirectoryEntrySchema = zod.z.object({
|
|
35903
|
+
id: zod.z.string(),
|
|
35904
|
+
name: zod.z.string(),
|
|
35905
|
+
isHub: zod.z.boolean(),
|
|
35906
|
+
isOnline: zod.z.boolean()
|
|
35907
|
+
});
|
|
35908
|
+
/**
|
|
35909
|
+
* The cheap node list. A consumer's rule for a STORED node id (a rule's
|
|
35910
|
+
* `nodeIds`) that is missing from `nodes`, whatever `complete` says: render it
|
|
35911
|
+
* as a removable chip labelled unknown, never drop it (D49). Even a complete
|
|
35912
|
+
* list omits a node that joined and left between two history captures, so a
|
|
35913
|
+
* missing id means "not known to the hub", never "removed". Only the operator
|
|
35914
|
+
* removes it.
|
|
35915
|
+
*
|
|
35916
|
+
* `complete` changes only the WORDING: `false` = no history read has ever
|
|
35917
|
+
* answered, so the list may be missing offline nodes the hub does know (D315).
|
|
35918
|
+
*
|
|
35919
|
+
* `name` is the history row's name (≤ 30 s behind a rename), or the id when
|
|
35920
|
+
* the history has none.
|
|
35921
|
+
*/
|
|
35922
|
+
var NodeDirectorySchema = zod.z.object({
|
|
35923
|
+
nodes: zod.z.array(NodeDirectoryEntrySchema).readonly(),
|
|
35924
|
+
complete: zod.z.boolean()
|
|
35925
|
+
});
|
|
35926
|
+
/**
|
|
35750
35927
|
* `nodes` is a **hub-centric** cluster-management cap: the hub hosts
|
|
35751
35928
|
* the single provider and every per-node method (`getNodeAddons`,
|
|
35752
35929
|
* `restartProcess`, `restartNode`, `undeployAddon`, …) takes `nodeId`
|
|
@@ -35765,6 +35942,12 @@ var nodesCapability = {
|
|
|
35765
35942
|
nodeIdMode: "data",
|
|
35766
35943
|
methods: {
|
|
35767
35944
|
topology: require_sleep.method(zod.z.void(), zod.z.array(TopologyNodeSchema).readonly(), { auth: "admin" }),
|
|
35945
|
+
/**
|
|
35946
|
+
* The cheap node list for pickers (D637): the hub's in-memory registry plus
|
|
35947
|
+
* the durable node history, no per-node RPC. `complete: false` when the
|
|
35948
|
+
* history could not be read.
|
|
35949
|
+
*/
|
|
35950
|
+
directory: require_sleep.method(zod.z.void(), NodeDirectorySchema, { auth: "admin" }),
|
|
35768
35951
|
deployAddon: require_sleep.method(NodeAddonInputSchema, SuccessSchema, {
|
|
35769
35952
|
kind: "mutation",
|
|
35770
35953
|
auth: "admin"
|
|
@@ -52634,6 +52817,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
52634
52817
|
addonId: null,
|
|
52635
52818
|
access: "create"
|
|
52636
52819
|
},
|
|
52820
|
+
"nodes.directory": {
|
|
52821
|
+
capName: "nodes",
|
|
52822
|
+
capScope: "system",
|
|
52823
|
+
addonId: null,
|
|
52824
|
+
access: "view"
|
|
52825
|
+
},
|
|
52637
52826
|
"nodes.executeQuery": {
|
|
52638
52827
|
capName: "nodes",
|
|
52639
52828
|
capScope: "system",
|
|
@@ -52802,6 +52991,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
52802
52991
|
addonId: null,
|
|
52803
52992
|
access: "view"
|
|
52804
52993
|
},
|
|
52994
|
+
"notificationRules.getRuleLastRuns": {
|
|
52995
|
+
capName: "notification-rules",
|
|
52996
|
+
capScope: "system",
|
|
52997
|
+
addonId: null,
|
|
52998
|
+
access: "view"
|
|
52999
|
+
},
|
|
52805
53000
|
"notificationRules.getTemplateCatalog": {
|
|
52806
53001
|
capName: "notification-rules",
|
|
52807
53002
|
capScope: "system",
|
|
@@ -59616,6 +59811,7 @@ function createSystemProxy(api) {
|
|
|
59616
59811
|
networkQuality: { getAllStats: (input) => dispatch("networkQuality", "getAllStats", "query", input) },
|
|
59617
59812
|
nodes: {
|
|
59618
59813
|
topology: (input) => dispatch("nodes", "topology", "query", input),
|
|
59814
|
+
directory: (input) => dispatch("nodes", "directory", "query", input),
|
|
59619
59815
|
deployAddon: (input) => dispatch("nodes", "deployAddon", "mutation", input),
|
|
59620
59816
|
undeployAddon: (input) => dispatch("nodes", "undeployAddon", "mutation", input),
|
|
59621
59817
|
restartAddon: (input) => dispatch("nodes", "restartAddon", "mutation", input),
|
|
@@ -60668,7 +60864,285 @@ function prepareNotification(caps, n) {
|
|
|
60668
60864
|
};
|
|
60669
60865
|
}
|
|
60670
60866
|
//#endregion
|
|
60867
|
+
//#region src/notification/system-event-filters.ts
|
|
60868
|
+
/** Every filter, for the callers that must cover all four (guards, tests). */
|
|
60869
|
+
var NC_SYSTEM_EVENT_FILTER_KEYS = [
|
|
60870
|
+
"deviceIds",
|
|
60871
|
+
"deviceTypes",
|
|
60872
|
+
"nodeIds",
|
|
60873
|
+
"packageNames"
|
|
60874
|
+
];
|
|
60875
|
+
/**
|
|
60876
|
+
* Does `filter` say anything about `kind`?
|
|
60877
|
+
*
|
|
60878
|
+
* `false` means the filter is not part of this kind's vocabulary: the engine
|
|
60879
|
+
* ignores it and an editor hides its input. It never means "excluded".
|
|
60880
|
+
*/
|
|
60881
|
+
function systemEventFilterApplies(kind, filter) {
|
|
60882
|
+
switch (filter) {
|
|
60883
|
+
case "deviceIds": return kind.startsWith("device-") || kind.startsWith("stream-") || kind === "detection-blind" || kind === "alarm-triggered";
|
|
60884
|
+
case "deviceTypes": return kind.startsWith("device-") || kind === "detection-blind";
|
|
60885
|
+
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";
|
|
60886
|
+
case "packageNames": return kind.endsWith("update-available") || kind === "addon-updated" || kind === "server-updated";
|
|
60887
|
+
}
|
|
60888
|
+
}
|
|
60889
|
+
/**
|
|
60890
|
+
* Does `filter` say anything about AT LEAST ONE of the selected kinds?
|
|
60891
|
+
*
|
|
60892
|
+
* The editor's question: a rule selects several kinds at once and renders one
|
|
60893
|
+
* filter input for the set, so a filter is shown when any selected kind can be
|
|
60894
|
+
* narrowed by it. The kinds it cannot narrow are then simply not narrowed —
|
|
60895
|
+
* which is the engine's half of the same rule.
|
|
60896
|
+
*/
|
|
60897
|
+
function systemEventFilterAppliesToAnyKind(kinds, filter) {
|
|
60898
|
+
return kinds.some((kind) => systemEventFilterApplies(kind, filter));
|
|
60899
|
+
}
|
|
60900
|
+
//#endregion
|
|
60901
|
+
//#region src/notification/system-event-families.ts
|
|
60902
|
+
/**
|
|
60903
|
+
* WHICH FAMILY every system-event kind belongs to, and which narrowing filters
|
|
60904
|
+
* each family may carry: one table, read by the hub validator, by `ruleKindOf`
|
|
60905
|
+
* and by both rule editors (D637).
|
|
60906
|
+
*
|
|
60907
|
+
* A system rule used to be one editor for thirty-one kinds and five filters.
|
|
60908
|
+
* "Eventi di sistema" carried battery kinds under a liveness `deviceTypes` filter
|
|
60909
|
+
* and went silent for two weeks (D636). The three families are three questions:
|
|
60910
|
+
* about devices, about the installation, and about the alarm panel. A rule
|
|
60911
|
+
* answers one of them. The engine never needed to know, and it still does not:
|
|
60912
|
+
* a mixed stored rule keeps firing. Only AUTHORING is strict.
|
|
60913
|
+
*
|
|
60914
|
+
* The legacy `camera-*` tail has no family (`null`). It is parsed, never produced,
|
|
60915
|
+
* never offered.
|
|
60916
|
+
*/
|
|
60917
|
+
var NC_SYSTEM_EVENT_FAMILIES = [
|
|
60918
|
+
"device-events",
|
|
60919
|
+
"system",
|
|
60920
|
+
"alarm"
|
|
60921
|
+
];
|
|
60922
|
+
function isSystemEventFamily(value) {
|
|
60923
|
+
return NC_SYSTEM_EVENT_FAMILIES.some((family) => family === value);
|
|
60924
|
+
}
|
|
60925
|
+
/** Total over the enum: a kind added to the cap without a family fails tsc here. */
|
|
60926
|
+
var NC_SYSTEM_EVENT_FAMILY = {
|
|
60927
|
+
"device-online": "device-events",
|
|
60928
|
+
"device-offline": "device-events",
|
|
60929
|
+
"device-disabled": "device-events",
|
|
60930
|
+
"device-enabled": "device-events",
|
|
60931
|
+
"device-battery-low": "device-events",
|
|
60932
|
+
"device-battery-normal": "device-events",
|
|
60933
|
+
"device-consumable-low": "device-events",
|
|
60934
|
+
"device-consumable-normal": "device-events",
|
|
60935
|
+
"stream-online": "device-events",
|
|
60936
|
+
"stream-offline": "device-events",
|
|
60937
|
+
"detection-blind": "device-events",
|
|
60938
|
+
"node-online": "system",
|
|
60939
|
+
"node-offline": "system",
|
|
60940
|
+
"node-inference-unavailable": "system",
|
|
60941
|
+
"addon-crash-loop": "system",
|
|
60942
|
+
"addon-update-available": "system",
|
|
60943
|
+
"addon-updated": "system",
|
|
60944
|
+
"server-update-available": "system",
|
|
60945
|
+
"server-updated": "system",
|
|
60946
|
+
"wrapper-update-available": "system",
|
|
60947
|
+
"backup-completed": "system",
|
|
60948
|
+
"export-completed": "system",
|
|
60949
|
+
"alarm-triggered": "alarm",
|
|
60950
|
+
"alarm-armed": "alarm",
|
|
60951
|
+
"alarm-disarmed": "alarm",
|
|
60952
|
+
"alarm-arming": "alarm",
|
|
60953
|
+
"alarm-arm-refused": "alarm",
|
|
60954
|
+
"alarm-pending": "alarm",
|
|
60955
|
+
"alarm-rearmed": "alarm",
|
|
60956
|
+
"alarm-sensor-bypass": "alarm",
|
|
60957
|
+
"alarm-check-failed": "alarm",
|
|
60958
|
+
"camera-online": null,
|
|
60959
|
+
"camera-offline": null,
|
|
60960
|
+
"camera-disabled": null,
|
|
60961
|
+
"camera-enabled": null
|
|
60962
|
+
};
|
|
60963
|
+
/** Read by NAME, for kinds that arrive as plain strings (a newer hub, the viewer's mirror). */
|
|
60964
|
+
var FAMILY_BY_NAME = new Map(Object.entries(NC_SYSTEM_EVENT_FAMILY));
|
|
60965
|
+
var NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS = [...NC_SYSTEM_EVENT_FILTER_KEYS, "excludeDeviceIds"];
|
|
60966
|
+
/**
|
|
60967
|
+
* The filters a family may carry. The four base filters are the union of
|
|
60968
|
+
* `systemEventFilterApplies` over the family's kinds (the spec pins that
|
|
60969
|
+
* equality). `excludeDeviceIds` is a device-events filter only: an alarm is
|
|
60970
|
+
* narrowed to the camera that triggered it and excludes nothing.
|
|
60971
|
+
*/
|
|
60972
|
+
var NC_SYSTEM_EVENT_FAMILY_FILTERS = {
|
|
60973
|
+
"device-events": [
|
|
60974
|
+
"deviceIds",
|
|
60975
|
+
"excludeDeviceIds",
|
|
60976
|
+
"deviceTypes"
|
|
60977
|
+
],
|
|
60978
|
+
system: ["nodeIds", "packageNames"],
|
|
60979
|
+
alarm: ["deviceIds"]
|
|
60980
|
+
};
|
|
60981
|
+
var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
60982
|
+
{
|
|
60983
|
+
id: "device-state",
|
|
60984
|
+
family: "device-events",
|
|
60985
|
+
label: "Device state",
|
|
60986
|
+
kinds: [
|
|
60987
|
+
"device-offline",
|
|
60988
|
+
"device-online",
|
|
60989
|
+
"device-disabled",
|
|
60990
|
+
"device-enabled"
|
|
60991
|
+
]
|
|
60992
|
+
},
|
|
60993
|
+
{
|
|
60994
|
+
id: "streams",
|
|
60995
|
+
family: "device-events",
|
|
60996
|
+
label: "Streams",
|
|
60997
|
+
kinds: ["stream-offline", "stream-online"]
|
|
60998
|
+
},
|
|
60999
|
+
{
|
|
61000
|
+
id: "battery",
|
|
61001
|
+
family: "device-events",
|
|
61002
|
+
label: "Battery",
|
|
61003
|
+
kinds: ["device-battery-low", "device-battery-normal"]
|
|
61004
|
+
},
|
|
61005
|
+
{
|
|
61006
|
+
id: "consumables",
|
|
61007
|
+
family: "device-events",
|
|
61008
|
+
label: "Consumables",
|
|
61009
|
+
kinds: ["device-consumable-low", "device-consumable-normal"]
|
|
61010
|
+
},
|
|
61011
|
+
{
|
|
61012
|
+
id: "detection-blind",
|
|
61013
|
+
family: "device-events",
|
|
61014
|
+
label: "Detecting nothing",
|
|
61015
|
+
kinds: ["detection-blind"]
|
|
61016
|
+
},
|
|
61017
|
+
{
|
|
61018
|
+
id: "nodes",
|
|
61019
|
+
family: "system",
|
|
61020
|
+
label: "Nodes",
|
|
61021
|
+
kinds: [
|
|
61022
|
+
"node-offline",
|
|
61023
|
+
"node-online",
|
|
61024
|
+
"node-inference-unavailable"
|
|
61025
|
+
]
|
|
61026
|
+
},
|
|
61027
|
+
{
|
|
61028
|
+
id: "addons",
|
|
61029
|
+
family: "system",
|
|
61030
|
+
label: "Addons",
|
|
61031
|
+
kinds: [
|
|
61032
|
+
"addon-crash-loop",
|
|
61033
|
+
"addon-update-available",
|
|
61034
|
+
"addon-updated"
|
|
61035
|
+
]
|
|
61036
|
+
},
|
|
61037
|
+
{
|
|
61038
|
+
id: "updates",
|
|
61039
|
+
family: "system",
|
|
61040
|
+
label: "Server & container updates",
|
|
61041
|
+
kinds: [
|
|
61042
|
+
"server-update-available",
|
|
61043
|
+
"server-updated",
|
|
61044
|
+
"wrapper-update-available"
|
|
61045
|
+
]
|
|
61046
|
+
},
|
|
61047
|
+
{
|
|
61048
|
+
id: "backups-exports",
|
|
61049
|
+
family: "system",
|
|
61050
|
+
label: "Backups & exports",
|
|
61051
|
+
kinds: ["backup-completed", "export-completed"]
|
|
61052
|
+
},
|
|
61053
|
+
{
|
|
61054
|
+
id: "alarm",
|
|
61055
|
+
family: "alarm",
|
|
61056
|
+
label: "Alarm",
|
|
61057
|
+
kinds: NC_ALARM_SYSTEM_EVENT_KINDS
|
|
61058
|
+
}
|
|
61059
|
+
];
|
|
61060
|
+
function systemEventKindsOfFamily(family) {
|
|
61061
|
+
return NC_SYSTEM_EVENT_KIND_GROUP_SPECS.filter((g) => g.family === family).flatMap((g) => g.kinds);
|
|
61062
|
+
}
|
|
61063
|
+
/** The kind names on an UNTYPED condition, or `undefined` when it has none. */
|
|
61064
|
+
function systemEventKindNamesOf(condition) {
|
|
61065
|
+
if (typeof condition !== "object" || condition === null || !("kinds" in condition)) return void 0;
|
|
61066
|
+
const kinds = condition.kinds;
|
|
61067
|
+
if (!Array.isArray(kinds)) return void 0;
|
|
61068
|
+
return kinds.filter((kind) => typeof kind === "string");
|
|
61069
|
+
}
|
|
61070
|
+
/**
|
|
61071
|
+
* One family, or `mixed`. Mixed covers kinds that span families, a legacy kind,
|
|
61072
|
+
* a kind this build does not know (it fails toward read-only and never toward
|
|
61073
|
+
* editable), and an empty selection (nothing to decide on).
|
|
61074
|
+
*/
|
|
61075
|
+
function systemEventFamilyOf(kindNames) {
|
|
61076
|
+
const families = /* @__PURE__ */ new Set();
|
|
61077
|
+
for (const name of kindNames) {
|
|
61078
|
+
const family = FAMILY_BY_NAME.get(name);
|
|
61079
|
+
if (family === void 0 || family === null) return { kind: "mixed" };
|
|
61080
|
+
families.add(family);
|
|
61081
|
+
}
|
|
61082
|
+
const [only] = [...families];
|
|
61083
|
+
return families.size === 1 && only !== void 0 ? {
|
|
61084
|
+
kind: "family",
|
|
61085
|
+
family: only
|
|
61086
|
+
} : { kind: "mixed" };
|
|
61087
|
+
}
|
|
61088
|
+
/**
|
|
61089
|
+
* Why the hub refuses this condition on a new or updated rule. Empty = accepted.
|
|
61090
|
+
* Families are reported in `NC_SYSTEM_EVENT_FAMILIES` order, and filters in
|
|
61091
|
+
* `NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS` order, so a refusal reads the same
|
|
61092
|
+
* every time.
|
|
61093
|
+
*/
|
|
61094
|
+
function systemEventFamilyProblems(condition) {
|
|
61095
|
+
if (condition === void 0 || condition.kinds.length === 0) return [{ code: "no-kinds" }];
|
|
61096
|
+
const problems = [];
|
|
61097
|
+
const present = /* @__PURE__ */ new Set();
|
|
61098
|
+
for (const kind of condition.kinds) {
|
|
61099
|
+
const family = NC_SYSTEM_EVENT_FAMILY[kind];
|
|
61100
|
+
if (family === null) problems.push({
|
|
61101
|
+
code: "legacy-kind",
|
|
61102
|
+
kind
|
|
61103
|
+
});
|
|
61104
|
+
else present.add(family);
|
|
61105
|
+
}
|
|
61106
|
+
const families = NC_SYSTEM_EVENT_FAMILIES.filter((f) => present.has(f));
|
|
61107
|
+
if (families.length > 1) problems.push({
|
|
61108
|
+
code: "mixed-families",
|
|
61109
|
+
families
|
|
61110
|
+
});
|
|
61111
|
+
const [family] = families;
|
|
61112
|
+
if (families.length !== 1 || family === void 0) return problems;
|
|
61113
|
+
const allowed = NC_SYSTEM_EVENT_FAMILY_FILTERS[family];
|
|
61114
|
+
for (const filter of NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS) if (condition[filter] !== void 0 && !allowed.includes(filter)) problems.push({
|
|
61115
|
+
code: "filter-outside-family",
|
|
61116
|
+
filter,
|
|
61117
|
+
family
|
|
61118
|
+
});
|
|
61119
|
+
return problems;
|
|
61120
|
+
}
|
|
61121
|
+
function describeSystemEventFamilyProblem(problem) {
|
|
61122
|
+
switch (problem.code) {
|
|
61123
|
+
case "no-kinds": return "a system-event rule needs at least one event kind";
|
|
61124
|
+
case "legacy-kind": return `'${problem.kind}' is a legacy kind and cannot be authored`;
|
|
61125
|
+
case "mixed-families": return `event kinds span ${problem.families.join(" + ")} — one rule per family`;
|
|
61126
|
+
case "filter-outside-family": return `filter '${problem.filter}' is not allowed on a ${problem.family} rule`;
|
|
61127
|
+
}
|
|
61128
|
+
}
|
|
61129
|
+
//#endregion
|
|
60671
61130
|
//#region src/notification/rule-kinds.ts
|
|
61131
|
+
/** Every kind a `system-event` rule can derive — the three families and `mixed`. */
|
|
61132
|
+
var NC_SYSTEM_RULE_KINDS = [
|
|
61133
|
+
"device-events",
|
|
61134
|
+
"system",
|
|
61135
|
+
"alarm",
|
|
61136
|
+
"mixed"
|
|
61137
|
+
];
|
|
61138
|
+
/** Is this a kind a `system-event` rule derives (any family, or `mixed`)? */
|
|
61139
|
+
function isSystemRuleKind(kind) {
|
|
61140
|
+
return NC_SYSTEM_RULE_KINDS.some((k) => k === kind);
|
|
61141
|
+
}
|
|
61142
|
+
/** The family a kind authors, or undefined (a camera kind, or `mixed`). */
|
|
61143
|
+
function systemFamilyOfKind(kind) {
|
|
61144
|
+
return isSystemEventFamily(kind) ? kind : void 0;
|
|
61145
|
+
}
|
|
60672
61146
|
/**
|
|
60673
61147
|
* Reasons, written once. Each names the SUBJECT FIELD the engine reads and
|
|
60674
61148
|
* finds absent — that is what makes the exclusion checkable against the engine
|
|
@@ -60676,6 +61150,7 @@ function prepareNotification(caps, n) {
|
|
|
60676
61150
|
*/
|
|
60677
61151
|
var NO_SENSOR_KIND = "An occupancy edge is not a sensor event: it carries no sensor kind, so this condition can never match one.";
|
|
60678
61152
|
var NO_EVENT_TOKEN = "An occupancy edge carries no device event-type token — that comes from an event-emitter slice, which a count crossing has none of.";
|
|
61153
|
+
var NO_SENSOR_EDGE = "An occupancy edge is a count crossing, not a sensor reading: it has no raise or clear, so this choice could never narrow it.";
|
|
60679
61154
|
var OCCUPANCY_SOURCE = "An occupancy edge is always produced by the pipeline, so any other source can never match and “pipeline” narrows nothing.";
|
|
60680
61155
|
var AUDIO_SOURCE = "A confirmed sound window is always stamped as an audio subject, so any other source can never match.";
|
|
60681
61156
|
var SOUND_NOT_A_PICTURE = "A sound rule fires on what the camera HEARD. Its subject carries no detection, so this condition can never match one — name the sounds in the Sound condition instead.";
|
|
@@ -60686,6 +61161,7 @@ var NC_RULE_KIND_SPECS = [
|
|
|
60686
61161
|
kind: "detection",
|
|
60687
61162
|
label: "Conditions",
|
|
60688
61163
|
excluded: {},
|
|
61164
|
+
editable: true,
|
|
60689
61165
|
carriesMedia: true,
|
|
60690
61166
|
carriesSubjectCrop: true
|
|
60691
61167
|
},
|
|
@@ -60694,6 +61170,7 @@ var NC_RULE_KIND_SPECS = [
|
|
|
60694
61170
|
label: "Conditions",
|
|
60695
61171
|
/** Same argument as `detection`: `occupancy` converts, it does not confuse. */
|
|
60696
61172
|
excluded: {},
|
|
61173
|
+
editable: true,
|
|
60697
61174
|
carriesMedia: true,
|
|
60698
61175
|
carriesSubjectCrop: true,
|
|
60699
61176
|
blurb: "A doorbell press or a linked sensor changing state. The picture comes from the camera the sensor is attributed to."
|
|
@@ -60705,8 +61182,10 @@ var NC_RULE_KIND_SPECS = [
|
|
|
60705
61182
|
excluded: {
|
|
60706
61183
|
sensorKinds: NO_SENSOR_KIND,
|
|
60707
61184
|
eventTypeTokens: NO_EVENT_TOKEN,
|
|
61185
|
+
sensorTransition: NO_SENSOR_EDGE,
|
|
60708
61186
|
source: OCCUPANCY_SOURCE
|
|
60709
61187
|
},
|
|
61188
|
+
editable: true,
|
|
60710
61189
|
carriesMedia: true,
|
|
60711
61190
|
carriesSubjectCrop: true,
|
|
60712
61191
|
blurb: "Fires when the count in a camera frame or a zone crosses your threshold and holds. Pick the camera first — the zone list is that camera’s."
|
|
@@ -60729,25 +61208,66 @@ var NC_RULE_KIND_SPECS = [
|
|
|
60729
61208
|
plates: SOUND_NOT_A_PICTURE,
|
|
60730
61209
|
source: AUDIO_SOURCE
|
|
60731
61210
|
},
|
|
61211
|
+
editable: true,
|
|
60732
61212
|
carriesMedia: true,
|
|
60733
61213
|
carriesSubjectCrop: false,
|
|
60734
61214
|
blurb: "Fires on a confirmed sampling window of audio, never on a picture. Name the sounds and/or keep a level threshold — with neither it can never match.",
|
|
60735
61215
|
mediaBlurb: "A sound owns no frame, so the picture is a photograph of the camera taken at the moment of the match — the whole scene, never a crop. The GIF and the clip are cut around the same instant, from the camera."
|
|
60736
61216
|
},
|
|
61217
|
+
{
|
|
61218
|
+
kind: "device-events",
|
|
61219
|
+
label: "Device events",
|
|
61220
|
+
discriminator: "systemEvent",
|
|
61221
|
+
excluded: {},
|
|
61222
|
+
editable: true,
|
|
61223
|
+
carriesMedia: false,
|
|
61224
|
+
carriesSubjectCrop: false,
|
|
61225
|
+
blurb: "A device or its stream going away or coming back, switched off or on, a battery or consumable running low, a camera detecting nothing. There is no frame to attach."
|
|
61226
|
+
},
|
|
60737
61227
|
{
|
|
60738
61228
|
kind: "system",
|
|
60739
|
-
label: "
|
|
61229
|
+
label: "System events",
|
|
60740
61230
|
discriminator: "systemEvent",
|
|
60741
61231
|
excluded: {},
|
|
61232
|
+
editable: true,
|
|
60742
61233
|
carriesMedia: false,
|
|
60743
61234
|
carriesSubjectCrop: false,
|
|
60744
|
-
blurb: "The installation itself: a
|
|
61235
|
+
blurb: "The installation itself: a node leaving, an addon crash-looping, an update available or installed, a backup or an export finishing."
|
|
61236
|
+
},
|
|
61237
|
+
{
|
|
61238
|
+
kind: "alarm",
|
|
61239
|
+
label: "Alarm",
|
|
61240
|
+
discriminator: "systemEvent",
|
|
61241
|
+
excluded: {},
|
|
61242
|
+
editable: true,
|
|
61243
|
+
carriesMedia: false,
|
|
61244
|
+
carriesSubjectCrop: false,
|
|
61245
|
+
blurb: "The alarm panel: refused, arming, armed, entry delay, triggered, re-armed, sensor bypass, disarmed.",
|
|
61246
|
+
mediaBlurb: "An alarm set off by a rule arrives with THAT rule's pictures, combined into one notification. This rule adds none of its own."
|
|
61247
|
+
},
|
|
61248
|
+
{
|
|
61249
|
+
kind: "mixed",
|
|
61250
|
+
label: "To recreate",
|
|
61251
|
+
discriminator: "systemEvent",
|
|
61252
|
+
excluded: {},
|
|
61253
|
+
editable: false,
|
|
61254
|
+
carriesMedia: false,
|
|
61255
|
+
carriesSubjectCrop: false,
|
|
61256
|
+
blurb: "This rule mixes events from more than one family (device events, system, alarm). It keeps firing as it is, but it can no longer be edited: create one rule per family, then delete this one."
|
|
60745
61257
|
}
|
|
60746
61258
|
];
|
|
60747
61259
|
/** The spec for a kind. Total by construction — every member has an entry. */
|
|
60748
61260
|
function ruleKindSpec(kind) {
|
|
60749
61261
|
return NC_RULE_KIND_SPECS.find((s) => s.kind === kind) ?? NC_RULE_KIND_SPECS[0];
|
|
60750
61262
|
}
|
|
61263
|
+
/**
|
|
61264
|
+
* Every kind a discriminator makes — one kind for `audio` and `occupancy`, the
|
|
61265
|
+
* whole system group for `systemEvent`. Empty for a condition that makes no
|
|
61266
|
+
* kind. See {@link NcRuleKindSpec.discriminator}.
|
|
61267
|
+
*/
|
|
61268
|
+
function kindsForDiscriminator(discriminator) {
|
|
61269
|
+
return NC_RULE_KIND_SPECS.filter((s) => s.discriminator === discriminator).map((s) => s.kind);
|
|
61270
|
+
}
|
|
60751
61271
|
/** The delivery a system rule rides — named once, compared everywhere. */
|
|
60752
61272
|
var NC_SYSTEM_DELIVERY = "system-event";
|
|
60753
61273
|
/**
|
|
@@ -60765,16 +61285,28 @@ function isSystemDelivery(delivery) {
|
|
|
60765
61285
|
* the order below is the engine's own: `evaluateRule` checks the system branch
|
|
60766
61286
|
* first, then the occupancy and audio gates. Takes a plain `delivery` string so
|
|
60767
61287
|
* a trigger this build does not know still classifies (as `detection`, which is
|
|
60768
|
-
* the read-only path's own fallback).
|
|
61288
|
+
* the read-only path's own fallback). A system rule classifies by the FAMILY of
|
|
61289
|
+
* its event kinds (D637) — see {@link systemRuleKindOf}.
|
|
60769
61290
|
*/
|
|
60770
61291
|
function ruleKindOf(rule) {
|
|
60771
|
-
if (isSystemDelivery(rule.delivery)) return
|
|
61292
|
+
if (isSystemDelivery(rule.delivery)) return systemRuleKindOf(rule.conditions.systemEvent);
|
|
60772
61293
|
if (rule.conditions.occupancy !== void 0 && rule.delivery === "device-event") return "occupancy";
|
|
60773
61294
|
if (rule.conditions.audio !== void 0 && rule.delivery === "immediate") return "sound";
|
|
60774
61295
|
if (rule.delivery === "device-event") return "sensor";
|
|
60775
61296
|
return "detection";
|
|
60776
61297
|
}
|
|
60777
61298
|
/**
|
|
61299
|
+
* A system rule's kind: its one family, or `mixed` (D637).
|
|
61300
|
+
*
|
|
61301
|
+
* Takes the UNTYPED condition for the same reason {@link NcRuleConditionsSubject}
|
|
61302
|
+
* is structural. `mixed` covers kinds across families, a legacy or unknown kind,
|
|
61303
|
+
* and no kinds at all — it fails toward read-only, never toward editable.
|
|
61304
|
+
*/
|
|
61305
|
+
function systemRuleKindOf(condition) {
|
|
61306
|
+
const verdict = systemEventFamilyOf(systemEventKindNamesOf(condition) ?? []);
|
|
61307
|
+
return verdict.kind === "family" ? verdict.family : "mixed";
|
|
61308
|
+
}
|
|
61309
|
+
/**
|
|
60778
61310
|
* Is this condition visible — and authorable — for a rule of this kind?
|
|
60779
61311
|
*
|
|
60780
61312
|
* The COMPOSITION, and the only function that decides it: `appliesTo` is the
|
|
@@ -60815,35 +61347,64 @@ var NC_RULE_SECTIONS = [
|
|
|
60815
61347
|
label: "All rules",
|
|
60816
61348
|
blurb: "Every notification rule, whatever its trigger. Each rule picks a trigger, matches conditions and fans out to one or more delivery targets.",
|
|
60817
61349
|
newRuleLabel: "New rule",
|
|
60818
|
-
emptyHint: "No notification rules yet. Create one to be told what your cameras see."
|
|
61350
|
+
emptyHint: "No notification rules yet. Create one to be told what your cameras see.",
|
|
61351
|
+
creatable: true
|
|
60819
61352
|
},
|
|
60820
61353
|
{
|
|
60821
61354
|
key: "detection",
|
|
60822
61355
|
label: "Detections & devices",
|
|
60823
61356
|
blurb: "Rules driven by what the cameras and sensors SEE — detections, tracks, doorbell presses and package events.",
|
|
60824
61357
|
newRuleLabel: "New detection rule",
|
|
60825
|
-
emptyHint: "No detection rules yet. Create one to be told what your cameras see."
|
|
61358
|
+
emptyHint: "No detection rules yet. Create one to be told what your cameras see.",
|
|
61359
|
+
creatable: true
|
|
60826
61360
|
},
|
|
60827
61361
|
{
|
|
60828
61362
|
key: "audio",
|
|
60829
61363
|
label: "Sound",
|
|
60830
61364
|
blurb: "Rules on what the cameras HEAR: a sustained window of sound loud enough, or classified as one of the sounds you name. A sound rule fires only on a confirmed sampling window, never on a picture.",
|
|
60831
61365
|
newRuleLabel: "New sound rule",
|
|
60832
|
-
emptyHint: "No sound rules yet. A new sound rule opens on the sound condition already filled in with a level threshold, so you only have to name the sounds and the targets."
|
|
61366
|
+
emptyHint: "No sound rules yet. A new sound rule opens on the sound condition already filled in with a level threshold, so you only have to name the sounds and the targets.",
|
|
61367
|
+
creatable: true
|
|
60833
61368
|
},
|
|
60834
61369
|
{
|
|
60835
61370
|
key: "occupancy",
|
|
60836
61371
|
label: "Occupancy",
|
|
60837
61372
|
blurb: "Rules on how many objects are in a camera frame or a zone, and for how long: \"the driveway became occupied\", \"the garden emptied\".",
|
|
60838
61373
|
newRuleLabel: "New occupancy rule",
|
|
60839
|
-
emptyHint: "No occupancy rules yet. A new occupancy rule opens on the occupancy condition; pick the camera first, then the zone and the count."
|
|
61374
|
+
emptyHint: "No occupancy rules yet. A new occupancy rule opens on the occupancy condition; pick the camera first, then the zone and the count.",
|
|
61375
|
+
creatable: true
|
|
61376
|
+
},
|
|
61377
|
+
{
|
|
61378
|
+
key: "device-events",
|
|
61379
|
+
label: "Device events",
|
|
61380
|
+
blurb: "Rules about your devices: offline or back, switched off or on, a stream dropping, a battery or consumable running low, a camera detecting nothing.",
|
|
61381
|
+
newRuleLabel: "New device-event rule",
|
|
61382
|
+
emptyHint: "No device-event rules yet. These tell you when a device drops, a battery runs low or a camera goes blind.",
|
|
61383
|
+
creatable: true
|
|
60840
61384
|
},
|
|
60841
61385
|
{
|
|
60842
61386
|
key: "system",
|
|
60843
61387
|
label: "System events",
|
|
60844
|
-
blurb: "Rules about the installation
|
|
61388
|
+
blurb: "Rules about the installation: a node leaving the cluster, an addon crash-looping, an update available or installed, a backup or export finishing.",
|
|
60845
61389
|
newRuleLabel: "New system rule",
|
|
60846
|
-
emptyHint: "No system
|
|
61390
|
+
emptyHint: "No system rules yet. These tell you when a node leaves, an update lands or a backup finishes.",
|
|
61391
|
+
creatable: true
|
|
61392
|
+
},
|
|
61393
|
+
{
|
|
61394
|
+
key: "alarm",
|
|
61395
|
+
label: "Alarm",
|
|
61396
|
+
blurb: "Rules about the alarm panel: arming, armed, triggered, disarmed, and the refusals in between.",
|
|
61397
|
+
newRuleLabel: "New alarm rule",
|
|
61398
|
+
emptyHint: "No alarm rules yet. These tell you when the alarm arms, goes off or is disarmed.",
|
|
61399
|
+
creatable: true
|
|
61400
|
+
},
|
|
61401
|
+
{
|
|
61402
|
+
key: "mixed",
|
|
61403
|
+
label: "To recreate",
|
|
61404
|
+
blurb: "System rules authored before the three families existed. Each mixes families, keeps firing as it is, and can only be read or deleted: recreate it as one rule per family.",
|
|
61405
|
+
newRuleLabel: "New rule",
|
|
61406
|
+
emptyHint: "Nothing to recreate.",
|
|
61407
|
+
creatable: false
|
|
60847
61408
|
}
|
|
60848
61409
|
];
|
|
60849
61410
|
/** The section for a key, or `undefined` — the lookup behind every label. */
|
|
@@ -60866,8 +61427,9 @@ function isOccupancyRule(subject) {
|
|
|
60866
61427
|
* Does a rule belong in this section?
|
|
60867
61428
|
*
|
|
60868
61429
|
* `all` always matches — a section that hides a rule is how an operator
|
|
60869
|
-
* concludes it was deleted. The
|
|
60870
|
-
* occupancy are claimed by their condition, system by its trigger
|
|
61430
|
+
* concludes it was deleted. The others PARTITION the list: sound and
|
|
61431
|
+
* occupancy are claimed by their condition, a system-event rule by its trigger
|
|
61432
|
+
* and then by the family of its event kinds (or `mixed`, D637), and
|
|
60871
61433
|
* everything left over — including a trigger this build has never heard of —
|
|
60872
61434
|
* counts as a detection rule so it stays visible somewhere.
|
|
60873
61435
|
*
|
|
@@ -60879,21 +61441,23 @@ function isOccupancyRule(subject) {
|
|
|
60879
61441
|
*/
|
|
60880
61442
|
function ruleMatchesSection(subject, section) {
|
|
60881
61443
|
if (section === "all") return true;
|
|
60882
|
-
if (
|
|
61444
|
+
if (isSystemDelivery(subject.delivery)) return ruleKindOf(subject) === section;
|
|
60883
61445
|
if (section === "audio") return isAudioRule(subject);
|
|
60884
61446
|
if (section === "occupancy") return isOccupancyRule(subject);
|
|
60885
|
-
|
|
61447
|
+
if (section === "detection") return !isAudioRule(subject) && !isOccupancyRule(subject);
|
|
61448
|
+
return false;
|
|
60886
61449
|
}
|
|
60887
61450
|
/**
|
|
60888
61451
|
* Which section OWNS this rule — the counter behind a section strip.
|
|
60889
61452
|
*
|
|
60890
|
-
*
|
|
60891
|
-
*
|
|
61453
|
+
* The same order as {@link ruleMatchesSection} — trigger first, then the
|
|
61454
|
+
* discriminating condition — and the section spec asserts the two agree on
|
|
61455
|
+
* every subject, so the strip's counts and its contents cannot disagree.
|
|
60892
61456
|
*/
|
|
60893
61457
|
function ruleSectionOf(subject) {
|
|
60894
|
-
if (
|
|
60895
|
-
if (
|
|
60896
|
-
if (
|
|
61458
|
+
if (isSystemDelivery(subject.delivery)) return systemRuleKindOf(subject.conditions.systemEvent);
|
|
61459
|
+
if (isAudioRule(subject)) return "audio";
|
|
61460
|
+
if (isOccupancyRule(subject)) return "occupancy";
|
|
60897
61461
|
return "detection";
|
|
60898
61462
|
}
|
|
60899
61463
|
/**
|
|
@@ -60931,9 +61495,17 @@ var NC_AUDIO_SEED = {
|
|
|
60931
61495
|
};
|
|
60932
61496
|
function ruleSeedForSection(section) {
|
|
60933
61497
|
switch (section) {
|
|
61498
|
+
case "device-events": return {
|
|
61499
|
+
delivery: NC_SYSTEM_DELIVERY,
|
|
61500
|
+
conditions: { systemEvent: { kinds: ["device-offline", "device-online"] } }
|
|
61501
|
+
};
|
|
60934
61502
|
case "system": return {
|
|
60935
61503
|
delivery: NC_SYSTEM_DELIVERY,
|
|
60936
|
-
conditions: {}
|
|
61504
|
+
conditions: { systemEvent: { kinds: ["node-offline", "node-online"] } }
|
|
61505
|
+
};
|
|
61506
|
+
case "alarm": return {
|
|
61507
|
+
delivery: NC_SYSTEM_DELIVERY,
|
|
61508
|
+
conditions: { systemEvent: { kinds: ["alarm-triggered"] } }
|
|
60937
61509
|
};
|
|
60938
61510
|
case "audio": return {
|
|
60939
61511
|
delivery: "immediate",
|
|
@@ -60975,7 +61547,7 @@ var EDITOR_SECTION_LABELS = {
|
|
|
60975
61547
|
*
|
|
60976
61548
|
* Two rules, both of them about a control that would decide nothing:
|
|
60977
61549
|
*
|
|
60978
|
-
* - a
|
|
61550
|
+
* - a system-event rule (any family) has no device scope — `conditions.devices` is not
|
|
60979
61551
|
* evaluated for it and the input builder refuses to write it — so the
|
|
60980
61552
|
* Cameras section is DROPPED rather than shown and ignored;
|
|
60981
61553
|
* - a sound or occupancy rule is NAMED on its conditions section. Neither has
|
|
@@ -60993,7 +61565,7 @@ function ruleEditorSectionsForKind(kind) {
|
|
|
60993
61565
|
const spec = ruleKindSpec(kind);
|
|
60994
61566
|
const sections = [];
|
|
60995
61567
|
for (const key of NC_RULE_EDITOR_SECTION_ORDER) {
|
|
60996
|
-
if (key === "devices" && kind
|
|
61568
|
+
if (key === "devices" && isSystemRuleKind(kind)) continue;
|
|
60997
61569
|
sections.push({
|
|
60998
61570
|
key,
|
|
60999
61571
|
label: key === "conditions" ? spec.label : EDITOR_SECTION_LABELS[key]
|
|
@@ -61064,6 +61636,111 @@ function isScheduleActive(schedule, atMs) {
|
|
|
61064
61636
|
return schedule.invert === true ? !inside : inside;
|
|
61065
61637
|
}
|
|
61066
61638
|
//#endregion
|
|
61639
|
+
//#region src/notification/alarm-membership.ts
|
|
61640
|
+
var ARMED_WORD_PREFIX = "armed_";
|
|
61641
|
+
var ALARM_PANEL_CAP = "alarm-panel";
|
|
61642
|
+
var ALARM_PANEL_TRIGGER_METHOD = "trigger";
|
|
61643
|
+
/**
|
|
61644
|
+
* The sensor-event kinds that are OPENINGS to the alarm — the keys of the
|
|
61645
|
+
* engine's opening table (`alarm-openings.ts`, which is checked against this
|
|
61646
|
+
* list with `satisfies`). Only these carry an opening edge the alarm refuses.
|
|
61647
|
+
*/
|
|
61648
|
+
var NC_ALARM_OPENING_EVENT_KINDS = [
|
|
61649
|
+
"contact",
|
|
61650
|
+
"cover",
|
|
61651
|
+
"lock"
|
|
61652
|
+
];
|
|
61653
|
+
/**
|
|
61654
|
+
* A rule belongs to the alarm when its `deviceState` gate names ANY device's
|
|
61655
|
+
* `armed_*` word, or an ENABLED `onTrigger` sequence pulls the alarm panel's
|
|
61656
|
+
* trigger (D630).
|
|
61657
|
+
*/
|
|
61658
|
+
function ruleBelongsToAlarm(rule) {
|
|
61659
|
+
if ((rule.conditions.deviceState?.states ?? []).some((s) => s.trim().toLowerCase().startsWith(ARMED_WORD_PREFIX))) return true;
|
|
61660
|
+
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));
|
|
61661
|
+
}
|
|
61662
|
+
function isOpeningKind(kind) {
|
|
61663
|
+
const k = kind.trim().toLowerCase();
|
|
61664
|
+
return NC_ALARM_OPENING_EVENT_KINDS.some((opening) => opening === k);
|
|
61665
|
+
}
|
|
61666
|
+
/**
|
|
61667
|
+
* An alarm rule over openings only, asking for the CLEAR: the alarm edge
|
|
61668
|
+
* refuses every closing, and the chosen edge refuses every opening, so nothing
|
|
61669
|
+
* is left (D640 × D630). Not refused on save — alarm membership is derived and
|
|
61670
|
+
* can change with an action edit — but every editor must SAY it.
|
|
61671
|
+
*/
|
|
61672
|
+
function sensorTransitionNeverFires(rule) {
|
|
61673
|
+
const kinds = rule.conditions.sensorKinds ?? [];
|
|
61674
|
+
if (rule.conditions.sensorTransition !== "cleared" || kinds.length === 0) return false;
|
|
61675
|
+
if (!kinds.every(isOpeningKind)) return false;
|
|
61676
|
+
return ruleBelongsToAlarm(rule);
|
|
61677
|
+
}
|
|
61678
|
+
/** The warning an editor shows for {@link sensorTransitionNeverFires}. */
|
|
61679
|
+
var NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = "This rule belongs to the alarm, and an alarm rule fires only when an opening OPENS. Set to “only when it clears”, it can never fire.";
|
|
61680
|
+
//#endregion
|
|
61681
|
+
//#region src/notification/sensor-raised.ts
|
|
61682
|
+
/**
|
|
61683
|
+
* WHICH WAY A BOOLEAN SENSOR MOVED — read off the one slice a sensor event
|
|
61684
|
+
* persists (D640 "a sensor rule fires on the raise, the clear, or both").
|
|
61685
|
+
*
|
|
61686
|
+
* A device-event rule over a flood sensor notified on BOTH edges: water
|
|
61687
|
+
* detected, and back to dry. `NcConditions.sensorTransition` lets the rule
|
|
61688
|
+
* name one edge; this file answers, for one `SensorEvent`, which edge it is.
|
|
61689
|
+
*
|
|
61690
|
+
* NOT A SECOND TABLE. The "which boolean of this cap counts as HIGH" question
|
|
61691
|
+
* already has one answer, `SOURCE_CAP_ACTIVE_FIELD`
|
|
61692
|
+
* (`catalogs/sensor-active-state.ts`, the doorbell's and the recorder's edge
|
|
61693
|
+
* table), and a sensor event names its kind, not its cap. So the table here is
|
|
61694
|
+
* DERIVED: event kind → cap (`EVENT_KIND_BY_CAP`) → that cap's active field.
|
|
61695
|
+
* Only kinds whose taxonomy category is `sensor` take part — a switch has an
|
|
61696
|
+
* `on` boolean too, but "it triggers / it clears" is not a sentence about a
|
|
61697
|
+
* light, and offering it there would be a knob with a misleading label.
|
|
61698
|
+
* `presence` is a WORD (`home` / `not_home` / a zone), not a boolean, and is
|
|
61699
|
+
* absent from the source table, so it is absent here.
|
|
61700
|
+
*
|
|
61701
|
+
* `undefined` = never guessed: a kind with no raise (a doorbell press, a
|
|
61702
|
+
* button, a cover), or a slice whose field is missing or not a boolean. The
|
|
61703
|
+
* engine then does NOT filter — a flood alert must not go silent because one
|
|
61704
|
+
* read came back unreadable (the same stance as the alarm's `sensorEdgeOf`).
|
|
61705
|
+
*
|
|
61706
|
+
* Pure, RN-safe: the viewer imports the support rule from here.
|
|
61707
|
+
*/
|
|
61708
|
+
/** Event kind → the boolean field of its cap slice that means "raised". */
|
|
61709
|
+
var NC_SENSOR_RAISED_FIELD_BY_KIND = Object.freeze(Object.fromEntries(Object.entries(EVENT_KIND_BY_CAP).flatMap(([capName, descriptor]) => {
|
|
61710
|
+
const field = SOURCE_CAP_ACTIVE_FIELD[capName];
|
|
61711
|
+
if (field === void 0 || descriptor.category !== "sensor") return [];
|
|
61712
|
+
return [[descriptor.kind, field]];
|
|
61713
|
+
})));
|
|
61714
|
+
/** The sensor kinds `sensorTransition` means something for. */
|
|
61715
|
+
var NC_SENSOR_TRANSITION_KINDS = Object.freeze(Object.keys(NC_SENSOR_RAISED_FIELD_BY_KIND));
|
|
61716
|
+
function normaliseKind(kind) {
|
|
61717
|
+
return kind.trim().toLowerCase();
|
|
61718
|
+
}
|
|
61719
|
+
/**
|
|
61720
|
+
* true = the sensor is raised (water, smoke, open, tampered…), false = it
|
|
61721
|
+
* cleared, undefined = this kind has no raise or the slice cannot say.
|
|
61722
|
+
*/
|
|
61723
|
+
function sensorRaisedOf(kind, value) {
|
|
61724
|
+
if (value === null) return void 0;
|
|
61725
|
+
const field = NC_SENSOR_RAISED_FIELD_BY_KIND[normaliseKind(kind)];
|
|
61726
|
+
if (field === void 0) return void 0;
|
|
61727
|
+
const raw = Object.entries(value).find(([key]) => key === field)?.[1];
|
|
61728
|
+
return typeof raw === "boolean" ? raw : void 0;
|
|
61729
|
+
}
|
|
61730
|
+
/**
|
|
61731
|
+
* THE SUPPORT RULE, shared by both editors: "Notify when" is offered only when
|
|
61732
|
+
* the rule names at least one sensor kind and EVERY kind it names has a raise.
|
|
61733
|
+
* A mixed rule (flood + doorbell) would hear "only when it clears" as "never
|
|
61734
|
+
* for the doorbell" in the operator's head while the engine lets the doorbell
|
|
61735
|
+
* through — so the choice is not offered, and an editor prunes it on save.
|
|
61736
|
+
*/
|
|
61737
|
+
function sensorTransitionOffered(sensorKinds) {
|
|
61738
|
+
if (sensorKinds === void 0 || sensorKinds.length === 0) return false;
|
|
61739
|
+
return sensorKinds.every((kind) => NC_SENSOR_TRANSITION_KINDS.includes(normaliseKind(kind)));
|
|
61740
|
+
}
|
|
61741
|
+
/** What an editor tells the operator when it is about to prune the choice. */
|
|
61742
|
+
var NC_SENSOR_TRANSITION_UNSUPPORTED_REASON = "Only a sensor that raises and clears (water, smoke, gas, CO, vibration, tamper, motion, contact) can fire on one edge. Pick only such sensor kinds, or the rule fires on every change.";
|
|
61743
|
+
//#endregion
|
|
61067
61744
|
//#region src/notification/template-vars.ts
|
|
61068
61745
|
var RULE_BODY_ONLY = ["body"];
|
|
61069
61746
|
var RULE_TEXT = ["title", "body"];
|
|
@@ -61802,10 +62479,38 @@ var CAPTION_VARS = {
|
|
|
61802
62479
|
function onAxis(declared, asked) {
|
|
61803
62480
|
return declared === void 0 || asked === void 0 || declared.includes(asked);
|
|
61804
62481
|
}
|
|
61805
|
-
|
|
61806
|
-
|
|
62482
|
+
/**
|
|
62483
|
+
* Does a descriptor declared for `declared` kinds have a value for a rule of
|
|
62484
|
+
* `kind`?
|
|
62485
|
+
*
|
|
62486
|
+
* `system` on the WIRE stands for every system rule kind (D637): the served
|
|
62487
|
+
* catalog keeps the five pre-D637 tokens so installed viewers still parse it
|
|
62488
|
+
* (`NcTemplateVarKindSchema`), and the family split lives here, in the match.
|
|
62489
|
+
* Exported so the admin's local interpreter of the served catalog asks the
|
|
62490
|
+
* same question instead of restating it.
|
|
62491
|
+
*/
|
|
62492
|
+
function templateVarKindApplies(declared, kind) {
|
|
62493
|
+
if (declared === void 0 || kind === void 0) return true;
|
|
62494
|
+
if (declared.some((k) => k === kind)) return true;
|
|
62495
|
+
return isSystemRuleKind(kind) && declared.includes("system");
|
|
62496
|
+
}
|
|
62497
|
+
/**
|
|
62498
|
+
* Is a descriptor that names `systemEventKinds` on the event-kind axis of a
|
|
62499
|
+
* system rule? Read only for a system rule kind; any other kind ignores it.
|
|
62500
|
+
*
|
|
62501
|
+
* Event kinds chosen: the descriptor must speak about one of them. None chosen
|
|
62502
|
+
* yet: a FAMILY kind watches its own family's event kinds (a device-events rule
|
|
62503
|
+
* is never offered the alarm's `{{mode}}`), and `mixed` watches all of them.
|
|
62504
|
+
*/
|
|
62505
|
+
function templateVarSystemEventApplies(d, ctx) {
|
|
62506
|
+
if (!isSystemRuleKind(ctx.kind) || d.systemEventKinds === void 0) return true;
|
|
62507
|
+
const declared = d.systemEventKinds;
|
|
61807
62508
|
const asked = ctx.systemEventKinds ?? [];
|
|
61808
|
-
|
|
62509
|
+
if (asked.length > 0) return asked.some((k) => declared.includes(k));
|
|
62510
|
+
const family = ctx.kind === void 0 ? void 0 : systemFamilyOfKind(ctx.kind);
|
|
62511
|
+
if (family === void 0) return true;
|
|
62512
|
+
const own = systemEventKindsOfFamily(family);
|
|
62513
|
+
return declared.some((k) => own.includes(k));
|
|
61809
62514
|
}
|
|
61810
62515
|
/**
|
|
61811
62516
|
* The variables that have a value in `ctx`, in catalog order. Pure.
|
|
@@ -61819,45 +62524,85 @@ function templateVarsFor(ctx) {
|
|
|
61819
62524
|
const allowed = CAPTION_VARS[ctx.field];
|
|
61820
62525
|
return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && allowed.includes(d.name) && d.dynamic === void 0);
|
|
61821
62526
|
}
|
|
61822
|
-
return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && onAxis(d.fields, ctx.field) &&
|
|
62527
|
+
return NC_TEMPLATE_VARS.filter((d) => d.families.includes(ctx.family) && onAxis(d.fields, ctx.field) && templateVarKindApplies(d.kinds, ctx.kind) && onAxis(d.deliveries, ctx.delivery) && templateVarSystemEventApplies(d, ctx));
|
|
61823
62528
|
}
|
|
61824
62529
|
/** True when `name` is supplied in `ctx`, dynamic families (`count_<class>`) included. */
|
|
61825
62530
|
function isKnownTemplateVar(name, ctx) {
|
|
61826
62531
|
return templateVarsFor(ctx).some((d) => d.dynamic !== void 0 ? name.startsWith(d.dynamic.prefix) && name.length > d.dynamic.prefix.length : d.name === name);
|
|
61827
62532
|
}
|
|
61828
62533
|
//#endregion
|
|
61829
|
-
//#region src/notification/
|
|
61830
|
-
|
|
61831
|
-
|
|
61832
|
-
|
|
61833
|
-
|
|
61834
|
-
|
|
61835
|
-
|
|
61836
|
-
|
|
62534
|
+
//#region src/notification/scope-picker-items.ts
|
|
62535
|
+
function nodePickerItems(nodes) {
|
|
62536
|
+
return nodes.map((node) => ({
|
|
62537
|
+
id: node.id,
|
|
62538
|
+
name: node.name,
|
|
62539
|
+
type: node.isHub ? "hub" : "agent",
|
|
62540
|
+
location: node.isOnline ? "online" : "offline",
|
|
62541
|
+
...node.name !== node.id ? { detail: node.id } : {}
|
|
62542
|
+
}));
|
|
62543
|
+
}
|
|
61837
62544
|
/**
|
|
61838
|
-
*
|
|
61839
|
-
*
|
|
61840
|
-
|
|
61841
|
-
|
|
61842
|
-
|
|
61843
|
-
|
|
61844
|
-
|
|
61845
|
-
|
|
61846
|
-
|
|
61847
|
-
|
|
61848
|
-
|
|
61849
|
-
|
|
62545
|
+
* The server's own package name: `server-update-available` / `server-updated`
|
|
62546
|
+
* carry it, and `addons.listPackages` does not list it.
|
|
62547
|
+
*/
|
|
62548
|
+
var NC_SERVER_PACKAGE_NAME = "@camstack/server";
|
|
62549
|
+
/**
|
|
62550
|
+
* Every package name an update EVENT carries as `packageName`, one per
|
|
62551
|
+
* producer. The package picker offers each of them whether or not
|
|
62552
|
+
* `addons.listPackages` lists it, because a rule scoped to a name no event
|
|
62553
|
+
* carries can never fire (and one an event carries must be pickable).
|
|
62554
|
+
*
|
|
62555
|
+
* - `@camstack/server` — `server-update-available` / `server-updated`: the hub
|
|
62556
|
+
* root package (`HUB_ROOT_SPEC.packageName`, `@camstack/node-root`).
|
|
62557
|
+
* - `@camstack/system` — `server-update-available` from the framework check,
|
|
62558
|
+
* which checks `[SYSTEM_PACKAGE]` only (`AddonPackageService.listFrameworkPackages`).
|
|
62559
|
+
* `@camstack/types` / `@camstack/sdk` are framework packages for upload
|
|
62560
|
+
* routing but are never announced, so they are NOT here.
|
|
62561
|
+
* - `camstack-wrapper` — `wrapper-update-available` (`WRAPPER_PACKAGE_NAME`,
|
|
62562
|
+
* `wrapper-update-checker.ts`).
|
|
62563
|
+
*
|
|
62564
|
+
* Types cannot import those producers; the backend spec
|
|
62565
|
+
* `core/updates/__tests__/update-event-package-names.spec.ts` pins each literal
|
|
62566
|
+
* to its producer constant. This is a picker list, never a routing list.
|
|
62567
|
+
*/
|
|
62568
|
+
var NC_UPDATE_EVENT_PACKAGE_NAMES = [
|
|
62569
|
+
NC_SERVER_PACKAGE_NAME,
|
|
62570
|
+
"@camstack/system",
|
|
62571
|
+
"camstack-wrapper"
|
|
62572
|
+
];
|
|
62573
|
+
var UPDATE_EVENT_PACKAGE_TYPE = {
|
|
62574
|
+
"@camstack/server": "server",
|
|
62575
|
+
"@camstack/system": "framework",
|
|
62576
|
+
"camstack-wrapper": "wrapper"
|
|
62577
|
+
};
|
|
62578
|
+
function isUpdateEventPackageName(name) {
|
|
62579
|
+
return NC_UPDATE_EVENT_PACKAGE_NAMES.some((pinned) => pinned === name);
|
|
61850
62580
|
}
|
|
61851
62581
|
/**
|
|
61852
|
-
*
|
|
61853
|
-
*
|
|
61854
|
-
*
|
|
61855
|
-
* filter input for the set, so a filter is shown when any selected kind can be
|
|
61856
|
-
* narrowed by it. The kinds it cannot narrow are then simply not narrowed —
|
|
61857
|
-
* which is the engine's half of the same rule.
|
|
62582
|
+
* Every update-event package first (always offered: an event carries it), in
|
|
62583
|
+
* `NC_UPDATE_EVENT_PACKAGE_NAMES` order, then the installed addons sorted by
|
|
62584
|
+
* name. An installed version is the second line.
|
|
61858
62585
|
*/
|
|
61859
|
-
function
|
|
61860
|
-
|
|
62586
|
+
function packagePickerItems(packages) {
|
|
62587
|
+
const versions = new Map(packages.map((pkg) => [pkg.name, pkg.version]));
|
|
62588
|
+
const pinned = NC_UPDATE_EVENT_PACKAGE_NAMES.map((name) => {
|
|
62589
|
+
const version = versions.get(name);
|
|
62590
|
+
return {
|
|
62591
|
+
id: name,
|
|
62592
|
+
name,
|
|
62593
|
+
type: UPDATE_EVENT_PACKAGE_TYPE[name],
|
|
62594
|
+
location: null,
|
|
62595
|
+
...version !== void 0 ? { detail: version } : {}
|
|
62596
|
+
};
|
|
62597
|
+
});
|
|
62598
|
+
const addons = packages.filter((pkg) => !isUpdateEventPackageName(pkg.name)).map((pkg) => ({
|
|
62599
|
+
id: pkg.name,
|
|
62600
|
+
name: pkg.name,
|
|
62601
|
+
type: "addon",
|
|
62602
|
+
location: null,
|
|
62603
|
+
detail: pkg.version
|
|
62604
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
62605
|
+
return [...pinned, ...addons];
|
|
61861
62606
|
}
|
|
61862
62607
|
//#endregion
|
|
61863
62608
|
//#region src/notification/timelapse-rule.ts
|
|
@@ -65406,6 +66151,7 @@ exports.NATIVE_LEASE_TILE_BUDGET_KEY = NATIVE_LEASE_TILE_BUDGET_KEY;
|
|
|
65406
66151
|
exports.NAVIGATION_ACTION_CATALOG = NAVIGATION_ACTION_CATALOG;
|
|
65407
66152
|
exports.NAVIGATION_LIGHT_LEVEL_MAX = NAVIGATION_LIGHT_LEVEL_MAX;
|
|
65408
66153
|
exports.NAVIGATION_LIGHT_LEVEL_MIN = NAVIGATION_LIGHT_LEVEL_MIN;
|
|
66154
|
+
exports.NC_ALARM_OPENING_EVENT_KINDS = NC_ALARM_OPENING_EVENT_KINDS;
|
|
65409
66155
|
exports.NC_ALARM_SYSTEM_EVENT_KINDS = NC_ALARM_SYSTEM_EVENT_KINDS;
|
|
65410
66156
|
exports.NC_AUDIO_CONFIRM_HITS_DEFAULT = NC_AUDIO_CONFIRM_HITS_DEFAULT;
|
|
65411
66157
|
exports.NC_AUDIO_CONFIRM_HITS_MAX = NC_AUDIO_CONFIRM_HITS_MAX;
|
|
@@ -65442,11 +66188,23 @@ exports.NC_RULE_CLEARABLE_KEYS = NC_RULE_CLEARABLE_KEYS;
|
|
|
65442
66188
|
exports.NC_RULE_EDITOR_SECTION_ORDER = NC_RULE_EDITOR_SECTION_ORDER;
|
|
65443
66189
|
exports.NC_RULE_KIND_SPECS = NC_RULE_KIND_SPECS;
|
|
65444
66190
|
exports.NC_RULE_SECTIONS = NC_RULE_SECTIONS;
|
|
66191
|
+
exports.NC_SENSOR_RAISED_FIELD_BY_KIND = NC_SENSOR_RAISED_FIELD_BY_KIND;
|
|
66192
|
+
exports.NC_SENSOR_TRANSITION_KINDS = NC_SENSOR_TRANSITION_KINDS;
|
|
66193
|
+
exports.NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING = NC_SENSOR_TRANSITION_NEVER_FIRES_WARNING;
|
|
66194
|
+
exports.NC_SENSOR_TRANSITION_UNSUPPORTED_REASON = NC_SENSOR_TRANSITION_UNSUPPORTED_REASON;
|
|
66195
|
+
exports.NC_SERVER_PACKAGE_NAME = NC_SERVER_PACKAGE_NAME;
|
|
65445
66196
|
exports.NC_SNOOZE_MAX_MINUTES = NC_SNOOZE_MAX_MINUTES;
|
|
65446
66197
|
exports.NC_SYSTEM_DELIVERY = NC_SYSTEM_DELIVERY;
|
|
66198
|
+
exports.NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS = NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS;
|
|
66199
|
+
exports.NC_SYSTEM_EVENT_FAMILIES = NC_SYSTEM_EVENT_FAMILIES;
|
|
66200
|
+
exports.NC_SYSTEM_EVENT_FAMILY = NC_SYSTEM_EVENT_FAMILY;
|
|
66201
|
+
exports.NC_SYSTEM_EVENT_FAMILY_FILTERS = NC_SYSTEM_EVENT_FAMILY_FILTERS;
|
|
65447
66202
|
exports.NC_SYSTEM_EVENT_FILTER_KEYS = NC_SYSTEM_EVENT_FILTER_KEYS;
|
|
66203
|
+
exports.NC_SYSTEM_EVENT_KIND_GROUP_SPECS = NC_SYSTEM_EVENT_KIND_GROUP_SPECS;
|
|
66204
|
+
exports.NC_SYSTEM_RULE_KINDS = NC_SYSTEM_RULE_KINDS;
|
|
65448
66205
|
exports.NC_TAXONOMY = NC_TAXONOMY;
|
|
65449
66206
|
exports.NC_TEMPLATE_VARS = NC_TEMPLATE_VARS;
|
|
66207
|
+
exports.NC_UPDATE_EVENT_PACKAGE_NAMES = NC_UPDATE_EVENT_PACKAGE_NAMES;
|
|
65450
66208
|
exports.NETWORK_LINK_TYPES = NETWORK_LINK_TYPES;
|
|
65451
66209
|
exports.NETWORK_LINK_UNKNOWN = NETWORK_LINK_UNKNOWN;
|
|
65452
66210
|
exports.NativeCropBboxSchema = NativeCropBboxSchema;
|
|
@@ -65503,6 +66261,8 @@ exports.NcRuleActionsSchema = NcRuleActionsSchema;
|
|
|
65503
66261
|
exports.NcRuleClearableKeySchema = NcRuleClearableKeySchema;
|
|
65504
66262
|
exports.NcRuleInputSchema = NcRuleInputSchema;
|
|
65505
66263
|
exports.NcRuleKindSchema = NcRuleKindSchema;
|
|
66264
|
+
exports.NcRuleLastRunSchema = NcRuleLastRunSchema;
|
|
66265
|
+
exports.NcRuleLastRunsSchema = NcRuleLastRunsSchema;
|
|
65506
66266
|
exports.NcRuleNotificationButtonSchema = NcRuleNotificationButtonSchema;
|
|
65507
66267
|
exports.NcRulePatchSchema = NcRulePatchSchema;
|
|
65508
66268
|
exports.NcRuleSchema = NcRuleSchema;
|
|
@@ -65511,6 +66271,7 @@ exports.NcRuleUpdateInputSchema = NcRuleUpdateInputSchema;
|
|
|
65511
66271
|
exports.NcSceneConditionSchema = NcSceneConditionSchema;
|
|
65512
66272
|
exports.NcScheduleSchema = NcScheduleSchema;
|
|
65513
66273
|
exports.NcScheduleWindowSchema = NcScheduleWindowSchema;
|
|
66274
|
+
exports.NcSensorTransitionSchema = NcSensorTransitionSchema;
|
|
65514
66275
|
exports.NcSnoozeInputSchema = NcSnoozeInputSchema;
|
|
65515
66276
|
exports.NcSnoozeSchema = NcSnoozeSchema;
|
|
65516
66277
|
exports.NcSnoozeScopeSchema = NcSnoozeScopeSchema;
|
|
@@ -65526,6 +66287,7 @@ exports.NcTemplatePreviewSchema = NcTemplatePreviewSchema;
|
|
|
65526
66287
|
exports.NcTemplateVarContextSchema = NcTemplateVarContextSchema;
|
|
65527
66288
|
exports.NcTemplateVarDescriptorSchema = NcTemplateVarDescriptorSchema;
|
|
65528
66289
|
exports.NcTemplateVarGroupSchema = NcTemplateVarGroupSchema;
|
|
66290
|
+
exports.NcTemplateVarKindSchema = NcTemplateVarKindSchema;
|
|
65529
66291
|
exports.NcTestResultSchema = NcTestResultSchema;
|
|
65530
66292
|
exports.NcThrottleGranularitySchema = NcThrottleGranularitySchema;
|
|
65531
66293
|
exports.NcThrottleSchema = NcThrottleSchema;
|
|
@@ -65534,6 +66296,8 @@ exports.NetworkAccessStatusSchema = NetworkAccessStatusSchema;
|
|
|
65534
66296
|
exports.NetworkAddressSchema = NetworkAddressSchema;
|
|
65535
66297
|
exports.NetworkEndpointSchema = NetworkEndpointSchema;
|
|
65536
66298
|
exports.NetworkLinkStatusSchema = NetworkLinkStatusSchema;
|
|
66299
|
+
exports.NodeDirectoryEntrySchema = NodeDirectoryEntrySchema;
|
|
66300
|
+
exports.NodeDirectorySchema = NodeDirectorySchema;
|
|
65537
66301
|
exports.NotificationActionIconSchema = NotificationActionIconSchema;
|
|
65538
66302
|
exports.NotificationActionSchema = NotificationActionSchema;
|
|
65539
66303
|
exports.NotificationFormatSchema = NotificationFormatSchema;
|
|
@@ -66129,6 +66893,7 @@ exports.describeCustomActions = require_sleep.describeCustomActions;
|
|
|
66129
66893
|
exports.describeModelVariant = describeModelVariant;
|
|
66130
66894
|
exports.describeOnboardClamp = describeOnboardClamp;
|
|
66131
66895
|
exports.describeOnboardRefusal = describeOnboardRefusal;
|
|
66896
|
+
exports.describeSystemEventFamilyProblem = describeSystemEventFamilyProblem;
|
|
66132
66897
|
exports.detectAccessRole = detectAccessRole;
|
|
66133
66898
|
exports.detectionPipelineCapability = detectionPipelineCapability;
|
|
66134
66899
|
exports.deviceAdminLinkCapability = deviceAdminLinkCapability;
|
|
@@ -66243,10 +67008,13 @@ exports.isSoftwareDecode = require_canonical_hash.isSoftwareDecode;
|
|
|
66243
67008
|
exports.isSourceCap = isSourceCap;
|
|
66244
67009
|
exports.isStorageLocationMode = isStorageLocationMode;
|
|
66245
67010
|
exports.isSystemDelivery = isSystemDelivery;
|
|
67011
|
+
exports.isSystemEventFamily = isSystemEventFamily;
|
|
67012
|
+
exports.isSystemRuleKind = isSystemRuleKind;
|
|
66246
67013
|
exports.isVoidInput = isVoidInput;
|
|
66247
67014
|
exports.ituDbfsFromPreEpoch = ituDbfsFromPreEpoch;
|
|
66248
67015
|
exports.jobKindSchema = jobKindSchema;
|
|
66249
67016
|
exports.kebabToCamel = kebabToCamel;
|
|
67017
|
+
exports.kindsForDiscriminator = kindsForDiscriminator;
|
|
66250
67018
|
exports.knownValues = knownValues;
|
|
66251
67019
|
exports.lawnMowerControlCapability = lawnMowerControlCapability;
|
|
66252
67020
|
exports.legacyAutoLinkIds = legacyAutoLinkIds;
|
|
@@ -66299,6 +67067,7 @@ exports.navigationCapability = navigationCapability;
|
|
|
66299
67067
|
exports.networkAccessCapability = networkAccessCapability;
|
|
66300
67068
|
exports.networkLinkCapability = networkLinkCapability;
|
|
66301
67069
|
exports.networkQualityCapability = networkQualityCapability;
|
|
67070
|
+
exports.nodePickerItems = nodePickerItems;
|
|
66302
67071
|
exports.nodePin = require_sleep.nodePin;
|
|
66303
67072
|
exports.nodesCapability = nodesCapability;
|
|
66304
67073
|
exports.normalizeAddonInitResult = require_sleep.normalizeAddonInitResult;
|
|
@@ -66317,6 +67086,7 @@ exports.optionalMethod = require_sleep.optionalMethod;
|
|
|
66317
67086
|
exports.osdCapability = osdCapability;
|
|
66318
67087
|
exports.osdManagerCapability = osdManagerCapability;
|
|
66319
67088
|
exports.overlayClusterStepSettings = overlayClusterStepSettings;
|
|
67089
|
+
exports.packagePickerItems = packagePickerItems;
|
|
66320
67090
|
exports.parseAdminBase = parseAdminBase;
|
|
66321
67091
|
exports.parseCameraStreamConfig = parseCameraStreamConfig;
|
|
66322
67092
|
exports.parseExpression = parseExpression;
|
|
@@ -66405,6 +67175,7 @@ exports.resolveStreamMaps = require_canonical_hash.resolveStreamMaps;
|
|
|
66405
67175
|
exports.resolveVariantModelId = resolveVariantModelId;
|
|
66406
67176
|
exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
|
|
66407
67177
|
exports.roleSpec = roleSpec;
|
|
67178
|
+
exports.ruleBelongsToAlarm = ruleBelongsToAlarm;
|
|
66408
67179
|
exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
|
|
66409
67180
|
exports.ruleKindOf = ruleKindOf;
|
|
66410
67181
|
exports.ruleKindSpec = ruleKindSpec;
|
|
@@ -66425,6 +67196,9 @@ exports.scoreRuntimes = scoreRuntimes;
|
|
|
66425
67196
|
exports.scriptRunnerCapability = scriptRunnerCapability;
|
|
66426
67197
|
exports.searchDisplayIcons = searchDisplayIcons;
|
|
66427
67198
|
exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
|
|
67199
|
+
exports.sensorRaisedOf = sensorRaisedOf;
|
|
67200
|
+
exports.sensorTransitionNeverFires = sensorTransitionNeverFires;
|
|
67201
|
+
exports.sensorTransitionOffered = sensorTransitionOffered;
|
|
66428
67202
|
exports.serverManagementCapability = serverManagementCapability;
|
|
66429
67203
|
exports.setByPath = setByPath;
|
|
66430
67204
|
exports.settingsStoreCapability = settingsStoreCapability;
|
|
@@ -66462,13 +67236,21 @@ exports.switchCapability = switchCapability;
|
|
|
66462
67236
|
exports.switchedOffIds = switchedOffIds;
|
|
66463
67237
|
exports.synthesizeSourceInfo = synthesizeSourceInfo;
|
|
66464
67238
|
exports.systemCapability = systemCapability;
|
|
67239
|
+
exports.systemEventFamilyOf = systemEventFamilyOf;
|
|
67240
|
+
exports.systemEventFamilyProblems = systemEventFamilyProblems;
|
|
66465
67241
|
exports.systemEventFilterApplies = systemEventFilterApplies;
|
|
66466
67242
|
exports.systemEventFilterAppliesToAnyKind = systemEventFilterAppliesToAnyKind;
|
|
67243
|
+
exports.systemEventKindNamesOf = systemEventKindNamesOf;
|
|
67244
|
+
exports.systemEventKindsOfFamily = systemEventKindsOfFamily;
|
|
67245
|
+
exports.systemFamilyOfKind = systemFamilyOfKind;
|
|
67246
|
+
exports.systemRuleKindOf = systemRuleKindOf;
|
|
66467
67247
|
exports.tamperCapability = tamperCapability;
|
|
66468
67248
|
exports.taskLogEntrySchema = taskLogEntrySchema;
|
|
66469
67249
|
exports.taskPhaseSchema = taskPhaseSchema;
|
|
66470
67250
|
exports.taskTargetSchema = taskTargetSchema;
|
|
66471
67251
|
exports.temperatureSensorCapability = temperatureSensorCapability;
|
|
67252
|
+
exports.templateVarKindApplies = templateVarKindApplies;
|
|
67253
|
+
exports.templateVarSystemEventApplies = templateVarSystemEventApplies;
|
|
66472
67254
|
exports.templateVarsFor = templateVarsFor;
|
|
66473
67255
|
exports.terminalSessionCapability = terminalSessionCapability;
|
|
66474
67256
|
exports.textToHtml = textToHtml;
|