@camstack/types 1.2.253 → 1.2.255

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.
@@ -61,17 +61,34 @@
61
61
  * (`packages/addon-benchmark/vite.config.ts`) and therefore read whatever the
62
62
  * host loaded; nothing in this file is consumed that way. See
63
63
  * `docs/design/2026-08-19-viewer-notification-rule-parity.md` §3 and Phase 3.
64
+ *
65
+ * THREE SYSTEM KINDS, AND ONE THAT IS ONLY READ (D637)
66
+ * ────────────────────────────────────────────────────
67
+ * A `system-event` rule used to be ONE kind for every infrastructure event. It
68
+ * is now one kind per family (`device-events`, `system`, `alarm`), DERIVED from
69
+ * the event kinds the rule names (`system-event-families.ts`), exactly as sound
70
+ * and occupancy are derived from their condition. A stored rule whose kinds span
71
+ * families — or name a legacy kind, or none — derives `mixed`: it keeps firing,
72
+ * it is listed and deletable, and it is never edited.
64
73
  */
65
74
  import { type NcAudioCondition, type NcConditions, type NcDelivery, type NcOccupancyCondition } from '../capabilities/notification-rules.cap.js';
75
+ import { type NcSystemEventFamily } from './system-event-families.js';
66
76
  /**
67
77
  * The kind of rule an operator is authoring.
68
78
  *
69
79
  * Coarser than `delivery` in one direction and finer in another, deliberately:
70
80
  * `immediate` / `track-end` / `package-event` are ONE kind here (their
71
81
  * differences are already the catalog's `appliesTo` job), while `device-event`
72
- * and `immediate` each split in two on their discriminating condition.
82
+ * and `immediate` each split in two on their discriminating condition, and
83
+ * `system-event` splits by the FAMILY of the event kinds it names (D637).
73
84
  */
