@camstack/types 1.2.87 → 1.2.89
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/capabilities/index.d.ts +1 -1
- package/dist/capabilities/recording.cap.d.ts +7 -4
- package/dist/capabilities/videoclips.cap.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +389 -3
- package/dist/index.mjs +368 -4
- package/dist/notification/rule-kinds.d.ts +348 -0
- package/package.json +1 -1
|
@@ -109,7 +109,7 @@ export { PasskeySummarySchema, userPasskeysCapability } from './user-passkeys.ca
|
|
|
109
109
|
export type { IVectorStoreProvider } from './vector-store.cap.js';
|
|
110
110
|
export { VectorDeclareIndexInputSchema, VectorDeleteByFilterInputSchema, VectorDeleteInputSchema, VectorDeleteResultSchema, type VectorFilter, VectorFilterSchema, VectorGetInputSchema, VectorGetResultSchema, type VectorItem, VectorItemSchema, type VectorMatch, VectorMatchSchema, type VectorMetadata, VectorMetadataSchema, type VectorMetric, VectorMetricSchema, VectorQueryInputSchema, VectorQueryResultSchema, VectorStatsInputSchema, VectorStatsResultSchema, VectorUpsertInputSchema, VectorUpsertResultSchema, vectorStoreCapability, } from './vector-store.cap.js';
|
|
111
111
|
export type { Clip, ClipPlayback, IVideoclipsProvider } from './videoclips.cap.js';
|
|
112
|
-
export { ClipPlaybackSchema, ClipSchema, MAX_CLIP_EVENT_IDS, videoclipsCapability, } from './videoclips.cap.js';
|
|
112
|
+
export { ClipPlaybackSchema, ClipSchema, MAX_CLIP_EVENT_IDS, MAX_CLIP_LABELS, videoclipsCapability, } from './videoclips.cap.js';
|
|
113
113
|
export type { IViewerUiProvider } from './viewer-ui.cap.js';
|
|
114
114
|
export { viewerUiCapability } from './viewer-ui.cap.js';
|
|
115
115
|
export { type IWebrtcSessionProvider, type WebrtcClientHints, type WebrtcStreamChoice, WebrtcStreamChoiceSchema, type WebrtcStreamTarget, WebrtcStreamTargetSchema, webrtcClientHintsSchema, webrtcSessionCapability, } from './webrtc-session.cap.js';
|
|
@@ -60,6 +60,7 @@ export type RecordingDeviceUsage = z.infer<typeof RecordingDeviceUsageSchema>;
|
|
|
60
60
|
export declare const RecordingLocationUsageSchema: z.ZodObject<{
|
|
61
61
|
locationId: z.ZodNullable<z.ZodString>;
|
|
62
62
|
locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
63
|
+
root: z.ZodOptional<z.ZodString>;
|
|
63
64
|
usedBytes: z.ZodNumber;
|
|
64
65
|
availableBytes: z.ZodNullable<z.ZodNumber>;
|
|
65
66
|
totalBytes: z.ZodNullable<z.ZodNumber>;
|
|
@@ -76,13 +77,14 @@ export declare const RecordingStorageUsageSchema: z.ZodObject<{
|
|
|
76
77
|
usedBytes: z.ZodNumber;
|
|
77
78
|
oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
78
79
|
}, z.core.$strip>>;
|
|
79
|
-
locations: z.ZodArray<z.ZodObject<{
|
|
80
|
+
locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
80
81
|
locationId: z.ZodNullable<z.ZodString>;
|
|
81
82
|
locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
83
|
+
root: z.ZodOptional<z.ZodString>;
|
|
82
84
|
usedBytes: z.ZodNumber;
|
|
83
85
|
availableBytes: z.ZodNullable<z.ZodNumber>;
|
|
84
86
|
totalBytes: z.ZodNullable<z.ZodNumber>;
|
|
85
|
-
}, z.core.$strip
|
|
87
|
+
}, z.core.$strip>>>;
|
|
86
88
|
}, z.core.$strip>;
|
|
87
89
|
export type RecordingStorageUsage = z.infer<typeof RecordingStorageUsageSchema>;
|
|
88
90
|
/**
|
|
@@ -263,13 +265,14 @@ export declare const recordingCapability: {
|
|
|
263
265
|
usedBytes: z.ZodNumber;
|
|
264
266
|
oldestMs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
265
267
|
}, z.core.$strip>>;
|
|
266
|
-
locations: z.ZodArray<z.ZodObject<{
|
|
268
|
+
locations: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
267
269
|
locationId: z.ZodNullable<z.ZodString>;
|
|
268
270
|
locationIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
271
|
+
root: z.ZodOptional<z.ZodString>;
|
|
269
272
|
usedBytes: z.ZodNumber;
|
|
270
273
|
availableBytes: z.ZodNullable<z.ZodNumber>;
|
|
271
274
|
totalBytes: z.ZodNullable<z.ZodNumber>;
|
|
272
|
-
}, z.core.$strip
|
|
275
|
+
}, z.core.$strip>>>;
|
|
273
276
|
}, z.core.$strip>, "query">;
|
|
274
277
|
readonly getDeviceConfig: import("./capability-definition.js").CapabilityMethodSchema<z.ZodObject<{
|
|
275
278
|
deviceId: z.ZodNumber;
|
|
@@ -22,6 +22,8 @@ import { type InferProvider } from './capability-definition.js';
|
|
|
22
22
|
* while preserving `eventIds[0]` — the surface's thumbnail fallback.
|
|
23
23
|
*/
|
|
24
24
|
export declare const MAX_CLIP_EVENT_IDS = 24;
|
|
25
|
+
/** Cap on {@link ClipSchema.labels} — the ribbon row has space for ~3 words. */
|
|
26
|
+
export declare const MAX_CLIP_LABELS = 3;
|
|
25
27
|
export declare const ClipSchema: z.ZodObject<{
|
|
26
28
|
id: z.ZodString;
|
|
27
29
|
source: z.ZodString;
|
|
@@ -35,6 +37,7 @@ export declare const ClipSchema: z.ZodObject<{
|
|
|
35
37
|
startMs: z.ZodNumber;
|
|
36
38
|
endMs: z.ZodNumber;
|
|
37
39
|
}, z.core.$strip>;
|
|
40
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
38
41
|
thumbnail: z.ZodOptional<z.ZodString>;
|
|
39
42
|
stillAtMs: z.ZodOptional<z.ZodNumber>;
|
|
40
43
|
eventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -80,6 +83,7 @@ export declare const videoclipsCapability: {
|
|
|
80
83
|
startMs: z.ZodNumber;
|
|
81
84
|
endMs: z.ZodNumber;
|
|
82
85
|
}, z.core.$strip>;
|
|
86
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
83
87
|
thumbnail: z.ZodOptional<z.ZodString>;
|
|
84
88
|
stillAtMs: z.ZodOptional<z.ZodNumber>;
|
|
85
89
|
eventIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -194,6 +194,7 @@ export { audioIsFailClosed, audioLabelChoices, audioModeOf, audioOrDefaults, isA
|
|
|
194
194
|
export { isBaseConditionKey, knownValues, NC_BASE_CONDITION_KEYS, type NcBaseConditionKey, pickerForCondition, type TaxonomyGroup, type TaxonomyOption, type TaxonomyPicker, } from './notification/condition-taxonomy.js';
|
|
195
195
|
export { type PreparedAction, type PreparedAttachment, type PreparedNotification, prepareNotification, type ResolvedLevel, } from './notification/degrade-engine.js';
|
|
196
196
|
export { htmlToText, markdownToHtmlLite, markdownToText, type NotificationFormat as NotificationBodyFormat, resolveFormat, textToHtml, transcodeBody, } from './notification/format-transcode.js';
|
|
197
|
+
export { conditionExclusionReason, conditionVisibleForKind, defaultDeliveryForSection, droppedConditionsForKind, isAudioRule, isOccupancyRule, isSystemDelivery, NC_AUDIO_SEED, NC_OCCUPANCY_DEFAULTS, NC_RULE_EDITOR_SECTION_ORDER, NC_RULE_KIND_SPECS, NC_RULE_SECTIONS, NC_SYSTEM_DELIVERY, type NcDroppedCondition, type NcKindVisibilitySubject, type NcRuleEditorSection, type NcRuleEditorSectionKey, type NcRuleKind, type NcRuleKindSpec, type NcRuleOwningSectionKey, type NcRuleSection, type NcRuleSectionKey, type NcRuleSectionSubject, type NcRuleSeed, parseRuleSection, ruleEditorSectionsForKind, ruleKindOf, ruleKindSpec, ruleMatchesSection, ruleSection, ruleSectionOf, ruleSeedForSection, } from './notification/rule-kinds.js';
|
|
197
198
|
export { isScheduleActive } from './notification/schedule.js';
|
|
198
199
|
export { NC_SYSTEM_EVENT_FILTER_KEYS, type NcSystemEventFilterKey, systemEventFilterApplies, systemEventFilterAppliesToAnyKind, } from './notification/system-event-filters.js';
|
|
199
200
|
export type { TimelapseCadencePair, TimelapsePreviewMode, TimelapseRule, TimelapseRuleInput, TimelapseRulePatch, TimelapseTemplate, } from './notification/timelapse-rule.js';
|
package/dist/index.js
CHANGED
|
@@ -20220,6 +20220,8 @@ var vectorStoreCapability = {
|
|
|
20220
20220
|
* while preserving `eventIds[0]` — the surface's thumbnail fallback.
|
|
20221
20221
|
*/
|
|
20222
20222
|
var MAX_CLIP_EVENT_IDS = 24;
|
|
20223
|
+
/** Cap on {@link ClipSchema.labels} — the ribbon row has space for ~3 words. */
|
|
20224
|
+
var MAX_CLIP_LABELS = 3;
|
|
20223
20225
|
var ClipSchema = zod.z.object({
|
|
20224
20226
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
20225
20227
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -20237,6 +20239,14 @@ var ClipSchema = zod.z.object({
|
|
|
20237
20239
|
endMs: zod.z.number()
|
|
20238
20240
|
}),
|
|
20239
20241
|
/**
|
|
20242
|
+
* Distinct object classes attached to this visit (`person`, `car`, …),
|
|
20243
|
+
* dominant first, capped at {@link MAX_CLIP_LABELS}. The ribbon renders these
|
|
20244
|
+
* instead of the bare kind — "Object" tells the operator nothing a colour bar
|
|
20245
|
+
* did not. Absent (never empty) when the visit attached no classified object
|
|
20246
|
+
* event, so a motion/audio-only visit keeps its kind label.
|
|
20247
|
+
*/
|
|
20248
|
+
labels: zod.z.array(zod.z.string()).max(3).optional(),
|
|
20249
|
+
/**
|
|
20240
20250
|
* Lazy thumbnail URL, never inlined.
|
|
20241
20251
|
*
|
|
20242
20252
|
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
@@ -27435,9 +27445,21 @@ var RecordingLocationUsageSchema = zod.z.object({
|
|
|
27435
27445
|
* previously rendered as two identical "disks" with a nonsensical used
|
|
27436
27446
|
* split — hydrate attribution across aliases is arbitrary by nature. */
|
|
27437
27447
|
locationIds: zod.z.array(zod.z.string()).optional(),
|
|
27438
|
-
/**
|
|
27448
|
+
/**
|
|
27449
|
+
* Filesystem root of the physical volume this row accounts — the only
|
|
27450
|
+
* operator-legible identity when a location has no `displayName` yet, and
|
|
27451
|
+
* what a "which disk is full" alert has to name. OPTIONAL for the same
|
|
27452
|
+
* train-skew reason as `oldestMs`: a recorder that predates the field omits
|
|
27453
|
+
* it, and this schema must keep validating that older provider's payload.
|
|
27454
|
+
*/
|
|
27455
|
+
root: zod.z.string().optional(),
|
|
27456
|
+
/** Bytes of recordings stored on this PHYSICAL volume (all aliases). This is
|
|
27457
|
+
* the footage's SHARE of the volume, not how full the volume is — the disk
|
|
27458
|
+
* also holds everything that is not recordings. Volume fill is
|
|
27459
|
+
* `(totalBytes - availableBytes) / totalBytes`. */
|
|
27439
27460
|
usedBytes: zod.z.number(),
|
|
27440
|
-
/** Free bytes on the location's volume; null when capacity is unknown
|
|
27461
|
+
/** Free bytes on the location's volume; null when capacity is unknown
|
|
27462
|
+
* (remote/unstattable — the recorder logs the statfs failure with the root). */
|
|
27441
27463
|
availableBytes: zod.z.number().nullable(),
|
|
27442
27464
|
/** Total bytes of the location's volume; null when unknown. */
|
|
27443
27465
|
totalBytes: zod.z.number().nullable()
|
|
@@ -27449,7 +27471,15 @@ var RecordingStorageUsageSchema = zod.z.object({
|
|
|
27449
27471
|
nodeId: zod.z.string(),
|
|
27450
27472
|
totalUsedBytes: zod.z.number(),
|
|
27451
27473
|
devices: zod.z.array(RecordingDeviceUsageSchema),
|
|
27452
|
-
|
|
27474
|
+
/**
|
|
27475
|
+
* Per-physical-volume capacity. OPTIONAL, and consumers must render the rest
|
|
27476
|
+
* of the payload without it: the hub serves this method through a BAKED
|
|
27477
|
+
* router, so a hub whose framework train predates a change to this array
|
|
27478
|
+
* strips it out of an answer a newer recorder happily produced. A UI that
|
|
27479
|
+
* dereferences it unconditionally crashes the whole Storage page over a
|
|
27480
|
+
* missing disk bar.
|
|
27481
|
+
*/
|
|
27482
|
+
locations: zod.z.array(RecordingLocationUsageSchema).optional()
|
|
27453
27483
|
});
|
|
27454
27484
|
/**
|
|
27455
27485
|
* The OPERATOR-ARMED half of multi-location recordings (D116).
|
|
@@ -43550,6 +43580,340 @@ function prepareNotification(caps, n) {
|
|
|
43550
43580
|
};
|
|
43551
43581
|
}
|
|
43552
43582
|
//#endregion
|
|
43583
|
+
//#region src/notification/rule-kinds.ts
|
|
43584
|
+
/**
|
|
43585
|
+
* Reasons, written once. Each names the SUBJECT FIELD the engine reads and
|
|
43586
|
+
* finds absent — that is what makes the exclusion checkable against the engine
|
|
43587
|
+
* rather than an opinion about tidiness.
|
|
43588
|
+
*/
|
|
43589
|
+
var NO_SENSOR_KIND = "An occupancy edge is not a sensor event: it carries no sensor kind, so this condition can never match one.";
|
|
43590
|
+
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.";
|
|
43591
|
+
var OCCUPANCY_SOURCE = "An occupancy edge is always produced by the pipeline, so any other source can never match and “pipeline” narrows nothing.";
|
|
43592
|
+
var AUDIO_SOURCE = "A confirmed sound window is always stamped as an audio subject, so any other source can never match.";
|
|
43593
|
+
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.";
|
|
43594
|
+
var SOUND_NO_CONFIDENCE = "A sound window’s evidence is a percentage of samples, not a detector score, so a confidence threshold can never be satisfied.";
|
|
43595
|
+
var SOUND_NO_GEOMETRY = "A sound has no position in the frame, so a zone or a drawn polygon can never match it.";
|
|
43596
|
+
var NC_RULE_KIND_SPECS = [
|
|
43597
|
+
{
|
|
43598
|
+
kind: "detection",
|
|
43599
|
+
label: "Conditions",
|
|
43600
|
+
excluded: {},
|
|
43601
|
+
carriesMedia: true,
|
|
43602
|
+
carriesSubjectCrop: true
|
|
43603
|
+
},
|
|
43604
|
+
{
|
|
43605
|
+
kind: "sensor",
|
|
43606
|
+
label: "Conditions",
|
|
43607
|
+
/** Same argument as `detection`: `occupancy` converts, it does not confuse. */
|
|
43608
|
+
excluded: {},
|
|
43609
|
+
carriesMedia: true,
|
|
43610
|
+
carriesSubjectCrop: true,
|
|
43611
|
+
blurb: "A doorbell press or a linked sensor changing state. The picture comes from the camera the sensor is attributed to."
|
|
43612
|
+
},
|
|
43613
|
+
{
|
|
43614
|
+
kind: "occupancy",
|
|
43615
|
+
label: "Occupancy",
|
|
43616
|
+
discriminator: "occupancy",
|
|
43617
|
+
excluded: {
|
|
43618
|
+
sensorKinds: NO_SENSOR_KIND,
|
|
43619
|
+
eventTypeTokens: NO_EVENT_TOKEN,
|
|
43620
|
+
source: OCCUPANCY_SOURCE
|
|
43621
|
+
},
|
|
43622
|
+
carriesMedia: true,
|
|
43623
|
+
carriesSubjectCrop: true,
|
|
43624
|
+
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."
|
|
43625
|
+
},
|
|
43626
|
+
{
|
|
43627
|
+
kind: "sound",
|
|
43628
|
+
label: "Sound",
|
|
43629
|
+
discriminator: "audio",
|
|
43630
|
+
excluded: {
|
|
43631
|
+
classes: SOUND_NOT_A_PICTURE,
|
|
43632
|
+
classesExclude: SOUND_NOT_A_PICTURE,
|
|
43633
|
+
minConfidence: SOUND_NO_CONFIDENCE,
|
|
43634
|
+
zones: SOUND_NO_GEOMETRY,
|
|
43635
|
+
zonesExclude: SOUND_NO_GEOMETRY,
|
|
43636
|
+
customZones: SOUND_NO_GEOMETRY,
|
|
43637
|
+
crossing: SOUND_NO_GEOMETRY,
|
|
43638
|
+
labelEquals: SOUND_NOT_A_PICTURE,
|
|
43639
|
+
identities: SOUND_NOT_A_PICTURE,
|
|
43640
|
+
identitiesExclude: SOUND_NOT_A_PICTURE,
|
|
43641
|
+
plates: SOUND_NOT_A_PICTURE,
|
|
43642
|
+
source: AUDIO_SOURCE
|
|
43643
|
+
},
|
|
43644
|
+
carriesMedia: true,
|
|
43645
|
+
carriesSubjectCrop: false,
|
|
43646
|
+
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.",
|
|
43647
|
+
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."
|
|
43648
|
+
},
|
|
43649
|
+
{
|
|
43650
|
+
kind: "system",
|
|
43651
|
+
label: "Events",
|
|
43652
|
+
discriminator: "systemEvent",
|
|
43653
|
+
excluded: {},
|
|
43654
|
+
carriesMedia: false,
|
|
43655
|
+
carriesSubjectCrop: false,
|
|
43656
|
+
blurb: "The installation itself: a camera or stream dropping, a node leaving, an update landing. There is no detection behind it and no frame to attach."
|
|
43657
|
+
}
|
|
43658
|
+
];
|
|
43659
|
+
/** The spec for a kind. Total by construction — every member has an entry. */
|
|
43660
|
+
function ruleKindSpec(kind) {
|
|
43661
|
+
return NC_RULE_KIND_SPECS.find((s) => s.kind === kind) ?? NC_RULE_KIND_SPECS[0];
|
|
43662
|
+
}
|
|
43663
|
+
/** The delivery a system rule rides — named once, compared everywhere. */
|
|
43664
|
+
var NC_SYSTEM_DELIVERY = "system-event";
|
|
43665
|
+
/**
|
|
43666
|
+
* Is this a SYSTEM rule — one about the installation rather than about anything
|
|
43667
|
+
* a camera saw? Takes a plain `string` so a rule carrying a delivery this build
|
|
43668
|
+
* has never heard of still gets an answer instead of a type error.
|
|
43669
|
+
*/
|
|
43670
|
+
function isSystemDelivery(delivery) {
|
|
43671
|
+
return delivery === NC_SYSTEM_DELIVERY;
|
|
43672
|
+
}
|
|
43673
|
+
/**
|
|
43674
|
+
* Which kind of rule is this?
|
|
43675
|
+
*
|
|
43676
|
+
* The CONDITION wins over the delivery wherever the engine says it does, and
|
|
43677
|
+
* the order below is the engine's own: `evaluateRule` checks the system branch
|
|
43678
|
+
* first, then the occupancy and audio gates. Takes a plain `delivery` string so
|
|
43679
|
+
* a trigger this build does not know still classifies (as `detection`, which is
|
|
43680
|
+
* the read-only path's own fallback).
|
|
43681
|
+
*/
|
|
43682
|
+
function ruleKindOf(rule) {
|
|
43683
|
+
if (isSystemDelivery(rule.delivery)) return "system";
|
|
43684
|
+
if (rule.conditions.occupancy !== void 0 && rule.delivery === "device-event") return "occupancy";
|
|
43685
|
+
if (rule.conditions.audio !== void 0 && rule.delivery === "immediate") return "sound";
|
|
43686
|
+
if (rule.delivery === "device-event") return "sensor";
|
|
43687
|
+
return "detection";
|
|
43688
|
+
}
|
|
43689
|
+
/**
|
|
43690
|
+
* Is this condition visible — and authorable — for a rule of this kind?
|
|
43691
|
+
*
|
|
43692
|
+
* The COMPOSITION, and the only function that decides it: `appliesTo` is the
|
|
43693
|
+
* server's answer about the trigger, the kind's `excluded` map is this build's
|
|
43694
|
+
* answer about the sub-type, and the discriminator overrides both (a sound rule
|
|
43695
|
+
* must be able to edit its sound even though `audio` is excluded for every
|
|
43696
|
+
* OTHER kind that rides `immediate`).
|
|
43697
|
+
*/
|
|
43698
|
+
function conditionVisibleForKind(descriptor, delivery, kind) {
|
|
43699
|
+
const spec = ruleKindSpec(kind);
|
|
43700
|
+
if (descriptor.id === spec.discriminator) return true;
|
|
43701
|
+
if (!descriptor.appliesTo.includes(delivery)) return false;
|
|
43702
|
+
return spec.excluded[descriptor.id] === void 0;
|
|
43703
|
+
}
|
|
43704
|
+
/** Why a condition is not offered for this kind, or `null` when it IS. */
|
|
43705
|
+
function conditionExclusionReason(descriptorId, kind) {
|
|
43706
|
+
const spec = ruleKindSpec(kind);
|
|
43707
|
+
if (descriptorId === spec.discriminator) return null;
|
|
43708
|
+
return spec.excluded[descriptorId] ?? null;
|
|
43709
|
+
}
|
|
43710
|
+
function droppedConditionsForKind(conditions, kind) {
|
|
43711
|
+
const spec = ruleKindSpec(kind);
|
|
43712
|
+
const out = [];
|
|
43713
|
+
for (const [conditionId, value] of Object.entries(conditions)) {
|
|
43714
|
+
if (value === void 0) continue;
|
|
43715
|
+
if (Array.isArray(value) && value.length === 0) continue;
|
|
43716
|
+
const reason = spec.excluded[conditionId];
|
|
43717
|
+
if (reason !== void 0) out.push({
|
|
43718
|
+
conditionId,
|
|
43719
|
+
reason
|
|
43720
|
+
});
|
|
43721
|
+
}
|
|
43722
|
+
return out;
|
|
43723
|
+
}
|
|
43724
|
+
var NC_RULE_SECTIONS = [
|
|
43725
|
+
{
|
|
43726
|
+
key: "all",
|
|
43727
|
+
label: "All rules",
|
|
43728
|
+
blurb: "Every notification rule, whatever its trigger. Each rule picks a trigger, matches conditions and fans out to one or more delivery targets.",
|
|
43729
|
+
newRuleLabel: "New rule",
|
|
43730
|
+
emptyHint: "No notification rules yet. Create one to be told what your cameras see."
|
|
43731
|
+
},
|
|
43732
|
+
{
|
|
43733
|
+
key: "detection",
|
|
43734
|
+
label: "Detections & devices",
|
|
43735
|
+
blurb: "Rules driven by what the cameras and sensors SEE — detections, tracks, doorbell presses and package events.",
|
|
43736
|
+
newRuleLabel: "New detection rule",
|
|
43737
|
+
emptyHint: "No detection rules yet. Create one to be told what your cameras see."
|
|
43738
|
+
},
|
|
43739
|
+
{
|
|
43740
|
+
key: "audio",
|
|
43741
|
+
label: "Sound",
|
|
43742
|
+
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.",
|
|
43743
|
+
newRuleLabel: "New sound rule",
|
|
43744
|
+
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."
|
|
43745
|
+
},
|
|
43746
|
+
{
|
|
43747
|
+
key: "occupancy",
|
|
43748
|
+
label: "Occupancy",
|
|
43749
|
+
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\".",
|
|
43750
|
+
newRuleLabel: "New occupancy rule",
|
|
43751
|
+
emptyHint: "No occupancy rules yet. A new occupancy rule opens on the occupancy condition; pick the camera first, then the zone and the count."
|
|
43752
|
+
},
|
|
43753
|
+
{
|
|
43754
|
+
key: "system",
|
|
43755
|
+
label: "System events",
|
|
43756
|
+
blurb: "Rules about the installation itself: a camera or stream dropping, a node leaving the cluster, an addon or server update becoming available. These carry no image and are not tied to a detection.",
|
|
43757
|
+
newRuleLabel: "New system rule",
|
|
43758
|
+
emptyHint: "No system-event rules yet. These tell you when a camera drops, a node leaves or an update lands."
|
|
43759
|
+
}
|
|
43760
|
+
];
|
|
43761
|
+
/** The section for a key, or `undefined` — the lookup behind every label. */
|
|
43762
|
+
function ruleSection(key) {
|
|
43763
|
+
return NC_RULE_SECTIONS.find((s) => s.key === key) ?? NC_RULE_SECTIONS[0];
|
|
43764
|
+
}
|
|
43765
|
+
/** Narrow a raw section string back to a known key (no cast). */
|
|
43766
|
+
function parseRuleSection(value) {
|
|
43767
|
+
return NC_RULE_SECTIONS.find((s) => s.key === value)?.key;
|
|
43768
|
+
}
|
|
43769
|
+
/** True for a rule whose sound condition makes it a SOUND rule. */
|
|
43770
|
+
function isAudioRule(subject) {
|
|
43771
|
+
return subject.conditions.audio !== void 0;
|
|
43772
|
+
}
|
|
43773
|
+
/** True for a rule whose occupancy condition makes it an OCCUPANCY rule. */
|
|
43774
|
+
function isOccupancyRule(subject) {
|
|
43775
|
+
return subject.conditions.occupancy !== void 0;
|
|
43776
|
+
}
|
|
43777
|
+
/**
|
|
43778
|
+
* Does a rule belong in this section?
|
|
43779
|
+
*
|
|
43780
|
+
* `all` always matches — a section that hides a rule is how an operator
|
|
43781
|
+
* concludes it was deleted. The other four PARTITION the list: sound and
|
|
43782
|
+
* occupancy are claimed by their condition, system by its trigger, and
|
|
43783
|
+
* everything left over — including a trigger this build has never heard of —
|
|
43784
|
+
* counts as a detection rule so it stays visible somewhere.
|
|
43785
|
+
*
|
|
43786
|
+
* Keyed on the CONDITION for two of them, because the trigger alone cannot
|
|
43787
|
+
* answer: a sound rule is `immediate` and an occupancy rule is `device-event`,
|
|
43788
|
+
* and in each case the condition is the discriminator the engine itself uses.
|
|
43789
|
+
* A section keyed on delivery would put both back in the pile they are
|
|
43790
|
+
* invisible in.
|
|
43791
|
+
*/
|
|
43792
|
+
function ruleMatchesSection(subject, section) {
|
|
43793
|
+
if (section === "all") return true;
|
|
43794
|
+
if (section === "system") return isSystemDelivery(subject.delivery);
|
|
43795
|
+
if (section === "audio") return isAudioRule(subject);
|
|
43796
|
+
if (section === "occupancy") return isOccupancyRule(subject);
|
|
43797
|
+
return !isSystemDelivery(subject.delivery) && !isAudioRule(subject) && !isOccupancyRule(subject);
|
|
43798
|
+
}
|
|
43799
|
+
/**
|
|
43800
|
+
* Which section OWNS this rule — the counter behind a section strip.
|
|
43801
|
+
*
|
|
43802
|
+
* Derived from {@link ruleMatchesSection} rather than restated, so the strip's
|
|
43803
|
+
* counts and the strip's contents can never disagree.
|
|
43804
|
+
*/
|
|
43805
|
+
function ruleSectionOf(subject) {
|
|
43806
|
+
if (ruleMatchesSection(subject, "system")) return "system";
|
|
43807
|
+
if (ruleMatchesSection(subject, "audio")) return "audio";
|
|
43808
|
+
if (ruleMatchesSection(subject, "occupancy")) return "occupancy";
|
|
43809
|
+
return "detection";
|
|
43810
|
+
}
|
|
43811
|
+
/**
|
|
43812
|
+
* The occupancy schema's own defaults, in one place.
|
|
43813
|
+
*
|
|
43814
|
+
* Both the WIDGET (what an untouched sub-field shows) and the CREATION PRESET
|
|
43815
|
+
* (what "New occupancy rule" seeds) have to author exactly these numbers, and
|
|
43816
|
+
* two copies of a default is how a preset starts writing a rule that does not
|
|
43817
|
+
* match what the editor then displays. Mirrors `NcOccupancyConditionSchema`'s
|
|
43818
|
+
* `.default(...)` clauses, and the spec asserts the mirror.
|
|
43819
|
+
*/
|
|
43820
|
+
var NC_OCCUPANCY_DEFAULTS = {
|
|
43821
|
+
op: "became-occupied",
|
|
43822
|
+
count: 1,
|
|
43823
|
+
sustainSeconds: 15
|
|
43824
|
+
};
|
|
43825
|
+
/**
|
|
43826
|
+
* The seeded sound condition.
|
|
43827
|
+
*
|
|
43828
|
+
* Carries a level floor rather than the bare defaults: with neither a level nor
|
|
43829
|
+
* a label the engine returns false for every window (`matchesAudio`), so a
|
|
43830
|
+
* preset without one would hand the operator a rule that can never fire. The
|
|
43831
|
+
* offered level is the same one the widget writes, so switching to SOUNDS
|
|
43832
|
+
* (label mode — the one that fires on the first labelled frame, D157) is one
|
|
43833
|
+
* tap on the mode picker.
|
|
43834
|
+
*
|
|
43835
|
+
* The seed cannot be a label rule instead: a labels-only condition with no
|
|
43836
|
+
* labels chosen yet is fail-closed too, and it would hand the operator the same
|
|
43837
|
+
* dead rule from the other side.
|
|
43838
|
+
*/
|
|
43839
|
+
var NC_AUDIO_SEED = {
|
|
43840
|
+
hitPercent: NC_AUDIO_DEFAULTS.hitPercent,
|
|
43841
|
+
samplingSeconds: NC_AUDIO_DEFAULTS.samplingSeconds,
|
|
43842
|
+
dbThreshold: -55
|
|
43843
|
+
};
|
|
43844
|
+
function ruleSeedForSection(section) {
|
|
43845
|
+
switch (section) {
|
|
43846
|
+
case "system": return {
|
|
43847
|
+
delivery: NC_SYSTEM_DELIVERY,
|
|
43848
|
+
conditions: {}
|
|
43849
|
+
};
|
|
43850
|
+
case "audio": return {
|
|
43851
|
+
delivery: "immediate",
|
|
43852
|
+
conditions: { audio: NC_AUDIO_SEED }
|
|
43853
|
+
};
|
|
43854
|
+
case "occupancy": return {
|
|
43855
|
+
delivery: "device-event",
|
|
43856
|
+
conditions: { occupancy: NC_OCCUPANCY_DEFAULTS }
|
|
43857
|
+
};
|
|
43858
|
+
default: return {
|
|
43859
|
+
delivery: "immediate",
|
|
43860
|
+
conditions: {}
|
|
43861
|
+
};
|
|
43862
|
+
}
|
|
43863
|
+
}
|
|
43864
|
+
/** The trigger a "New rule" in this section should open on. */
|
|
43865
|
+
function defaultDeliveryForSection(section) {
|
|
43866
|
+
return ruleSeedForSection(section).delivery;
|
|
43867
|
+
}
|
|
43868
|
+
var NC_RULE_EDITOR_SECTION_ORDER = [
|
|
43869
|
+
"rule",
|
|
43870
|
+
"devices",
|
|
43871
|
+
"conditions",
|
|
43872
|
+
"notification",
|
|
43873
|
+
"actions",
|
|
43874
|
+
"advanced"
|
|
43875
|
+
];
|
|
43876
|
+
/** The English fallback name of each section, before the kind renames one. */
|
|
43877
|
+
var EDITOR_SECTION_LABELS = {
|
|
43878
|
+
rule: "Rule",
|
|
43879
|
+
devices: "Cameras",
|
|
43880
|
+
conditions: "Conditions",
|
|
43881
|
+
notification: "Notification",
|
|
43882
|
+
actions: "Actions",
|
|
43883
|
+
advanced: "Advanced"
|
|
43884
|
+
};
|
|
43885
|
+
/**
|
|
43886
|
+
* The sections a rule of THIS kind actually shows.
|
|
43887
|
+
*
|
|
43888
|
+
* Two rules, both of them about a control that would decide nothing:
|
|
43889
|
+
*
|
|
43890
|
+
* - a `system-event` rule has no device scope — `conditions.devices` is not
|
|
43891
|
+
* evaluated for it and the input builder refuses to write it — so the
|
|
43892
|
+
* Cameras section is DROPPED rather than shown and ignored;
|
|
43893
|
+
* - a sound or occupancy rule is NAMED on its conditions section. Neither has
|
|
43894
|
+
* a trigger of its own, so that section is the only place either feature
|
|
43895
|
+
* exists, and a heading that never mentions sound is exactly why an operator
|
|
43896
|
+
* with a working audio engine reported there was no way to create an audio
|
|
43897
|
+
* rule.
|
|
43898
|
+
*
|
|
43899
|
+
* The NOTIFICATION section always survives: priority and the template still
|
|
43900
|
+
* matter even for a kind that carries no picture, and dropping the section to
|
|
43901
|
+
* hide the media controls would take the template with it. Whether the media
|
|
43902
|
+
* half renders is `carriesMedia` / `carriesSubjectCrop`, asked separately.
|
|
43903
|
+
*/
|
|
43904
|
+
function ruleEditorSectionsForKind(kind) {
|
|
43905
|
+
const spec = ruleKindSpec(kind);
|
|
43906
|
+
const sections = [];
|
|
43907
|
+
for (const key of NC_RULE_EDITOR_SECTION_ORDER) {
|
|
43908
|
+
if (key === "devices" && kind === "system") continue;
|
|
43909
|
+
sections.push({
|
|
43910
|
+
key,
|
|
43911
|
+
label: key === "conditions" ? spec.label : EDITOR_SECTION_LABELS[key]
|
|
43912
|
+
});
|
|
43913
|
+
}
|
|
43914
|
+
return sections;
|
|
43915
|
+
}
|
|
43916
|
+
//#endregion
|
|
43553
43917
|
//#region src/notification/schedule.ts
|
|
43554
43918
|
var WEEKDAY_TO_DAY = {
|
|
43555
43919
|
Sun: 0,
|
|
@@ -46682,6 +47046,7 @@ exports.LoginMethodContributionSchema = LoginMethodContributionSchema;
|
|
|
46682
47046
|
exports.LoginStageEnum = LoginStageEnum;
|
|
46683
47047
|
exports.MACRO_LABELS = MACRO_LABELS;
|
|
46684
47048
|
exports.MAX_CLIP_EVENT_IDS = MAX_CLIP_EVENT_IDS;
|
|
47049
|
+
exports.MAX_CLIP_LABELS = MAX_CLIP_LABELS;
|
|
46685
47050
|
exports.MAX_CONDITION_DEPTH = MAX_CONDITION_DEPTH;
|
|
46686
47051
|
exports.MAX_CONDITION_LEAVES = MAX_CONDITION_LEAVES;
|
|
46687
47052
|
exports.MAX_EXPRESSION_AST_NODES = MAX_EXPRESSION_AST_NODES;
|
|
@@ -46761,6 +47126,7 @@ exports.NC_AUDIO_HIT_PERCENT_MAX = NC_AUDIO_HIT_PERCENT_MAX;
|
|
|
46761
47126
|
exports.NC_AUDIO_HIT_PERCENT_MIN = NC_AUDIO_HIT_PERCENT_MIN;
|
|
46762
47127
|
exports.NC_AUDIO_SAMPLING_MAX_SEC = NC_AUDIO_SAMPLING_MAX_SEC;
|
|
46763
47128
|
exports.NC_AUDIO_SAMPLING_MIN_SEC = NC_AUDIO_SAMPLING_MIN_SEC;
|
|
47129
|
+
exports.NC_AUDIO_SEED = NC_AUDIO_SEED;
|
|
46764
47130
|
exports.NC_AUTHORABLE_SYSTEM_EVENT_KINDS = NC_AUTHORABLE_SYSTEM_EVENT_KINDS;
|
|
46765
47131
|
exports.NC_BASE_CONDITION_KEYS = NC_BASE_CONDITION_KEYS;
|
|
46766
47132
|
exports.NC_CONDITION_CATALOG = NC_CONDITION_CATALOG;
|
|
@@ -46772,7 +47138,12 @@ exports.NC_DEFAULT_SNOOZE_MINUTES = NC_DEFAULT_SNOOZE_MINUTES;
|
|
|
46772
47138
|
exports.NC_HISTORY_LIMIT_DEFAULT = NC_HISTORY_LIMIT_DEFAULT;
|
|
46773
47139
|
exports.NC_HISTORY_LIMIT_MAX = NC_HISTORY_LIMIT_MAX;
|
|
46774
47140
|
exports.NC_MAX_PER_TRACK_IMMEDIATE = NC_MAX_PER_TRACK_IMMEDIATE;
|
|
47141
|
+
exports.NC_OCCUPANCY_DEFAULTS = NC_OCCUPANCY_DEFAULTS;
|
|
47142
|
+
exports.NC_RULE_EDITOR_SECTION_ORDER = NC_RULE_EDITOR_SECTION_ORDER;
|
|
47143
|
+
exports.NC_RULE_KIND_SPECS = NC_RULE_KIND_SPECS;
|
|
47144
|
+
exports.NC_RULE_SECTIONS = NC_RULE_SECTIONS;
|
|
46775
47145
|
exports.NC_SNOOZE_MAX_MINUTES = NC_SNOOZE_MAX_MINUTES;
|
|
47146
|
+
exports.NC_SYSTEM_DELIVERY = NC_SYSTEM_DELIVERY;
|
|
46776
47147
|
exports.NC_SYSTEM_EVENT_FILTER_KEYS = NC_SYSTEM_EVENT_FILTER_KEYS;
|
|
46777
47148
|
exports.NC_TAXONOMY = NC_TAXONOMY;
|
|
46778
47149
|
exports.NativeCropBboxSchema = NativeCropBboxSchema;
|
|
@@ -47260,6 +47631,8 @@ exports.compileExpression = compileExpression;
|
|
|
47260
47631
|
exports.compileExpressionSafe = compileExpressionSafe;
|
|
47261
47632
|
exports.composeSwitchedOff = composeSwitchedOff;
|
|
47262
47633
|
exports.conditionDepth = conditionDepth;
|
|
47634
|
+
exports.conditionExclusionReason = conditionExclusionReason;
|
|
47635
|
+
exports.conditionVisibleForKind = conditionVisibleForKind;
|
|
47263
47636
|
exports.connectionTestCapability = connectionTestCapability;
|
|
47264
47637
|
exports.connectivityCapability = connectivityCapability;
|
|
47265
47638
|
exports.consumablesCapability = consumablesCapability;
|
|
@@ -47289,6 +47662,7 @@ exports.dayNightCapability = dayNightCapability;
|
|
|
47289
47662
|
exports.declarationOwnerNodeId = declarationOwnerNodeId;
|
|
47290
47663
|
exports.decodeVectorBase64 = decodeVectorBase64;
|
|
47291
47664
|
exports.decoderCapability = decoderCapability;
|
|
47665
|
+
exports.defaultDeliveryForSection = defaultDeliveryForSection;
|
|
47292
47666
|
exports.defaultDeviceFor = defaultDeviceFor;
|
|
47293
47667
|
exports.defineCustomActions = defineCustomActions;
|
|
47294
47668
|
exports.deriveBatteryPresence = deriveBatteryPresence;
|
|
@@ -47311,6 +47685,7 @@ exports.deviceSelectorMatches = deviceSelectorMatches;
|
|
|
47311
47685
|
exports.deviceStateCapability = deviceStateCapability;
|
|
47312
47686
|
exports.deviceStatusCapability = deviceStatusCapability;
|
|
47313
47687
|
exports.doorbellCapability = doorbellCapability;
|
|
47688
|
+
exports.droppedConditionsForKind = droppedConditionsForKind;
|
|
47314
47689
|
exports.egressTranscodeSharingKey = egressTranscodeSharingKey;
|
|
47315
47690
|
exports.egressTransportFromRequest = egressTransportFromRequest;
|
|
47316
47691
|
exports.embeddingEncoderCapability = embeddingEncoderCapability;
|
|
@@ -47362,6 +47737,7 @@ exports.invocationFromEncodeProfile = require_canonical_hash.invocationFromEncod
|
|
|
47362
47737
|
exports.isAgentOnlyPlacement = isAgentOnlyPlacement;
|
|
47363
47738
|
exports.isArrayOutputSchema = isArrayOutputSchema;
|
|
47364
47739
|
exports.isAudioLabelSelected = isAudioLabelSelected;
|
|
47740
|
+
exports.isAudioRule = isAudioRule;
|
|
47365
47741
|
exports.isBaseConditionKey = isBaseConditionKey;
|
|
47366
47742
|
exports.isBatteryPresenceFault = isBatteryPresenceFault;
|
|
47367
47743
|
exports.isCollectionArrayMethod = isCollectionArrayMethod;
|
|
@@ -47373,10 +47749,12 @@ exports.isEvent = require_sleep.isEvent;
|
|
|
47373
47749
|
exports.isIsolatedBuiltin = isIsolatedBuiltin;
|
|
47374
47750
|
exports.isNode = isNode;
|
|
47375
47751
|
exports.isObjectInput = isObjectInput;
|
|
47752
|
+
exports.isOccupancyRule = isOccupancyRule;
|
|
47376
47753
|
exports.isRestoredCap = isRestoredCap;
|
|
47377
47754
|
exports.isSameAddonId = isSameAddonId;
|
|
47378
47755
|
exports.isScheduleActive = isScheduleActive;
|
|
47379
47756
|
exports.isSoftwareDecode = require_canonical_hash.isSoftwareDecode;
|
|
47757
|
+
exports.isSystemDelivery = isSystemDelivery;
|
|
47380
47758
|
exports.isVoidInput = isVoidInput;
|
|
47381
47759
|
exports.jobKindSchema = jobKindSchema;
|
|
47382
47760
|
exports.kebabToCamel = kebabToCamel;
|
|
@@ -47440,6 +47818,7 @@ exports.parseJsonObject = require_sleep.parseJsonObject;
|
|
|
47440
47818
|
exports.parseJsonUnknown = require_sleep.parseJsonUnknown;
|
|
47441
47819
|
exports.parseProcStatus = parseProcStatus;
|
|
47442
47820
|
exports.parseProfileBrokerId = require_sleep.parseProfileBrokerId;
|
|
47821
|
+
exports.parseRuleSection = parseRuleSection;
|
|
47443
47822
|
exports.parseStreamParamsFormPatch = parseStreamParamsFormPatch;
|
|
47444
47823
|
exports.patchAudio = patchAudio;
|
|
47445
47824
|
exports.petFeederCapability = petFeederCapability;
|
|
@@ -47499,6 +47878,13 @@ exports.resolveScrubThumbnailGeometry = resolveScrubThumbnailGeometry;
|
|
|
47499
47878
|
exports.resolveVariantModelId = resolveVariantModelId;
|
|
47500
47879
|
exports.resolveViewableDeviceIds = resolveViewableDeviceIds;
|
|
47501
47880
|
exports.roleSpec = roleSpec;
|
|
47881
|
+
exports.ruleEditorSectionsForKind = ruleEditorSectionsForKind;
|
|
47882
|
+
exports.ruleKindOf = ruleKindOf;
|
|
47883
|
+
exports.ruleKindSpec = ruleKindSpec;
|
|
47884
|
+
exports.ruleMatchesSection = ruleMatchesSection;
|
|
47885
|
+
exports.ruleSection = ruleSection;
|
|
47886
|
+
exports.ruleSectionOf = ruleSectionOf;
|
|
47887
|
+
exports.ruleSeedForSection = ruleSeedForSection;
|
|
47502
47888
|
exports.runInferenceStep = runInferenceStep;
|
|
47503
47889
|
exports.runtimeDevices = runtimeDevices;
|
|
47504
47890
|
exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
|