@camstack/addon-post-analysis 1.2.611 → 1.2.613
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/{clip-model-registry-D1PS6-db.js → clip-model-registry-CM-m6e1l.js} +575 -41
- package/dist/{clip-model-registry-3TQUwS_R.mjs → clip-model-registry-D6tdLEFB.mjs} +558 -42
- package/dist/embedding-encoder/index.js +1 -1
- package/dist/embedding-encoder/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +559 -1180
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-D_6mbip_.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-PyXxg2Wg.mjs} +3 -3
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-mydSlNUz.mjs +26 -0
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BB2kgLY1.mjs +26 -0
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-Cx9AsA5q.mjs} +1 -1
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-CkwmHEi0.mjs} +8 -8
- package/dist/pipeline-analytics/{hostInit-Tp2cEslm.mjs → hostInit-RCMuxWxC.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +1298 -359
- package/dist/pipeline-analytics/index.mjs +1298 -359
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BX7AfZj6.mjs +0 -26
- package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DZcBAOjR.mjs +0 -26
|
@@ -5643,7 +5643,7 @@ var ZodIssueCode = {
|
|
|
5643
5643
|
var ZodFirstPartyTypeKind;
|
|
5644
5644
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5645
5645
|
//#endregion
|
|
5646
|
-
//#region ../types/dist/sleep-
|
|
5646
|
+
//#region ../types/dist/sleep-BSuCCFjf.mjs
|
|
5647
5647
|
/**
|
|
5648
5648
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5649
5649
|
* window to float samples (D455).
|
|
@@ -18541,7 +18541,19 @@ var DeviceHistorySubjectSchema = discriminatedUnion("kind", [object({
|
|
|
18541
18541
|
kind: literal("node"),
|
|
18542
18542
|
nodeId: string().min(1)
|
|
18543
18543
|
})]);
|
|
18544
|
+
/**
|
|
18545
|
+
* `enum` stores a STATE as the ordinal of its value in the series' value list
|
|
18546
|
+
* (`DeviceHistorySeriesInfo.values`, append-only, so an ordinal never changes
|
|
18547
|
+
* meaning); a rollup keeps the time spent in each state (`states`).
|
|
18548
|
+
*/
|
|
18544
18549
|
var DeviceHistoryKindSchema = _enum([
|
|
18550
|
+
"gauge",
|
|
18551
|
+
"counter",
|
|
18552
|
+
"boolean",
|
|
18553
|
+
"enum"
|
|
18554
|
+
]);
|
|
18555
|
+
/** What a PRODUCER may declare. `enum` is cap-only: its value list is the cap field's. */
|
|
18556
|
+
var DeviceHistoryProducerKindSchema = _enum([
|
|
18545
18557
|
"gauge",
|
|
18546
18558
|
"counter",
|
|
18547
18559
|
"boolean"
|
|
@@ -18578,7 +18590,13 @@ var SeriesInfoSchema = object({
|
|
|
18578
18590
|
/** `null` is unknown (a `unitFrom` series whose device does not state a unit right now), never a guess. */
|
|
18579
18591
|
unit: string().nullable(),
|
|
18580
18592
|
displayName: string(),
|
|
18581
|
-
source: _enum([
|
|
18593
|
+
source: _enum([
|
|
18594
|
+
"cap",
|
|
18595
|
+
"addon",
|
|
18596
|
+
"derived"
|
|
18597
|
+
]),
|
|
18598
|
+
/** `enum`: the value of each ordinal (index = ordinal); `null` for every other kind. */
|
|
18599
|
+
values: array(string()).readonly().nullable(),
|
|
18582
18600
|
firstTs: number(),
|
|
18583
18601
|
lastTs: number()
|
|
18584
18602
|
});
|
|
@@ -18592,17 +18610,31 @@ var QueryPointSchema = object({
|
|
|
18592
18610
|
twMean: number().nullable(),
|
|
18593
18611
|
min: number(),
|
|
18594
18612
|
max: number(),
|
|
18595
|
-
/** `null` is unknown, never zero (D393). */
|
|
18596
|
-
last: number().nullable()
|
|
18613
|
+
/** `null` is unknown, never zero (D393). For an `enum` series: the ordinal of {@link state}. */
|
|
18614
|
+
last: number().nullable(),
|
|
18615
|
+
/**
|
|
18616
|
+
* The increase over the point: a `counter`'s growth since the previous point
|
|
18617
|
+
* or bucket (a drop is a reset, counted from zero), and for
|
|
18618
|
+
* {@link DEVICE_HISTORY_ENERGY_KEY} the kWh used in the bucket. `null` for
|
|
18619
|
+
* every other kind, and when it cannot be known.
|
|
18620
|
+
*/
|
|
18621
|
+
delta: number().nullable(),
|
|
18622
|
+
/** `enum`: the state in force at the end of the point (the name of `last`); `null` otherwise. */
|
|
18623
|
+
state: string().nullable(),
|
|
18624
|
+
/** `enum` rollup: milliseconds spent in each state inside the bucket; `null` for raw points and other kinds. */
|
|
18625
|
+
states: record(string(), number()).nullable()
|
|
18597
18626
|
});
|
|
18598
18627
|
var QuerySeriesSchema = object({
|
|
18599
18628
|
scope: string(),
|
|
18600
18629
|
/** The last point STRICTLY BEFORE `from` in the chosen tier, so a step chart can start at the held value. */
|
|
18601
18630
|
before: object({
|
|
18602
18631
|
t: number(),
|
|
18603
|
-
value: number().nullable()
|
|
18632
|
+
value: number().nullable(),
|
|
18633
|
+
state: string().nullable()
|
|
18604
18634
|
}).nullable(),
|
|
18605
|
-
points: array(QueryPointSchema).readonly()
|
|
18635
|
+
points: array(QueryPointSchema).readonly(),
|
|
18636
|
+
/** A derived key: the stored key its points were computed from; `null` for a stored series. */
|
|
18637
|
+
derivedFrom: string().nullable()
|
|
18606
18638
|
});
|
|
18607
18639
|
/** The window part of a query, shared by the device and node forms. */
|
|
18608
18640
|
var QueryWindowShape = {
|
|
@@ -18618,6 +18650,23 @@ var QueryResultSchema = object({
|
|
|
18618
18650
|
series: array(QuerySeriesSchema).readonly(),
|
|
18619
18651
|
truncated: boolean()
|
|
18620
18652
|
});
|
|
18653
|
+
/** One read of a batch: a device's key or a node's key (exactly one subject). */
|
|
18654
|
+
var QueryManyItemSchema = union([object({
|
|
18655
|
+
deviceId: number().int(),
|
|
18656
|
+
key: string(),
|
|
18657
|
+
scope: string().optional()
|
|
18658
|
+
}), object({
|
|
18659
|
+
forNodeId: string().min(1),
|
|
18660
|
+
key: string(),
|
|
18661
|
+
scope: string().optional()
|
|
18662
|
+
})]);
|
|
18663
|
+
var QueryManyEntrySchema = discriminatedUnion("ok", [object({
|
|
18664
|
+
ok: literal(true),
|
|
18665
|
+
result: QueryResultSchema
|
|
18666
|
+
}), object({
|
|
18667
|
+
ok: literal(false),
|
|
18668
|
+
error: string()
|
|
18669
|
+
})]);
|
|
18621
18670
|
var TierStatusSchema = object({
|
|
18622
18671
|
tier: DeviceHistoryResolutionSchema,
|
|
18623
18672
|
/** `null` until the first background count answered. */
|
|
@@ -18673,16 +18722,22 @@ var DeviceHistoryStatusSchema = object({
|
|
|
18673
18722
|
lastRefreshAt: number().nullable()
|
|
18674
18723
|
})
|
|
18675
18724
|
});
|
|
18676
|
-
method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({
|
|
18725
|
+
method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({ forNodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), method(object({
|
|
18677
18726
|
deviceId: number().int(),
|
|
18678
18727
|
...QueryWindowShape
|
|
18679
18728
|
}), QueryResultSchema), method(object({
|
|
18680
|
-
|
|
18729
|
+
forNodeId: string().min(1),
|
|
18681
18730
|
...QueryWindowShape
|
|
18682
18731
|
}), QueryResultSchema, { auth: "admin" }), method(object({
|
|
18732
|
+
items: array(QueryManyItemSchema).min(1).max(24),
|
|
18733
|
+
from: QueryWindowShape.from,
|
|
18734
|
+
to: QueryWindowShape.to,
|
|
18735
|
+
resolution: QueryWindowShape.resolution,
|
|
18736
|
+
maxPoints: QueryWindowShape.maxPoints
|
|
18737
|
+
}), object({ results: array(QueryManyEntrySchema).readonly() }), { auth: "admin" }), method(object({
|
|
18683
18738
|
name: string().regex(/^[a-z0-9-]+$/),
|
|
18684
18739
|
subjectKind: _enum(["device", "node"]),
|
|
18685
|
-
kind:
|
|
18740
|
+
kind: DeviceHistoryProducerKindSchema,
|
|
18686
18741
|
unit: string().optional(),
|
|
18687
18742
|
displayName: string().min(1),
|
|
18688
18743
|
ingest: _enum(["points", "buckets"])
|
|
@@ -42007,14 +42062,106 @@ var LogEntrySchema = object({
|
|
|
42007
42062
|
meta: record(string(), unknown()).optional(),
|
|
42008
42063
|
tags: record(string(), string()).optional()
|
|
42009
42064
|
});
|
|
42010
|
-
|
|
42011
|
-
|
|
42065
|
+
/**
|
|
42066
|
+
* A history READ against one destination (D898).
|
|
42067
|
+
*
|
|
42068
|
+
* Every filter is applied by the PROVIDER, before the limit — a filter the
|
|
42069
|
+
* browser applied after the limit is what made a rare device's lines
|
|
42070
|
+
* unreachable behind a busy one's. `before` / `after` are cursors the provider
|
|
42071
|
+
* minted (opaque to everyone else): a file position for the rotated files, a
|
|
42072
|
+
* nanosecond timestamp for Loki.
|
|
42073
|
+
*
|
|
42074
|
+
* A read is BOUNDED by `budgetMs`: a filter that matches nothing on a 30-day
|
|
42075
|
+
* store answers `done: false` with the cursor it reached and the bytes it
|
|
42076
|
+
* scanned, and the caller decides whether to go on. That is what makes a long
|
|
42077
|
+
* scan show progress and stop when asked — `cancelRead` ends the slice in
|
|
42078
|
+
* flight, and not asking for the next slice ends the scan.
|
|
42079
|
+
*/
|
|
42080
|
+
var LogReadQuerySchema = object({
|
|
42081
|
+
/** Correlates `cancelRead`. Caller-chosen, unique per in-flight read. */
|
|
42082
|
+
requestId: string().min(1).max(64).optional(),
|
|
42083
|
+
/** The device the line is about (`tags.deviceId`, numeric). */
|
|
42084
|
+
deviceId: number().int().optional(),
|
|
42085
|
+
/**
|
|
42086
|
+
* The emitting addon — bare manifest id; `@<version>` / `::<sub>` suffixes
|
|
42087
|
+
* match. Not `addonId`: a cap router reads that name as "which provider".
|
|
42088
|
+
*/
|
|
42089
|
+
fromAddonId: string().min(1).max(200).optional(),
|
|
42090
|
+
/**
|
|
42091
|
+
* The emitting node: matches the agent that emitted the line, the node
|
|
42092
|
+
* itself, or a worker under it (`<agent>/<runner>`) — the `agentId`
|
|
42093
|
+
* semantics of `matchesLogTags`. Not `nodeId`: a cap router reads that
|
|
42094
|
+
* name as "which node's provider".
|
|
42095
|
+
*/
|
|
42096
|
+
fromNodeId: string().min(1).max(200).optional(),
|
|
42097
|
+
/** Any other tag, exact match (AND). */
|
|
42098
|
+
tags: record(string(), union([string(), number()])).optional(),
|
|
42099
|
+
/** Severity FLOOR: this level and above. */
|
|
42012
42100
|
level: LogLevelSchema.optional(),
|
|
42013
|
-
|
|
42014
|
-
|
|
42015
|
-
|
|
42016
|
-
|
|
42017
|
-
|
|
42101
|
+
/** Case-insensitive substring over message, scope, tag values and meta values. */
|
|
42102
|
+
text: string().min(1).max(200).optional(),
|
|
42103
|
+
/** Epoch ms, inclusive. */
|
|
42104
|
+
since: number().optional(),
|
|
42105
|
+
/** Epoch ms, inclusive. */
|
|
42106
|
+
until: number().optional(),
|
|
42107
|
+
/** Older than this cursor (exclusive). Absent with `after` absent ⇒ from the newest. */
|
|
42108
|
+
before: string().min(1).max(1024).optional(),
|
|
42109
|
+
/** Newer than this cursor (exclusive). */
|
|
42110
|
+
after: string().min(1).max(1024).optional(),
|
|
42111
|
+
limit: number().int().min(1).max(1e3).optional(),
|
|
42112
|
+
/** Wall-clock bound of this slice. The provider caps it. */
|
|
42113
|
+
budgetMs: number().int().min(50).max(1e4).optional()
|
|
42114
|
+
});
|
|
42115
|
+
var LogReadResultSchema = object({
|
|
42116
|
+
/** Newest first. */
|
|
42117
|
+
entries: array(object({
|
|
42118
|
+
/** `<bootId>.<seq>` minted by the emitting LogManager — the dedupe key. */
|
|
42119
|
+
id: string().optional(),
|
|
42120
|
+
/** Epoch ms. */
|
|
42121
|
+
timestamp: number(),
|
|
42122
|
+
level: LogLevelSchema,
|
|
42123
|
+
scope: string().optional(),
|
|
42124
|
+
message: string(),
|
|
42125
|
+
tags: record(string(), union([string(), number()])).optional(),
|
|
42126
|
+
meta: record(string(), unknown()).optional()
|
|
42127
|
+
})),
|
|
42128
|
+
/** Pass as `before` for the next older page; null when nothing older exists. */
|
|
42129
|
+
nextBefore: string().nullable(),
|
|
42130
|
+
/** Pass as `after` to read what arrived since; null when unknown. */
|
|
42131
|
+
nextAfter: string().nullable(),
|
|
42132
|
+
/** Bytes this slice read (files) or received (remote). Progress, not a promise. */
|
|
42133
|
+
scannedBytes: number().int().nonnegative(),
|
|
42134
|
+
/**
|
|
42135
|
+
* True when the scan in this direction reached the end of the store.
|
|
42136
|
+
* False with fewer than `limit` entries means the budget ran out first —
|
|
42137
|
+
* call again with `nextBefore` to go on.
|
|
42138
|
+
*/
|
|
42139
|
+
done: boolean(),
|
|
42140
|
+
/** True when `cancelRead` ended this slice early. */
|
|
42141
|
+
cancelled: boolean().optional()
|
|
42142
|
+
});
|
|
42143
|
+
var LogReadCapabilitiesSchema = object({
|
|
42144
|
+
/** False ⇒ this destination only ships lines (console, forwarder, an unconfigured Loki). */
|
|
42145
|
+
readable: boolean(),
|
|
42146
|
+
/** Why not, when `readable` is false — rendered next to the source. */
|
|
42147
|
+
reason: string().nullable(),
|
|
42148
|
+
/** Filters the provider applies itself. A false one is applied by nobody. */
|
|
42149
|
+
filters: object({
|
|
42150
|
+
deviceId: boolean(),
|
|
42151
|
+
addonId: boolean(),
|
|
42152
|
+
nodeId: boolean(),
|
|
42153
|
+
tags: boolean(),
|
|
42154
|
+
level: boolean(),
|
|
42155
|
+
text: boolean(),
|
|
42156
|
+
timeRange: boolean()
|
|
42157
|
+
}),
|
|
42158
|
+
/** How far back the store reaches, when the provider knows (days). */
|
|
42159
|
+
retentionDays: number().nullable()
|
|
42160
|
+
});
|
|
42161
|
+
method(LogEntrySchema, _void(), { kind: "mutation" }), optionalMethod(_void(), LogReadCapabilitiesSchema, { auth: "admin" }), optionalMethod(LogReadQuerySchema, LogReadResultSchema, { auth: "admin" }), optionalMethod(object({ requestId: string().min(1).max(64) }), object({ cancelled: boolean() }), {
|
|
42162
|
+
kind: "mutation",
|
|
42163
|
+
auth: "admin"
|
|
42164
|
+
});
|
|
42018
42165
|
/**
|
|
42019
42166
|
* `login-method` — collection cap through which auth addons contribute
|
|
42020
42167
|
* their pre-auth login surfaces to the login page. This is the SINGLE,
|
|
@@ -43763,9 +43910,11 @@ var alarmPanelCapability = {
|
|
|
43763
43910
|
*/
|
|
43764
43911
|
durability: "restored",
|
|
43765
43912
|
/**
|
|
43766
|
-
* History (D850):
|
|
43913
|
+
* History (D850): the panel's lifecycle state as an `enum` series —
|
|
43914
|
+
* change-only, no floor, so an `arming -> pending -> triggered` sequence of a
|
|
43915
|
+
* few seconds keeps every step. Who armed it stays in the events ledger.
|
|
43767
43916
|
*/
|
|
43768
|
-
history: "
|
|
43917
|
+
history: { fields: { state: { kind: "enum" } } },
|
|
43769
43918
|
/** Clock fields: written, but excluded from the compare that decides
|
|
43770
43919
|
* whether persisting is worth a SQLite commit. */
|
|
43771
43920
|
volatileStateFields: ["lastChangedAt"]
|
|
@@ -44687,6 +44836,33 @@ var NcRuleTargetSchema = object({
|
|
|
44687
44836
|
params: record(string(), unknown()).optional()
|
|
44688
44837
|
});
|
|
44689
44838
|
/**
|
|
44839
|
+
* WHAT THE NOTIFICATION'S PICTURE IS (D897) — the ONE media choice of a rule.
|
|
44840
|
+
*
|
|
44841
|
+
* Every mode starts from the same CLEAN source frame of the trigger moment
|
|
44842
|
+
* (keyFrame → sceneFrame → lastSceneFrame, narrowed to the trigger instant and
|
|
44843
|
+
* to the zone that fired the rule) and renders it once at send time:
|
|
44844
|
+
* - `scene-boxes` — the whole scene, the subject outlined thick in the accent
|
|
44845
|
+
* colour and every OTHER track visible at that instant outlined thin, each
|
|
44846
|
+
* labelled with class and confidence ("dog 87%").
|
|
44847
|
+
* - `crop` — the subject cut out of that frame around its box at that instant.
|
|
44848
|
+
* - `clean` — the whole scene with nothing drawn on it.
|
|
44849
|
+
* - `none` — no picture.
|
|
44850
|
+
*
|
|
44851
|
+
* A mode that cannot be honoured (no box at that instant, a photograph with no
|
|
44852
|
+
* tracked subject) ships `clean` and names the reason in the log, per camera.
|
|
44853
|
+
* It replaces the `attach` × `frame` × `zoneCrop` triple, which let one rule
|
|
44854
|
+
* ship a crop on one event and a boxed scene on the next depending on which
|
|
44855
|
+
* stored kind had landed.
|
|
44856
|
+
*/
|
|
44857
|
+
var NcMediaImageSchema = _enum([
|
|
44858
|
+
"scene-boxes",
|
|
44859
|
+
"crop",
|
|
44860
|
+
"clean",
|
|
44861
|
+
"none"
|
|
44862
|
+
]);
|
|
44863
|
+
/**
|
|
44864
|
+
* @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
|
|
44865
|
+
*
|
|
44690
44866
|
* Media attachment policy (P1 still-image subset).
|
|
44691
44867
|
* - `best` — the best AVAILABLE subject image at dispatch time (D-3).
|
|
44692
44868
|
* - `best-matching` — the media that explains WHY the rule fired: a rule
|
|
@@ -44700,6 +44876,8 @@ var NcRuleTargetSchema = object({
|
|
|
44700
44876
|
* - `none` — no attachment.
|
|
44701
44877
|
*/
|
|
44702
44878
|
/**
|
|
44879
|
+
* @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
|
|
44880
|
+
*
|
|
44703
44881
|
* WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
|
|
44704
44882
|
* conflate it with the selection strategy and betray the request: asking for
|
|
44705
44883
|
* the clean scene frame on an object-event owner used to start at
|
|
@@ -44746,16 +44924,29 @@ var NcLinkedCameraModeSchema = _enum(["mosaic", "each"]);
|
|
|
44746
44924
|
var NC_CLIP_PRE_ROLL_DEFAULT_SEC = 4;
|
|
44747
44925
|
var NC_CLIP_POST_ROLL_DEFAULT_SEC = 6;
|
|
44748
44926
|
var NcMediaPolicySchema = object({
|
|
44927
|
+
/**
|
|
44928
|
+
* The picture — see {@link NcMediaImageSchema}. Absent on a rule nobody has
|
|
44929
|
+
* saved since D897: `normalizeNcMediaPolicy` derives it from the legacy
|
|
44930
|
+
* triple below, at load and at every write, and the store keeps only this.
|
|
44931
|
+
*/
|
|
44932
|
+
image: NcMediaImageSchema.optional(),
|
|
44933
|
+
/**
|
|
44934
|
+
* Draw the zone that FIRED the rule on the picture (`scene-boxes` / `clean`;
|
|
44935
|
+
* a `crop` never shows it). Valid only on a rule whose trigger is a zone —
|
|
44936
|
+
* `conditions.zones` or an occupancy zone — and refused on save otherwise.
|
|
44937
|
+
* Replaces `zoneCrop`.
|
|
44938
|
+
*/
|
|
44939
|
+
showTriggerZone: boolean().optional(),
|
|
44940
|
+
/** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
|
|
44749
44941
|
attach: _enum([
|
|
44750
44942
|
"best",
|
|
44751
44943
|
"best-matching",
|
|
44752
44944
|
"keyFrame",
|
|
44753
44945
|
"none"
|
|
44754
|
-
]).
|
|
44755
|
-
/**
|
|
44946
|
+
]).optional(),
|
|
44947
|
+
/** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
|
|
44756
44948
|
frame: NcMediaFrameSchema.optional(),
|
|
44757
|
-
/**
|
|
44758
|
-
* "show me the ZONE", not the whole scene or the subject crop. */
|
|
44949
|
+
/** @deprecated D897 — folded into `image: 'clean'` + `showTriggerZone` on save. */
|
|
44759
44950
|
zoneCrop: boolean().optional(),
|
|
44760
44951
|
/**
|
|
44761
44952
|
* Also attach a short GIF cut from the stream broker's clip ring around the
|
|
@@ -44941,7 +45132,9 @@ var NcRuleInputSchema = object({
|
|
|
44941
45132
|
* targets.
|
|
44942
45133
|
*/
|
|
44943
45134
|
targetUsers: array(string()).optional(),
|
|
44944
|
-
|
|
45135
|
+
/** Absent = the kind's default picture (`resolveNcMediaImage`): the subject crop for a
|
|
45136
|
+
* detection, the clean scene for a sensor or a sound. Set explicitly on save (D897). */
|
|
45137
|
+
media: NcMediaPolicySchema.default({}),
|
|
44945
45138
|
throttle: NcThrottleSchema.default({
|
|
44946
45139
|
cooldownSec: 60,
|
|
44947
45140
|
scope: "rule-device"
|
|
@@ -46476,13 +46669,37 @@ var NcAlarmModeOpeningsSchema = object({
|
|
|
46476
46669
|
/** Covered devices whose state could not be read (D49): neither open nor closed. */
|
|
46477
46670
|
unknown: array(number().int())
|
|
46478
46671
|
});
|
|
46672
|
+
/**
|
|
46673
|
+
* One alarm INPUT — a (rule, device) pair — the operator bypassed until the
|
|
46674
|
+
* next disarm ("Bypass this input until disarm" on a trigger notification, or
|
|
46675
|
+
* `nc.bypassAlarmInput`). Reported so an armed alarm with a silenced input
|
|
46676
|
+
* never looks fully armed (D62: off must never look like broken).
|
|
46677
|
+
*/
|
|
46678
|
+
var NcAlarmInputBypassViewSchema = object({
|
|
46679
|
+
ruleId: string(),
|
|
46680
|
+
/** The rule's current name (its frozen name when the rule is gone). */
|
|
46681
|
+
ruleName: string(),
|
|
46682
|
+
/** The input: the sensor of the match, else its camera. */
|
|
46683
|
+
deviceId: number().int(),
|
|
46684
|
+
/** The input's current name. */
|
|
46685
|
+
name: string(),
|
|
46686
|
+
/** When it was bypassed (ms epoch). */
|
|
46687
|
+
since: number(),
|
|
46688
|
+
/** Triggers from this input dropped since. */
|
|
46689
|
+
dropped: number().int().min(0)
|
|
46690
|
+
});
|
|
46479
46691
|
var NcAlarmLiveSchema = object({
|
|
46480
46692
|
state: AlarmStateSchema,
|
|
46481
46693
|
/** The mode being armed into (exit delay) or held; null when disarmed. */
|
|
46482
46694
|
targetMode: AlarmArmModeSchema.nullable(),
|
|
46483
46695
|
availableModes: array(AlarmArmModeSchema),
|
|
46484
46696
|
openings: array(NcAlarmModeOpeningsSchema),
|
|
46485
|
-
exclusions: array(NcAlarmExclusionViewSchema)
|
|
46697
|
+
exclusions: array(NcAlarmExclusionViewSchema),
|
|
46698
|
+
/**
|
|
46699
|
+
* Inputs bypassed for the rest of this arm session; cleared on disarm.
|
|
46700
|
+
* Defaulted so an older hub answer still parses (as "none known").
|
|
46701
|
+
*/
|
|
46702
|
+
bypassedInputs: array(NcAlarmInputBypassViewSchema).default([])
|
|
46486
46703
|
});
|
|
46487
46704
|
var NcAlarmConfigSchema = object({
|
|
46488
46705
|
/**
|
|
@@ -58392,9 +58609,11 @@ var connectivityCapability = {
|
|
|
58392
58609
|
*/
|
|
58393
58610
|
durability: "restored",
|
|
58394
58611
|
/**
|
|
58395
|
-
* History (D850):
|
|
58612
|
+
* History (D850): `connected` as a boolean series — change-only, no floor. It
|
|
58613
|
+
* is the upstream entity's own link (a HA connectivity sensor), not the
|
|
58614
|
+
* device's reachability, which stays `device-status.online`.
|
|
58396
58615
|
*/
|
|
58397
|
-
history: "
|
|
58616
|
+
history: { fields: { connected: { kind: "boolean" } } },
|
|
58398
58617
|
/** Clock fields: written, but excluded from the compare that decides
|
|
58399
58618
|
* whether persisting is worth a SQLite commit. */
|
|
58400
58619
|
volatileStateFields: ["lastChangedAt"]
|
|
@@ -59240,11 +59459,22 @@ var dishwasherCapability = {
|
|
|
59240
59459
|
},
|
|
59241
59460
|
runtimeState: DishwasherStatusSchema,
|
|
59242
59461
|
durability: "session",
|
|
59243
|
-
history: { fields: {
|
|
59244
|
-
|
|
59245
|
-
|
|
59246
|
-
|
|
59247
|
-
|
|
59462
|
+
history: { fields: {
|
|
59463
|
+
progressPercent: {
|
|
59464
|
+
kind: "gauge",
|
|
59465
|
+
unit: "%",
|
|
59466
|
+
deadband: 2
|
|
59467
|
+
},
|
|
59468
|
+
state: { kind: "enum" },
|
|
59469
|
+
operationState: { kind: "enum" },
|
|
59470
|
+
remainingSeconds: {
|
|
59471
|
+
kind: "gauge",
|
|
59472
|
+
unit: "s",
|
|
59473
|
+
minIntervalMs: 6e4
|
|
59474
|
+
},
|
|
59475
|
+
doorOpen: { kind: "boolean" },
|
|
59476
|
+
powerOn: { kind: "boolean" }
|
|
59477
|
+
} }
|
|
59248
59478
|
};
|
|
59249
59479
|
var DoorbellStatusSchema = object({
|
|
59250
59480
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
@@ -59361,9 +59591,15 @@ var enumSensorCapability = {
|
|
|
59361
59591
|
*/
|
|
59362
59592
|
durability: "restored",
|
|
59363
59593
|
/**
|
|
59364
|
-
* History (D850):
|
|
59594
|
+
* History (D850): the value as an `enum` series (an appliance's program or
|
|
59595
|
+
* operation state, an HVAC action). The option set is per device, so the
|
|
59596
|
+
* value list is LEARNED as values are first seen (bounded). A sensor with a
|
|
59597
|
+
* `format` carries a timestamp, not a state, and is not recorded.
|
|
59365
59598
|
*/
|
|
59366
|
-
history:
|
|
59599
|
+
history: { fields: { value: {
|
|
59600
|
+
kind: "enum",
|
|
59601
|
+
skipWhenSet: "format"
|
|
59602
|
+
} } },
|
|
59367
59603
|
/** Clock fields: written, but excluded from the compare that decides
|
|
59368
59604
|
* whether persisting is worth a SQLite commit. */
|
|
59369
59605
|
volatileStateFields: ["lastFetchedAt"]
|
|
@@ -61397,9 +61633,10 @@ var lockControlCapability = {
|
|
|
61397
61633
|
*/
|
|
61398
61634
|
durability: "restored",
|
|
61399
61635
|
/**
|
|
61400
|
-
* History (D850):
|
|
61636
|
+
* History (D850): the lock's state as an `enum` series — change-only, no
|
|
61637
|
+
* floor: a jam or an unlock lasting seconds is the edge an operator looks for.
|
|
61401
61638
|
*/
|
|
61402
|
-
history: "
|
|
61639
|
+
history: { fields: { state: { kind: "enum" } } },
|
|
61403
61640
|
/** Clock fields: written, but excluded from the compare that decides
|
|
61404
61641
|
* whether persisting is worth a SQLite commit. */
|
|
61405
61642
|
volatileStateFields: ["lastChangedAt"]
|
|
@@ -61573,9 +61810,18 @@ var mediaPlayerCapability = {
|
|
|
61573
61810
|
*/
|
|
61574
61811
|
durability: "session",
|
|
61575
61812
|
/**
|
|
61576
|
-
* History (D850):
|
|
61813
|
+
* History (D850): volume (a level an operator or an automation sets; the
|
|
61814
|
+
* default 10 s floor folds a slider drag into its end value) and mute.
|
|
61815
|
+
* `positionMs` is not recorded: it moves continuously while playing.
|
|
61577
61816
|
*/
|
|
61578
|
-
history:
|
|
61817
|
+
history: { fields: {
|
|
61818
|
+
volumeLevel: {
|
|
61819
|
+
kind: "gauge",
|
|
61820
|
+
unit: "%",
|
|
61821
|
+
deadband: 1
|
|
61822
|
+
},
|
|
61823
|
+
isMuted: { kind: "boolean" }
|
|
61824
|
+
} }
|
|
61579
61825
|
};
|
|
61580
61826
|
/**
|
|
61581
61827
|
* mesh-network — collection cap for mesh-VPN providers.
|
|
@@ -63778,9 +64024,24 @@ var NpuInfoSchema = object({
|
|
|
63778
64024
|
name: string().optional(),
|
|
63779
64025
|
generation: _enum(["xdna1", "xdna2"]).optional()
|
|
63780
64026
|
});
|
|
64027
|
+
var CoralBusSchema = _enum(["usb", "pci"]);
|
|
63781
64028
|
var CoralInfoSchema = object({
|
|
63782
64029
|
type: literal("coral-edgetpu"),
|
|
63783
|
-
bus
|
|
64030
|
+
/** Legacy single-bus report (older nodes) — read via `coralUsableUnits`. */
|
|
64031
|
+
bus: string().optional(),
|
|
64032
|
+
/** Legacy USB unit count (older nodes) — read via `coralUsableUnits`. */
|
|
64033
|
+
count: number().int().nonnegative().optional(),
|
|
64034
|
+
/** Usable units per bus — each one is its own `edgetpu:<bus>[:N]` device. */
|
|
64035
|
+
units: array(object({
|
|
64036
|
+
bus: CoralBusSchema,
|
|
64037
|
+
count: number().int().nonnegative()
|
|
64038
|
+
})).readonly().optional(),
|
|
64039
|
+
/** Present-but-unusable units, each with its typed reason (never "absent"). */
|
|
64040
|
+
unavailable: array(object({
|
|
64041
|
+
bus: CoralBusSchema,
|
|
64042
|
+
count: number().int().nonnegative(),
|
|
64043
|
+
reason: _enum(["driver-missing", "device-not-accessible"])
|
|
64044
|
+
})).readonly().optional()
|
|
63784
64045
|
});
|
|
63785
64046
|
var HardwareInfoSchema = object({
|
|
63786
64047
|
platform: HardwarePlatformSchema,
|
|
@@ -66977,9 +67238,29 @@ var streamParamsCapability = {
|
|
|
66977
67238
|
*/
|
|
66978
67239
|
durability: "restored",
|
|
66979
67240
|
/**
|
|
66980
|
-
* History (D850):
|
|
67241
|
+
* History (D850): the configured bitrate and frame rate of the main and sub
|
|
67242
|
+
* profiles. Configuration, so change-only on the default floor: a point is an
|
|
67243
|
+
* operator's (or a tuner's) edit, which is exactly what a chart of a stream's
|
|
67244
|
+
* quality over time must show.
|
|
66981
67245
|
*/
|
|
66982
|
-
history:
|
|
67246
|
+
history: { fields: {
|
|
67247
|
+
"main.bitrate": {
|
|
67248
|
+
kind: "gauge",
|
|
67249
|
+
unit: "kbps"
|
|
67250
|
+
},
|
|
67251
|
+
"main.framerate": {
|
|
67252
|
+
kind: "gauge",
|
|
67253
|
+
unit: "fps"
|
|
67254
|
+
},
|
|
67255
|
+
"sub.bitrate": {
|
|
67256
|
+
kind: "gauge",
|
|
67257
|
+
unit: "kbps"
|
|
67258
|
+
},
|
|
67259
|
+
"sub.framerate": {
|
|
67260
|
+
kind: "gauge",
|
|
67261
|
+
unit: "fps"
|
|
67262
|
+
}
|
|
67263
|
+
} },
|
|
66983
67264
|
/** Clock fields: written, but excluded from the compare that decides
|
|
66984
67265
|
* whether persisting is worth a SQLite commit. */
|
|
66985
67266
|
volatileStateFields: ["lastFetchedAt"]
|
|
@@ -70210,6 +70491,15 @@ var BaseDevice = class {
|
|
|
70210
70491
|
* Drivers can use the `getProbeFlags()` helper to read the flag bag
|
|
70211
70492
|
* with a typed cast.
|
|
70212
70493
|
*
|
|
70494
|
+
* Answer what you KNOW. A plain array is read as the complete list only
|
|
70495
|
+
* while this device is `online` and probed; return
|
|
70496
|
+
* `accessoryChildrenUnknown(reason)` whenever you cannot know the list right
|
|
70497
|
+
* now (no credentials, parent not connected, a failed or partial read) —
|
|
70498
|
+
* the kernel then deletes nothing. Return `accessoryChildrenComplete(list)`
|
|
70499
|
+
* to say "connected, and this is the complete list" explicitly. A shrink is
|
|
70500
|
+
* deleted only after a second agreeing complete read on a later probe (D49;
|
|
70501
|
+
* `packages/system/src/kernel/moleculer/accessory-prune-gate.ts`).
|
|
70502
|
+
*
|
|
70213
70503
|
* Default: no children.
|
|
70214
70504
|
*/
|
|
70215
70505
|
getAccessoryChildren() {
|
|
@@ -73858,7 +74148,19 @@ Object.freeze({
|
|
|
73858
74148
|
addonId: null,
|
|
73859
74149
|
access: "view"
|
|
73860
74150
|
},
|
|
73861
|
-
"logDestination.
|
|
74151
|
+
"logDestination.cancelRead": {
|
|
74152
|
+
capName: "log-destination",
|
|
74153
|
+
capScope: "system",
|
|
74154
|
+
addonId: null,
|
|
74155
|
+
access: "create"
|
|
74156
|
+
},
|
|
74157
|
+
"logDestination.describeRead": {
|
|
74158
|
+
capName: "log-destination",
|
|
74159
|
+
capScope: "system",
|
|
74160
|
+
addonId: null,
|
|
74161
|
+
access: "view"
|
|
74162
|
+
},
|
|
74163
|
+
"logDestination.read": {
|
|
73862
74164
|
capName: "log-destination",
|
|
73863
74165
|
capScope: "system",
|
|
73864
74166
|
addonId: null,
|
|
@@ -79865,6 +80167,11 @@ Object.freeze({
|
|
|
79865
80167
|
form: "single",
|
|
79866
80168
|
optional: false
|
|
79867
80169
|
}],
|
|
80170
|
+
"logDestination.read": [{
|
|
80171
|
+
name: "deviceId",
|
|
80172
|
+
form: "single",
|
|
80173
|
+
optional: true
|
|
80174
|
+
}],
|
|
79868
80175
|
"mediaPlayer.getStatus": [{
|
|
79869
80176
|
name: "deviceId",
|
|
79870
80177
|
form: "single",
|
|
@@ -82114,6 +82421,123 @@ function isSystemRuleKind(kind) {
|
|
|
82114
82421
|
function systemFamilyOfKind(kind) {
|
|
82115
82422
|
return isSystemEventFamily(kind) ? kind : void 0;
|
|
82116
82423
|
}
|
|
82424
|
+
/**
|
|
82425
|
+
* Reasons, written once. Each names the SUBJECT FIELD the engine reads and
|
|
82426
|
+
* finds absent — that is what makes the exclusion checkable against the engine
|
|
82427
|
+
* rather than an opinion about tidiness.
|
|
82428
|
+
*/
|
|
82429
|
+
var NO_SENSOR_KIND = "An occupancy edge is not a sensor event: it carries no sensor kind, so this condition can never match one.";
|
|
82430
|
+
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.";
|
|
82431
|
+
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.";
|
|
82432
|
+
var OCCUPANCY_SOURCE = "An occupancy edge is always produced by the pipeline, so any other source can never match and “pipeline” narrows nothing.";
|
|
82433
|
+
var AUDIO_SOURCE = "A confirmed sound window is always stamped as an audio subject, so any other source can never match.";
|
|
82434
|
+
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.";
|
|
82435
|
+
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.";
|
|
82436
|
+
var SOUND_NO_GEOMETRY = "A sound has no position in the frame, so a zone or a drawn polygon can never match it.";
|
|
82437
|
+
var NC_RULE_KIND_SPECS = [
|
|
82438
|
+
{
|
|
82439
|
+
kind: "detection",
|
|
82440
|
+
label: "Conditions",
|
|
82441
|
+
excluded: { audio: "A detection rule fires on what the camera SAW. Sounds are a Sound rule of their own — adding one here turned the rule into a sound rule and dropped every detection condition." },
|
|
82442
|
+
editable: true,
|
|
82443
|
+
carriesMedia: true,
|
|
82444
|
+
carriesSubjectCrop: true
|
|
82445
|
+
},
|
|
82446
|
+
{
|
|
82447
|
+
kind: "sensor",
|
|
82448
|
+
label: "Conditions",
|
|
82449
|
+
/** `occupancy` is still offered here: authoring it converts a sensor rule into an occupancy rule. */
|
|
82450
|
+
excluded: {},
|
|
82451
|
+
editable: true,
|
|
82452
|
+
carriesMedia: true,
|
|
82453
|
+
carriesSubjectCrop: true,
|
|
82454
|
+
blurb: "A doorbell press or a linked sensor changing state. The picture comes from the camera the sensor is attributed to."
|
|
82455
|
+
},
|
|
82456
|
+
{
|
|
82457
|
+
kind: "occupancy",
|
|
82458
|
+
label: "Occupancy",
|
|
82459
|
+
discriminator: "occupancy",
|
|
82460
|
+
excluded: {
|
|
82461
|
+
sensorKinds: NO_SENSOR_KIND,
|
|
82462
|
+
eventTypeTokens: NO_EVENT_TOKEN,
|
|
82463
|
+
sensorTransition: NO_SENSOR_EDGE,
|
|
82464
|
+
source: OCCUPANCY_SOURCE
|
|
82465
|
+
},
|
|
82466
|
+
editable: true,
|
|
82467
|
+
carriesMedia: true,
|
|
82468
|
+
carriesSubjectCrop: true,
|
|
82469
|
+
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."
|
|
82470
|
+
},
|
|
82471
|
+
{
|
|
82472
|
+
kind: "sound",
|
|
82473
|
+
label: "Sound",
|
|
82474
|
+
discriminator: "audio",
|
|
82475
|
+
excluded: {
|
|
82476
|
+
classes: SOUND_NOT_A_PICTURE,
|
|
82477
|
+
classesExclude: SOUND_NOT_A_PICTURE,
|
|
82478
|
+
minConfidence: SOUND_NO_CONFIDENCE,
|
|
82479
|
+
zones: SOUND_NO_GEOMETRY,
|
|
82480
|
+
zonesExclude: SOUND_NO_GEOMETRY,
|
|
82481
|
+
customZones: SOUND_NO_GEOMETRY,
|
|
82482
|
+
crossing: SOUND_NO_GEOMETRY,
|
|
82483
|
+
labelEquals: SOUND_NOT_A_PICTURE,
|
|
82484
|
+
identities: SOUND_NOT_A_PICTURE,
|
|
82485
|
+
identitiesExclude: SOUND_NOT_A_PICTURE,
|
|
82486
|
+
plates: SOUND_NOT_A_PICTURE,
|
|
82487
|
+
source: AUDIO_SOURCE
|
|
82488
|
+
},
|
|
82489
|
+
editable: true,
|
|
82490
|
+
carriesMedia: true,
|
|
82491
|
+
carriesSubjectCrop: false,
|
|
82492
|
+
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.",
|
|
82493
|
+
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."
|
|
82494
|
+
},
|
|
82495
|
+
{
|
|
82496
|
+
kind: "device-events",
|
|
82497
|
+
label: "Device events",
|
|
82498
|
+
discriminator: "systemEvent",
|
|
82499
|
+
excluded: {},
|
|
82500
|
+
editable: true,
|
|
82501
|
+
carriesMedia: false,
|
|
82502
|
+
carriesSubjectCrop: false,
|
|
82503
|
+
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."
|
|
82504
|
+
},
|
|
82505
|
+
{
|
|
82506
|
+
kind: "system",
|
|
82507
|
+
label: "System events",
|
|
82508
|
+
discriminator: "systemEvent",
|
|
82509
|
+
excluded: {},
|
|
82510
|
+
editable: true,
|
|
82511
|
+
carriesMedia: false,
|
|
82512
|
+
carriesSubjectCrop: false,
|
|
82513
|
+
blurb: "The installation itself: a node leaving, an addon crash-looping, an update available or installed, a backup or an export finishing."
|
|
82514
|
+
},
|
|
82515
|
+
{
|
|
82516
|
+
kind: "alarm",
|
|
82517
|
+
label: "Alarm",
|
|
82518
|
+
discriminator: "systemEvent",
|
|
82519
|
+
excluded: {},
|
|
82520
|
+
editable: true,
|
|
82521
|
+
carriesMedia: false,
|
|
82522
|
+
carriesSubjectCrop: false,
|
|
82523
|
+
blurb: "The alarm panel: refused, arming, armed, entry delay, triggered, re-armed, sensor bypass, disarmed.",
|
|
82524
|
+
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."
|
|
82525
|
+
},
|
|
82526
|
+
{
|
|
82527
|
+
kind: "mixed",
|
|
82528
|
+
label: "To recreate",
|
|
82529
|
+
discriminator: "systemEvent",
|
|
82530
|
+
excluded: {},
|
|
82531
|
+
editable: false,
|
|
82532
|
+
carriesMedia: false,
|
|
82533
|
+
carriesSubjectCrop: false,
|
|
82534
|
+
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."
|
|
82535
|
+
}
|
|
82536
|
+
];
|
|
82537
|
+
/** The spec for a kind. Total by construction — every member has an entry. */
|
|
82538
|
+
function ruleKindSpec(kind) {
|
|
82539
|
+
return NC_RULE_KIND_SPECS.find((s) => s.kind === kind) ?? NC_RULE_KIND_SPECS[0];
|
|
82540
|
+
}
|
|
82117
82541
|
/** The delivery a system rule rides — named once, compared everywhere. */
|
|
82118
82542
|
var NC_SYSTEM_DELIVERY = "system-event";
|
|
82119
82543
|
/**
|
|
@@ -82231,6 +82655,98 @@ function systemRuleKindOf(condition) {
|
|
|
82231
82655
|
return verdict.kind === "family" ? verdict.family : "mixed";
|
|
82232
82656
|
}
|
|
82233
82657
|
NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
|
|
82658
|
+
/** Every mode, in the order an editor offers them. */
|
|
82659
|
+
var NC_MEDIA_IMAGE_MODES = [
|
|
82660
|
+
"scene-boxes",
|
|
82661
|
+
"crop",
|
|
82662
|
+
"clean",
|
|
82663
|
+
"none"
|
|
82664
|
+
];
|
|
82665
|
+
/**
|
|
82666
|
+
* The modes a rule of this kind can honour. A kind that carries no media gets
|
|
82667
|
+
* none (its row ships text, or — an alarm — its SOURCE rule's picture); a kind
|
|
82668
|
+
* whose subject has no region of the frame (a sound) is never offered `crop`.
|
|
82669
|
+
*/
|
|
82670
|
+
function imageModesForKind(kind) {
|
|
82671
|
+
const spec = ruleKindSpec(kind);
|
|
82672
|
+
if (!spec.carriesMedia) return [];
|
|
82673
|
+
return spec.carriesSubjectCrop ? NC_MEDIA_IMAGE_MODES : NC_MEDIA_IMAGE_MODES.filter((mode) => mode !== "crop");
|
|
82674
|
+
}
|
|
82675
|
+
/**
|
|
82676
|
+
* The zone ids that FIRE a rule: its `zones` condition, or an occupancy rule's
|
|
82677
|
+
* own scoped zone. Empty when the trigger is not a zone — and then
|
|
82678
|
+
* `showTriggerZone` has nothing to draw and is refused on save.
|
|
82679
|
+
*/
|
|
82680
|
+
function ruleTriggerZoneIds(conditions) {
|
|
82681
|
+
if (conditions.zones !== void 0) return conditions.zones.ids;
|
|
82682
|
+
const zoneId = conditions.occupancy?.zoneId;
|
|
82683
|
+
return zoneId !== void 0 ? [zoneId] : [];
|
|
82684
|
+
}
|
|
82685
|
+
/**
|
|
82686
|
+
* What the legacy triple MEANT, as a mode. `zoneCrop` forced the clean
|
|
82687
|
+
* keyFrame ladder and dropped `frame`, so it is `clean` whatever else was set;
|
|
82688
|
+
* `frame` decided over `attach` when present; `keyFrame` was the clean scene;
|
|
82689
|
+
* every other still (`best`, `best-matching`, the default) was the subject.
|
|
82690
|
+
*/
|
|
82691
|
+
function legacyImageMode(media) {
|
|
82692
|
+
if (media.attach === "none") return "none";
|
|
82693
|
+
if (media.zoneCrop === true) return "clean";
|
|
82694
|
+
if (media.frame === "full") return "clean";
|
|
82695
|
+
if (media.frame === "boxed") return "scene-boxes";
|
|
82696
|
+
if (media.frame === "cropped") return "crop";
|
|
82697
|
+
if (media.attach === "keyFrame") return "clean";
|
|
82698
|
+
return "crop";
|
|
82699
|
+
}
|
|
82700
|
+
/** A mode the kind cannot honour, mapped to the nearest one it can. */
|
|
82701
|
+
function clampToKind(mode, kind) {
|
|
82702
|
+
const offered = imageModesForKind(kind);
|
|
82703
|
+
if (offered.length === 0 || offered.includes(mode)) return mode;
|
|
82704
|
+
return mode === "crop" ? "clean" : mode;
|
|
82705
|
+
}
|
|
82706
|
+
/**
|
|
82707
|
+
* The mode a rule's picture is rendered in. `image` when stored; else what the
|
|
82708
|
+
* legacy triple meant — and, for a SENSOR rule written before D897, `clean`
|
|
82709
|
+
* whatever it stored (even `attach: 'none'`), because its stored triple was
|
|
82710
|
+
* ignored and one plain snapshot always shipped (operator ruling, 2026-10-01):
|
|
82711
|
+
* the migration keeps what the rule actually DID. Clamped to what the kind can
|
|
82712
|
+
* honour.
|
|
82713
|
+
*/
|
|
82714
|
+
function resolveNcMediaImage(media, kind) {
|
|
82715
|
+
if (media.image !== void 0) return clampToKind(media.image, kind);
|
|
82716
|
+
if (kind === "sensor") return "clean";
|
|
82717
|
+
return clampToKind(legacyImageMode(media), kind);
|
|
82718
|
+
}
|
|
82719
|
+
/**
|
|
82720
|
+
* The stored shape of a media policy: `image` set, the legacy triple gone.
|
|
82721
|
+
* `showTriggerZone` survives only where it can be drawn — a zone trigger and a
|
|
82722
|
+
* mode other than `crop`/`none`; a legacy `zoneCrop` on a zone rule becomes it.
|
|
82723
|
+
* Every other field (gif, clip, rolls, speed, profile, linked cameras) is
|
|
82724
|
+
* carried through untouched. Pure; never throws.
|
|
82725
|
+
*/
|
|
82726
|
+
function normalizeNcMediaPolicy(media, rule) {
|
|
82727
|
+
const image = resolveNcMediaImage(media, ruleKindOf(rule));
|
|
82728
|
+
const { attach: _attach, frame: _frame, zoneCrop, showTriggerZone, image: _image, ...rest } = media;
|
|
82729
|
+
const drawable = (showTriggerZone === true || media.image === void 0 && zoneCrop === true) && image !== "crop" && image !== "none" && ruleTriggerZoneIds(rule.conditions).length > 0;
|
|
82730
|
+
return {
|
|
82731
|
+
...rest,
|
|
82732
|
+
image,
|
|
82733
|
+
...drawable ? { showTriggerZone: true } : {}
|
|
82734
|
+
};
|
|
82735
|
+
}
|
|
82736
|
+
/**
|
|
82737
|
+
* Why a media policy cannot be SAVED on this rule, or null. Server-side and
|
|
82738
|
+
* editor alike: `showTriggerZone` on a rule whose trigger is not a zone, and a
|
|
82739
|
+
* mode the rule's kind cannot honour.
|
|
82740
|
+
*/
|
|
82741
|
+
function ncMediaPolicyError(media, rule) {
|
|
82742
|
+
const kind = ruleKindOf(rule);
|
|
82743
|
+
if (media.image !== void 0) {
|
|
82744
|
+
const offered = imageModesForKind(kind);
|
|
82745
|
+
if (offered.length > 0 && !offered.includes(media.image)) return `media.image '${media.image}' is not available for a ${kind} rule (offered: ${offered.join(", ")})`;
|
|
82746
|
+
}
|
|
82747
|
+
if (media.showTriggerZone === true && ruleTriggerZoneIds(rule.conditions).length === 0) return "media.showTriggerZone needs a rule triggered by a zone (a zones condition or an occupancy zone)";
|
|
82748
|
+
return null;
|
|
82749
|
+
}
|
|
82234
82750
|
var WEEKDAY_TO_DAY = {
|
|
82235
82751
|
Sun: 0,
|
|
82236
82752
|
Mon: 1,
|
|
@@ -87278,12 +87794,24 @@ Object.defineProperty(exports, "memoizePinnedFfmpeg", {
|
|
|
87278
87794
|
return memoizePinnedFfmpeg;
|
|
87279
87795
|
}
|
|
87280
87796
|
});
|
|
87797
|
+
Object.defineProperty(exports, "ncMediaPolicyError", {
|
|
87798
|
+
enumerable: true,
|
|
87799
|
+
get: function() {
|
|
87800
|
+
return ncMediaPolicyError;
|
|
87801
|
+
}
|
|
87802
|
+
});
|
|
87281
87803
|
Object.defineProperty(exports, "nodePin", {
|
|
87282
87804
|
enumerable: true,
|
|
87283
87805
|
get: function() {
|
|
87284
87806
|
return nodePin;
|
|
87285
87807
|
}
|
|
87286
87808
|
});
|
|
87809
|
+
Object.defineProperty(exports, "normalizeNcMediaPolicy", {
|
|
87810
|
+
enumerable: true,
|
|
87811
|
+
get: function() {
|
|
87812
|
+
return normalizeNcMediaPolicy;
|
|
87813
|
+
}
|
|
87814
|
+
});
|
|
87287
87815
|
Object.defineProperty(exports, "normalizeNodeId", {
|
|
87288
87816
|
enumerable: true,
|
|
87289
87817
|
get: function() {
|
|
@@ -87416,6 +87944,12 @@ Object.defineProperty(exports, "resolveModeNotifyPolicy", {
|
|
|
87416
87944
|
return resolveModeNotifyPolicy;
|
|
87417
87945
|
}
|
|
87418
87946
|
});
|
|
87947
|
+
Object.defineProperty(exports, "resolveNcMediaImage", {
|
|
87948
|
+
enumerable: true,
|
|
87949
|
+
get: function() {
|
|
87950
|
+
return resolveNcMediaImage;
|
|
87951
|
+
}
|
|
87952
|
+
});
|
|
87419
87953
|
Object.defineProperty(exports, "resolvePoolMemoryPolicy", {
|
|
87420
87954
|
enumerable: true,
|
|
87421
87955
|
get: function() {
|