74
- export type NcRuleKind = 'detection' | 'sensor' | 'occupancy' | 'sound' | 'system';
85
+ export type NcRuleKind = 'detection' | 'sensor' | 'occupancy' | 'sound' | NcSystemEventFamily | 'mixed';
86
+ /** Every kind a `system-event` rule can derive — the three families and `mixed`. */
87
+ export declare const NC_SYSTEM_RULE_KINDS: readonly ["device-events", "system", "alarm", "mixed"];
88
+ /** Is this a kind a `system-event` rule derives (any family, or `mixed`)? */
89
+ export declare function isSystemRuleKind(kind: NcRuleKind | undefined): boolean;
90
+ /** The family a kind authors, or undefined (a camera kind, or `mixed`). */
91
+ export declare function systemFamilyOfKind(kind: NcRuleKind): NcSystemEventFamily | undefined;
75
92
  export interface NcRuleKindSpec {
76
93
  readonly kind: NcRuleKind;
77
94
  /** What the conditions section is CALLED for this kind (English fallback). */
@@ -81,6 +98,13 @@ export interface NcRuleKindSpec {
81
98
  * excluded — burying it would hide the whole feature (which is how an
82
99
  * operator with a working audio engine reported there was no way to create an
83
100
  * audio rule).
101
+ *
102
+ * NOT UNIQUE PER KIND. A GROUP of kinds may share one discriminator: the three
103
+ * system families and `mixed` all ride `systemEvent` (D637), and which of them
104
+ * a rule is comes from the event kinds, not from the condition's presence. A
105
+ * consumer that maps a discriminator back to ONE kind (a `Map` keyed on it)
106
+ * keeps the last spec and silently misroutes the others — ask
107
+ * {@link kindsForDiscriminator} for the whole group.
84
108
  */
85
109
  readonly discriminator?: keyof NcConditions;
86
110
  /**
@@ -89,6 +113,12 @@ export interface NcRuleKindSpec {
89
113
  * save is about to drop one.
90
114
  */
91
115
  readonly excluded: Readonly<Record<string, string>>;
116
+ /**
117
+ * false = readable and deletable, never edited. Only `mixed`: a rule that
118
+ * predates D637 and spans families. It keeps firing; the operator recreates
119
+ * it one rule per family.
120
+ */
121
+ readonly editable: boolean;
92
122
  /**
93
123
  * Can a notification of this kind carry a picture AT ALL?
94
124
  *
@@ -96,9 +126,9 @@ export interface NcRuleKindSpec {
96
126
  * ladder resolves media by OWNER, and only a subject that freezes one has any
97
127
  * (`triggerCanCarryStill` in the addon's `test-event.ts` is the same list).
98
128
  *
99
- * Only `system` is left. An infrastructure event is about no camera at all —
100
- * there is nothing to photograph, so every media control on it is a knob that
101
- * does nothing. A SOUND rule was here until 2026-08-15 and was right to be:
129
+ * Only the system-event kinds are left. An infrastructure event is about no
130
+ * camera at all — there is nothing to photograph, so every media control on it
131
+ * is a knob that does nothing. A SOUND rule was here until 2026-08-15 and was right to be:
102
132
  * its subject is a sampling window that owns no frame. It now photographs the
103
133
  * camera at the match instead (`still-shelf.ts`), which is a picture nothing
104
134
  * else could give it.
@@ -124,6 +154,12 @@ export interface NcRuleKindSpec {
124
154
  export declare const NC_RULE_KIND_SPECS: readonly NcRuleKindSpec[];
125
155
  /** The spec for a kind. Total by construction — every member has an entry. */
126
156
  export declare function ruleKindSpec(kind: NcRuleKind): NcRuleKindSpec;
157
+ /**
158
+ * Every kind a discriminator makes — one kind for `audio` and `occupancy`, the
159
+ * whole system group for `systemEvent`. Empty for a condition that makes no
160
+ * kind. See {@link NcRuleKindSpec.discriminator}.
161
+ */
162
+ export declare function kindsForDiscriminator(discriminator: keyof NcConditions): readonly NcRuleKind[];
127
163
  /** The delivery a system rule rides — named once, compared everywhere. */
128
164
  export declare const NC_SYSTEM_DELIVERY = "system-event";
129
165
  /**
@@ -171,9 +207,18 @@ export interface NcRuleSectionSubject {
171
207
  * the order below is the engine's own: `evaluateRule` checks the system branch
172
208
  * first, then the occupancy and audio gates. Takes a plain `delivery` string so
173
209
  * a trigger this build does not know still classifies (as `detection`, which is
174
- * the read-only path's own fallback).
210
+ * the read-only path's own fallback). A system rule classifies by the FAMILY of
211
+ * its event kinds (D637) — see {@link systemRuleKindOf}.
175
212
  */
176
213
  export declare function ruleKindOf(rule: NcRuleSectionSubject): NcRuleKind;
214
+ /**
215
+ * A system rule's kind: its one family, or `mixed` (D637).
216
+ *
217
+ * Takes the UNTYPED condition for the same reason {@link NcRuleConditionsSubject}
218
+ * is structural. `mixed` covers kinds across families, a legacy or unknown kind,
219
+ * and no kinds at all — it fails toward read-only, never toward editable.
220
+ */
221
+ export declare function systemRuleKindOf(condition: unknown): NcSystemEventFamily | 'mixed';
177
222
  /**
178
223
  * The shape {@link conditionVisibleForKind} reads off a catalog descriptor.
179
224
  *
@@ -226,10 +271,14 @@ export declare function droppedConditionsForKind(conditions: NcAuthoredCondition
226
271
  *
227
272
  * `all` is kept and is the DEFAULT: a section that hides rules is how an
228
273
  * operator concludes a rule was deleted. Which sections a given SURFACE offers
229
- * for authoring is that surface's decision — the viewer omits `system` from its
230
- * create flow and still renders system rules under `all`.
274
+ * for authoring is that surface's decision — the viewer omits the system-event
275
+ * sections from its create flow and still renders system rules under `all`.
276
+ *
277
+ * D637 split the one `system` section into the three families, plus `mixed`:
278
+ * the stored system rules that span families. `mixed` is a real, owning section
279
+ * (a rule must be listed somewhere) that nothing can CREATE into.
231
280
  */
232
- export type NcRuleSectionKey = 'all' | 'detection' | 'audio' | 'occupancy' | 'system';
281
+ export type NcRuleSectionKey = 'all' | 'detection' | 'audio' | 'occupancy' | 'device-events' | 'system' | 'alarm' | 'mixed';
233
282
  export interface NcRuleSection {
234
283
  readonly key: NcRuleSectionKey;
235
284
  /** English fallback; the viewer maps `key` onto an i18n key. */
@@ -240,6 +289,8 @@ export interface NcRuleSection {
240
289
  readonly newRuleLabel: string;
241
290
  /** What the section says when it holds nothing yet. */
242
291
  readonly emptyHint: string;
292
+ /** Can a rule be CREATED from this section? false only for `mixed` (D637). */
293
+ readonly creatable: boolean;
243
294
  }
244
295
  export declare const NC_RULE_SECTIONS: readonly NcRuleSection[];
245
296
  /** The section for a key, or `undefined` — the lookup behind every label. */
@@ -254,8 +305,9 @@ export declare function isOccupancyRule(subject: NcRuleSectionSubject): boolean;
254
305
  * Does a rule belong in this section?
255
306
  *
256
307
  * `all` always matches — a section that hides a rule is how an operator
257
- * concludes it was deleted. The other four PARTITION the list: sound and
258
- * occupancy are claimed by their condition, system by its trigger, and
308
+ * concludes it was deleted. The others PARTITION the list: sound and
309
+ * occupancy are claimed by their condition, a system-event rule by its trigger
310
+ * and then by the family of its event kinds (or `mixed`, D637), and
259
311
  * everything left over — including a trigger this build has never heard of —
260
312
  * counts as a detection rule so it stays visible somewhere.
261
313
  *
@@ -271,8 +323,9 @@ export type NcRuleOwningSectionKey = Exclude<NcRuleSectionKey, 'all'>;
271
323
  /**
272
324
  * Which section OWNS this rule — the counter behind a section strip.
273
325
  *
274
- * Derived from {@link ruleMatchesSection} rather than restated, so the strip's
275
- * counts and the strip's contents can never disagree.
326
+ * The same order as {@link ruleMatchesSection} — trigger first, then the
327
+ * discriminating condition — and the section spec asserts the two agree on
328
+ * every subject, so the strip's counts and its contents cannot disagree.
276
329
  */
277
330
  export declare function ruleSectionOf(subject: NcRuleSectionSubject): NcRuleOwningSectionKey;
278
331
  /**
@@ -310,6 +363,10 @@ export declare const NC_AUDIO_SEED: NcAudioCondition;
310
363
  * on a trigger they must pick first. That is exactly the gap reported on
311
364
  * 2026-08-13 ("non vedo un modo per creare le nuove rules audio e occupancy")
312
365
  * for two features whose engines had already shipped.
366
+ *
367
+ * A system seed carries its event kinds for the same reason: the kind is derived
368
+ * from them (D637), so an empty seed would open a `mixed` rule. `mixed` itself
369
+ * falls to the default and is never offered — its section is not `creatable`.
313
370
  */
314
371
  export interface NcRuleSeed extends NcRuleSectionSubject {
315
372
  readonly delivery: NcDelivery;
@@ -349,7 +406,7 @@ export interface NcRuleEditorSection {
349
406
  *
350
407
  * Two rules, both of them about a control that would decide nothing:
351
408
  *
352
- * - a `system-event` rule has no device scope — `conditions.devices` is not
409
+ * - a system-event rule (any family) has no device scope — `conditions.devices` is not
353
410
  * evaluated for it and the input builder refuses to write it — so the
354
411
  * Cameras section is DROPPED rather than shown and ignored;
355
412
  * - a sound or occupancy rule is NAMED on its conditions section. Neither has
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Nodes and packages as a PICKER lists them (D637). One projection shared by the
3
+ * admin UI and the viewer, so the system family's two pickers group and label
4
+ * the same way. The shape is structurally the pickers' `PickerItem<string>`.
5
+ */
6
+ import type { NodeDirectoryEntry } from '../capabilities/nodes.cap.js';
7
+ export interface NcScopePickerItem {
8
+ readonly id: string;
9
+ readonly name: string;
10
+ readonly type?: string;
11
+ readonly location?: string | null;
12
+ readonly detail?: string;
13
+ }
14
+ export declare function nodePickerItems(nodes: readonly NodeDirectoryEntry[]): readonly NcScopePickerItem[];
15
+ /**
16
+ * The server's own package name: `server-update-available` / `server-updated`
17
+ * carry it, and `addons.listPackages` does not list it.
18
+ */
19
+ export declare const NC_SERVER_PACKAGE_NAME = "@camstack/server";
20
+ /**
21
+ * Every package name an update EVENT carries as `packageName`, one per
22
+ * producer. The package picker offers each of them whether or not
23
+ * `addons.listPackages` lists it, because a rule scoped to a name no event
24
+ * carries can never fire (and one an event carries must be pickable).
25
+ *
26
+ * - `@camstack/server` — `server-update-available` / `server-updated`: the hub
27
+ * root package (`HUB_ROOT_SPEC.packageName`, `@camstack/node-root`).
28
+ * - `@camstack/system` — `server-update-available` from the framework check,
29
+ * which checks `[SYSTEM_PACKAGE]` only (`AddonPackageService.listFrameworkPackages`).
30
+ * `@camstack/types` / `@camstack/sdk` are framework packages for upload
31
+ * routing but are never announced, so they are NOT here.
32
+ * - `camstack-wrapper` — `wrapper-update-available` (`WRAPPER_PACKAGE_NAME`,
33
+ * `wrapper-update-checker.ts`).
34
+ *
35
+ * Types cannot import those producers; the backend spec
36
+ * `core/updates/__tests__/update-event-package-names.spec.ts` pins each literal
37
+ * to its producer constant. This is a picker list, never a routing list.
38
+ */
39
+ export declare const NC_UPDATE_EVENT_PACKAGE_NAMES: readonly ["@camstack/server", "@camstack/system", "camstack-wrapper"];
40
+ export interface NcInstalledPackageLike {
41
+ readonly name: string;
42
+ readonly version: string;
43
+ }
44
+ /**
45
+ * Every update-event package first (always offered: an event carries it), in
46
+ * `NC_UPDATE_EVENT_PACKAGE_NAMES` order, then the installed addons sorted by
47
+ * name. An installed version is the second line.
48
+ */
49
+ export declare function packagePickerItems(packages: readonly NcInstalledPackageLike[]): readonly NcScopePickerItem[];
@@ -0,0 +1,76 @@
1
+ /**
2
+ * WHICH FAMILY every system-event kind belongs to, and which narrowing filters
3
+ * each family may carry: one table, read by the hub validator, by `ruleKindOf`
4
+ * and by both rule editors (D637).
5
+ *
6
+ * A system rule used to be one editor for thirty-one kinds and five filters.
7
+ * "Eventi di sistema" carried battery kinds under a liveness `deviceTypes` filter
8
+ * and went silent for two weeks (D636). The three families are three questions:
9
+ * about devices, about the installation, and about the alarm panel. A rule
10
+ * answers one of them. The engine never needed to know, and it still does not:
11
+ * a mixed stored rule keeps firing. Only AUTHORING is strict.
12
+ *
13
+ * The legacy `camera-*` tail has no family (`null`). It is parsed, never produced,
14
+ * never offered.
15
+ */
16
+ import { type NcSystemEventCondition, type NcSystemEventKind } from '../capabilities/notification-rules.cap.js';
17
+ import { type NcSystemEventFilterKey } from './system-event-filters.js';
18
+ export declare const NC_SYSTEM_EVENT_FAMILIES: readonly ["device-events", "system", "alarm"];
19
+ export type NcSystemEventFamily = (typeof NC_SYSTEM_EVENT_FAMILIES)[number];
20
+ export declare function isSystemEventFamily(value: string): value is NcSystemEventFamily;
21
+ /** Total over the enum: a kind added to the cap without a family fails tsc here. */
22
+ export declare const NC_SYSTEM_EVENT_FAMILY: Readonly<Record<NcSystemEventKind, NcSystemEventFamily | null>>;
23
+ /** A condition field that can narrow or exclude a system subject. */
24
+ export type NcSystemEventConditionFilterKey = NcSystemEventFilterKey | 'excludeDeviceIds';
25
+ export declare const NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS: readonly NcSystemEventConditionFilterKey[];
26
+ /**
27
+ * The filters a family may carry. The four base filters are the union of
28
+ * `systemEventFilterApplies` over the family's kinds (the spec pins that
29
+ * equality). `excludeDeviceIds` is a device-events filter only: an alarm is
30
+ * narrowed to the camera that triggered it and excludes nothing.
31
+ */
32
+ export declare const NC_SYSTEM_EVENT_FAMILY_FILTERS: Readonly<Record<NcSystemEventFamily, readonly NcSystemEventConditionFilterKey[]>>;
33
+ /** A themed set of kinds as both editors list them. `label` is an English fallback. */
34
+ export interface NcSystemEventKindGroupSpec {
35
+ readonly id: string;
36
+ readonly family: NcSystemEventFamily;
37
+ readonly label: string;
38
+ readonly kinds: readonly NcSystemEventKind[];
39
+ }
40
+ export declare const NC_SYSTEM_EVENT_KIND_GROUP_SPECS: readonly NcSystemEventKindGroupSpec[];
41
+ export declare function systemEventKindsOfFamily(family: NcSystemEventFamily): readonly NcSystemEventKind[];
42
+ /** The kind names on an UNTYPED condition, or `undefined` when it has none. */
43
+ export declare function systemEventKindNamesOf(condition: unknown): readonly string[] | undefined;
44
+ export type NcSystemEventFamilyVerdict = {
45
+ readonly kind: 'family';
46
+ readonly family: NcSystemEventFamily;
47
+ } | {
48
+ readonly kind: 'mixed';
49
+ };
50
+ /**
51
+ * One family, or `mixed`. Mixed covers kinds that span families, a legacy kind,
52
+ * a kind this build does not know (it fails toward read-only and never toward
53
+ * editable), and an empty selection (nothing to decide on).
54
+ */
55
+ export declare function systemEventFamilyOf(kindNames: readonly string[]): NcSystemEventFamilyVerdict;
56
+ export type NcSystemEventFamilyProblem = {
57
+ readonly code: 'no-kinds';
58
+ } | {
59
+ readonly code: 'legacy-kind';
60
+ readonly kind: NcSystemEventKind;
61
+ } | {
62
+ readonly code: 'mixed-families';
63
+ readonly families: readonly NcSystemEventFamily[];
64
+ } | {
65
+ readonly code: 'filter-outside-family';
66
+ readonly filter: NcSystemEventConditionFilterKey;
67
+ readonly family: NcSystemEventFamily;
68
+ };
69
+ /**
70
+ * Why the hub refuses this condition on a new or updated rule. Empty = accepted.
71
+ * Families are reported in `NC_SYSTEM_EVENT_FAMILIES` order, and filters in
72
+ * `NC_SYSTEM_EVENT_CONDITION_FILTER_KEYS` order, so a refusal reads the same
73
+ * every time.
74
+ */
75
+ export declare function systemEventFamilyProblems(condition: NcSystemEventCondition | undefined): readonly NcSystemEventFamilyProblem[];
76
+ export declare function describeSystemEventFamilyProblem(problem: NcSystemEventFamilyProblem): string;
@@ -8,10 +8,31 @@
8
8
  * `addon-post-analysis` run each producer and compare its keys with this list,
9
9
  * so the two cannot drift silently again.
10
10
  */
11
- import { NcRuleKindSchema, NcTemplateFamilySchema, NcTemplateFieldSchema, NcTemplateVarContextSchema, NcTemplateVarDescriptorSchema, NcTemplateVarGroupSchema, type NcTemplateVarContext, type NcTemplateVarDescriptor } from '../capabilities/notification-rules.cap.js';
11
+ import { NcRuleKindSchema, NcTemplateFamilySchema, NcTemplateFieldSchema, NcTemplateVarContextSchema, NcTemplateVarDescriptorSchema, NcTemplateVarGroupSchema, type NcTemplateVarContext, type NcTemplateVarDescriptor, type NcTemplateVarKind } from '../capabilities/notification-rules.cap.js';
12
+ import { type NcRuleKind } from './rule-kinds.js';
12
13
  export { NcRuleKindSchema, NcTemplateFamilySchema, NcTemplateFieldSchema, NcTemplateVarContextSchema, NcTemplateVarDescriptorSchema, NcTemplateVarGroupSchema, };
13
14
  export type { NcTemplateFamily, NcTemplateField, NcTemplateVarContext, NcTemplateVarDescriptor, NcTemplateVarGroup, } from '../capabilities/notification-rules.cap.js';
14
15
  export declare const NC_TEMPLATE_VARS: readonly NcTemplateVarDescriptor[];
16
+ /**
17
+ * Does a descriptor declared for `declared` kinds have a value for a rule of
18
+ * `kind`?
19
+ *
20
+ * `system` on the WIRE stands for every system rule kind (D637): the served
21
+ * catalog keeps the five pre-D637 tokens so installed viewers still parse it
22
+ * (`NcTemplateVarKindSchema`), and the family split lives here, in the match.
23
+ * Exported so the admin's local interpreter of the served catalog asks the
24
+ * same question instead of restating it.
25
+ */
26
+ export declare function templateVarKindApplies(declared: readonly NcTemplateVarKind[] | undefined, kind: NcRuleKind | undefined): boolean;
27
+ /**
28
+ * Is a descriptor that names `systemEventKinds` on the event-kind axis of a
29
+ * system rule? Read only for a system rule kind; any other kind ignores it.
30
+ *
31
+ * Event kinds chosen: the descriptor must speak about one of them. None chosen
32
+ * yet: a FAMILY kind watches its own family's event kinds (a device-events rule
33
+ * is never offered the alarm's `{{mode}}`), and `mixed` watches all of them.
34
+ */
35
+ export declare function templateVarSystemEventApplies(d: NcTemplateVarDescriptor, ctx: NcTemplateVarContext): boolean;
15
36
  /**
16
37
  * The variables that have a value in `ctx`, in catalog order. Pure.
17
38
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/types",
3
- "version": "1.2.253",
3
+ "version": "1.2.255",
4
4
  "description": "Shared types, interfaces, and model catalogs for the CamStack detection ecosystem",
5
5
  "keywords": [
6
6
  "camstack",