@camstack/addon-post-analysis 1.2.611 → 1.2.612

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.
Files changed (15) hide show
  1. package/dist/{clip-model-registry-D1PS6-db.js → clip-model-registry-C7WMvftu.js} +559 -40
  2. package/dist/{clip-model-registry-3TQUwS_R.mjs → clip-model-registry-JH4cTI06.mjs} +542 -41
  3. package/dist/embedding-encoder/index.js +1 -1
  4. package/dist/embedding-encoder/index.mjs +1 -1
  5. package/dist/pipeline-analytics/_stub.js +2 -2
  6. 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-DQE_Wu6_.mjs} +3 -3
  7. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-7dLQKt_H.mjs +26 -0
  8. package/dist/pipeline-analytics/_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DbUPeg6m.mjs +26 -0
  9. package/dist/pipeline-analytics/{hostInit-Tp2cEslm.mjs → hostInit-Bl6Zvb1p.mjs} +3 -3
  10. package/dist/pipeline-analytics/index.js +1298 -359
  11. package/dist/pipeline-analytics/index.mjs +1298 -359
  12. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  13. package/package.json +1 -1
  14. 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
  15. 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-yKL5gfrH.mjs
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(["cap", "addon"]),
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({ nodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), 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
- nodeId: string().min(1),
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: DeviceHistoryKindSchema,
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
- method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
42011
- scope: array(string()).optional(),
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
- since: date().optional(),
42014
- until: date().optional(),
42015
- limit: number().optional(),
42016
- tags: record(string(), string()).optional()
42017
- }), array(LogEntrySchema).readonly());
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): none — enum state; arm/disarm history belongs in the events ledger.
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: "none",
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
- ]).default("best"),
44755
- /** What the still shows. Absent = `cropped` (the historical `best` shape). */
44946
+ ]).optional(),
44947
+ /** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
44756
44948
  frame: NcMediaFrameSchema.optional(),
44757
- /** Crop the attached still to the rule's condition-zone bbox (padded) —
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
- media: NcMediaPolicySchema.default({ attach: "best" }),
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): none — duplicates device-status.online (one authority for availability).
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: "none",
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: { progressPercent: {
59244
- kind: "gauge",
59245
- unit: "%",
59246
- deadband: 2
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): none — text/enum state has no history (non-goal).
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: "none",
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): none — enum state; lock events belong in the events ledger.
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: "none",
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): none — `positionMs` moves continuously while playing; volume is transient.
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: "none"
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.
@@ -66977,9 +67223,29 @@ var streamParamsCapability = {
66977
67223
  */
66978
67224
  durability: "restored",
66979
67225
  /**
66980
- * History (D850): none — encoder configuration.
67226
+ * History (D850): the configured bitrate and frame rate of the main and sub
67227
+ * profiles. Configuration, so change-only on the default floor: a point is an
67228
+ * operator's (or a tuner's) edit, which is exactly what a chart of a stream's
67229
+ * quality over time must show.
66981
67230
  */
66982
- history: "none",
67231
+ history: { fields: {
67232
+ "main.bitrate": {
67233
+ kind: "gauge",
67234
+ unit: "kbps"
67235
+ },
67236
+ "main.framerate": {
67237
+ kind: "gauge",
67238
+ unit: "fps"
67239
+ },
67240
+ "sub.bitrate": {
67241
+ kind: "gauge",
67242
+ unit: "kbps"
67243
+ },
67244
+ "sub.framerate": {
67245
+ kind: "gauge",
67246
+ unit: "fps"
67247
+ }
67248
+ } },
66983
67249
  /** Clock fields: written, but excluded from the compare that decides
66984
67250
  * whether persisting is worth a SQLite commit. */
66985
67251
  volatileStateFields: ["lastFetchedAt"]
@@ -70210,6 +70476,15 @@ var BaseDevice = class {
70210
70476
  * Drivers can use the `getProbeFlags()` helper to read the flag bag
70211
70477
  * with a typed cast.
70212
70478
  *
70479
+ * Answer what you KNOW. A plain array is read as the complete list only
70480
+ * while this device is `online` and probed; return
70481
+ * `accessoryChildrenUnknown(reason)` whenever you cannot know the list right
70482
+ * now (no credentials, parent not connected, a failed or partial read) —
70483
+ * the kernel then deletes nothing. Return `accessoryChildrenComplete(list)`
70484
+ * to say "connected, and this is the complete list" explicitly. A shrink is
70485
+ * deleted only after a second agreeing complete read on a later probe (D49;
70486
+ * `packages/system/src/kernel/moleculer/accessory-prune-gate.ts`).
70487
+ *
70213
70488
  * Default: no children.
70214
70489
  */
70215
70490
  getAccessoryChildren() {
@@ -73858,7 +74133,19 @@ Object.freeze({
73858
74133
  addonId: null,
73859
74134
  access: "view"
73860
74135
  },
73861
- "logDestination.query": {
74136
+ "logDestination.cancelRead": {
74137
+ capName: "log-destination",
74138
+ capScope: "system",
74139
+ addonId: null,
74140
+ access: "create"
74141
+ },
74142
+ "logDestination.describeRead": {
74143
+ capName: "log-destination",
74144
+ capScope: "system",
74145
+ addonId: null,
74146
+ access: "view"
74147
+ },
74148
+ "logDestination.read": {
73862
74149
  capName: "log-destination",
73863
74150
  capScope: "system",
73864
74151
  addonId: null,
@@ -79865,6 +80152,11 @@ Object.freeze({
79865
80152
  form: "single",
79866
80153
  optional: false
79867
80154
  }],
80155
+ "logDestination.read": [{
80156
+ name: "deviceId",
80157
+ form: "single",
80158
+ optional: true
80159
+ }],
79868
80160
  "mediaPlayer.getStatus": [{
79869
80161
  name: "deviceId",
79870
80162
  form: "single",
@@ -82114,6 +82406,123 @@ function isSystemRuleKind(kind) {
82114
82406
  function systemFamilyOfKind(kind) {
82115
82407
  return isSystemEventFamily(kind) ? kind : void 0;
82116
82408
  }
82409
+ /**
82410
+ * Reasons, written once. Each names the SUBJECT FIELD the engine reads and
82411
+ * finds absent — that is what makes the exclusion checkable against the engine
82412
+ * rather than an opinion about tidiness.
82413
+ */
82414
+ var NO_SENSOR_KIND = "An occupancy edge is not a sensor event: it carries no sensor kind, so this condition can never match one.";
82415
+ 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.";
82416
+ 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.";
82417
+ var OCCUPANCY_SOURCE = "An occupancy edge is always produced by the pipeline, so any other source can never match and “pipeline” narrows nothing.";
82418
+ var AUDIO_SOURCE = "A confirmed sound window is always stamped as an audio subject, so any other source can never match.";
82419
+ 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.";
82420
+ 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.";
82421
+ var SOUND_NO_GEOMETRY = "A sound has no position in the frame, so a zone or a drawn polygon can never match it.";
82422
+ var NC_RULE_KIND_SPECS = [
82423
+ {
82424
+ kind: "detection",
82425
+ label: "Conditions",
82426
+ 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." },
82427
+ editable: true,
82428
+ carriesMedia: true,
82429
+ carriesSubjectCrop: true
82430
+ },
82431
+ {
82432
+ kind: "sensor",
82433
+ label: "Conditions",
82434
+ /** `occupancy` is still offered here: authoring it converts a sensor rule into an occupancy rule. */
82435
+ excluded: {},
82436
+ editable: true,
82437
+ carriesMedia: true,
82438
+ carriesSubjectCrop: true,
82439
+ blurb: "A doorbell press or a linked sensor changing state. The picture comes from the camera the sensor is attributed to."
82440
+ },
82441
+ {
82442
+ kind: "occupancy",
82443
+ label: "Occupancy",
82444
+ discriminator: "occupancy",
82445
+ excluded: {
82446
+ sensorKinds: NO_SENSOR_KIND,
82447
+ eventTypeTokens: NO_EVENT_TOKEN,
82448
+ sensorTransition: NO_SENSOR_EDGE,
82449
+ source: OCCUPANCY_SOURCE
82450
+ },
82451
+ editable: true,
82452
+ carriesMedia: true,
82453
+ carriesSubjectCrop: true,
82454
+ 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."
82455
+ },
82456
+ {
82457
+ kind: "sound",
82458
+ label: "Sound",
82459
+ discriminator: "audio",
82460
+ excluded: {
82461
+ classes: SOUND_NOT_A_PICTURE,
82462
+ classesExclude: SOUND_NOT_A_PICTURE,
82463
+ minConfidence: SOUND_NO_CONFIDENCE,
82464
+ zones: SOUND_NO_GEOMETRY,
82465
+ zonesExclude: SOUND_NO_GEOMETRY,
82466
+ customZones: SOUND_NO_GEOMETRY,
82467
+ crossing: SOUND_NO_GEOMETRY,
82468
+ labelEquals: SOUND_NOT_A_PICTURE,
82469
+ identities: SOUND_NOT_A_PICTURE,
82470
+ identitiesExclude: SOUND_NOT_A_PICTURE,
82471
+ plates: SOUND_NOT_A_PICTURE,
82472
+ source: AUDIO_SOURCE
82473
+ },
82474
+ editable: true,
82475
+ carriesMedia: true,
82476
+ carriesSubjectCrop: false,
82477
+ 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.",
82478
+ 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."
82479
+ },
82480
+ {
82481
+ kind: "device-events",
82482
+ label: "Device events",
82483
+ discriminator: "systemEvent",
82484
+ excluded: {},
82485
+ editable: true,
82486
+ carriesMedia: false,
82487
+ carriesSubjectCrop: false,
82488
+ 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."
82489
+ },
82490
+ {
82491
+ kind: "system",
82492
+ label: "System events",
82493
+ discriminator: "systemEvent",
82494
+ excluded: {},
82495
+ editable: true,
82496
+ carriesMedia: false,
82497
+ carriesSubjectCrop: false,
82498
+ blurb: "The installation itself: a node leaving, an addon crash-looping, an update available or installed, a backup or an export finishing."
82499
+ },
82500
+ {
82501
+ kind: "alarm",
82502
+ label: "Alarm",
82503
+ discriminator: "systemEvent",
82504
+ excluded: {},
82505
+ editable: true,
82506
+ carriesMedia: false,
82507
+ carriesSubjectCrop: false,
82508
+ blurb: "The alarm panel: refused, arming, armed, entry delay, triggered, re-armed, sensor bypass, disarmed.",
82509
+ 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."
82510
+ },
82511
+ {
82512
+ kind: "mixed",
82513
+ label: "To recreate",
82514
+ discriminator: "systemEvent",
82515
+ excluded: {},
82516
+ editable: false,
82517
+ carriesMedia: false,
82518
+ carriesSubjectCrop: false,
82519
+ 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."
82520
+ }
82521
+ ];
82522
+ /** The spec for a kind. Total by construction — every member has an entry. */
82523
+ function ruleKindSpec(kind) {
82524
+ return NC_RULE_KIND_SPECS.find((s) => s.kind === kind) ?? NC_RULE_KIND_SPECS[0];
82525
+ }
82117
82526
  /** The delivery a system rule rides — named once, compared everywhere. */
82118
82527
  var NC_SYSTEM_DELIVERY = "system-event";
82119
82528
  /**
@@ -82231,6 +82640,98 @@ function systemRuleKindOf(condition) {
82231
82640
  return verdict.kind === "family" ? verdict.family : "mixed";
82232
82641
  }
82233
82642
  NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
82643
+ /** Every mode, in the order an editor offers them. */
82644
+ var NC_MEDIA_IMAGE_MODES = [
82645
+ "scene-boxes",
82646
+ "crop",
82647
+ "clean",
82648
+ "none"
82649
+ ];
82650
+ /**
82651
+ * The modes a rule of this kind can honour. A kind that carries no media gets
82652
+ * none (its row ships text, or — an alarm — its SOURCE rule's picture); a kind
82653
+ * whose subject has no region of the frame (a sound) is never offered `crop`.
82654
+ */
82655
+ function imageModesForKind(kind) {
82656
+ const spec = ruleKindSpec(kind);
82657
+ if (!spec.carriesMedia) return [];
82658
+ return spec.carriesSubjectCrop ? NC_MEDIA_IMAGE_MODES : NC_MEDIA_IMAGE_MODES.filter((mode) => mode !== "crop");
82659
+ }
82660
+ /**
82661
+ * The zone ids that FIRE a rule: its `zones` condition, or an occupancy rule's
82662
+ * own scoped zone. Empty when the trigger is not a zone — and then
82663
+ * `showTriggerZone` has nothing to draw and is refused on save.
82664
+ */
82665
+ function ruleTriggerZoneIds(conditions) {
82666
+ if (conditions.zones !== void 0) return conditions.zones.ids;
82667
+ const zoneId = conditions.occupancy?.zoneId;
82668
+ return zoneId !== void 0 ? [zoneId] : [];
82669
+ }
82670
+ /**
82671
+ * What the legacy triple MEANT, as a mode. `zoneCrop` forced the clean
82672
+ * keyFrame ladder and dropped `frame`, so it is `clean` whatever else was set;
82673
+ * `frame` decided over `attach` when present; `keyFrame` was the clean scene;
82674
+ * every other still (`best`, `best-matching`, the default) was the subject.
82675
+ */
82676
+ function legacyImageMode(media) {
82677
+ if (media.attach === "none") return "none";
82678
+ if (media.zoneCrop === true) return "clean";
82679
+ if (media.frame === "full") return "clean";
82680
+ if (media.frame === "boxed") return "scene-boxes";
82681
+ if (media.frame === "cropped") return "crop";
82682
+ if (media.attach === "keyFrame") return "clean";
82683
+ return "crop";
82684
+ }
82685
+ /** A mode the kind cannot honour, mapped to the nearest one it can. */
82686
+ function clampToKind(mode, kind) {
82687
+ const offered = imageModesForKind(kind);
82688
+ if (offered.length === 0 || offered.includes(mode)) return mode;
82689
+ return mode === "crop" ? "clean" : mode;
82690
+ }
82691
+ /**
82692
+ * The mode a rule's picture is rendered in. `image` when stored; else what the
82693
+ * legacy triple meant — and, for a SENSOR rule written before D897, `clean`
82694
+ * whatever it stored (even `attach: 'none'`), because its stored triple was
82695
+ * ignored and one plain snapshot always shipped (operator ruling, 2026-10-01):
82696
+ * the migration keeps what the rule actually DID. Clamped to what the kind can
82697
+ * honour.
82698
+ */
82699
+ function resolveNcMediaImage(media, kind) {
82700
+ if (media.image !== void 0) return clampToKind(media.image, kind);
82701
+ if (kind === "sensor") return "clean";
82702
+ return clampToKind(legacyImageMode(media), kind);
82703
+ }
82704
+ /**
82705
+ * The stored shape of a media policy: `image` set, the legacy triple gone.
82706
+ * `showTriggerZone` survives only where it can be drawn — a zone trigger and a
82707
+ * mode other than `crop`/`none`; a legacy `zoneCrop` on a zone rule becomes it.
82708
+ * Every other field (gif, clip, rolls, speed, profile, linked cameras) is
82709
+ * carried through untouched. Pure; never throws.
82710
+ */
82711
+ function normalizeNcMediaPolicy(media, rule) {
82712
+ const image = resolveNcMediaImage(media, ruleKindOf(rule));
82713
+ const { attach: _attach, frame: _frame, zoneCrop, showTriggerZone, image: _image, ...rest } = media;
82714
+ const drawable = (showTriggerZone === true || media.image === void 0 && zoneCrop === true) && image !== "crop" && image !== "none" && ruleTriggerZoneIds(rule.conditions).length > 0;
82715
+ return {
82716
+ ...rest,
82717
+ image,
82718
+ ...drawable ? { showTriggerZone: true } : {}
82719
+ };
82720
+ }
82721
+ /**
82722
+ * Why a media policy cannot be SAVED on this rule, or null. Server-side and
82723
+ * editor alike: `showTriggerZone` on a rule whose trigger is not a zone, and a
82724
+ * mode the rule's kind cannot honour.
82725
+ */
82726
+ function ncMediaPolicyError(media, rule) {
82727
+ const kind = ruleKindOf(rule);
82728
+ if (media.image !== void 0) {
82729
+ const offered = imageModesForKind(kind);
82730
+ if (offered.length > 0 && !offered.includes(media.image)) return `media.image '${media.image}' is not available for a ${kind} rule (offered: ${offered.join(", ")})`;
82731
+ }
82732
+ 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)";
82733
+ return null;
82734
+ }
82234
82735
  var WEEKDAY_TO_DAY = {
82235
82736
  Sun: 0,
82236
82737
  Mon: 1,
@@ -87278,12 +87779,24 @@ Object.defineProperty(exports, "memoizePinnedFfmpeg", {
87278
87779
  return memoizePinnedFfmpeg;
87279
87780
  }
87280
87781
  });
87782
+ Object.defineProperty(exports, "ncMediaPolicyError", {
87783
+ enumerable: true,
87784
+ get: function() {
87785
+ return ncMediaPolicyError;
87786
+ }
87787
+ });
87281
87788
  Object.defineProperty(exports, "nodePin", {
87282
87789
  enumerable: true,
87283
87790
  get: function() {
87284
87791
  return nodePin;
87285
87792
  }
87286
87793
  });
87794
+ Object.defineProperty(exports, "normalizeNcMediaPolicy", {
87795
+ enumerable: true,
87796
+ get: function() {
87797
+ return normalizeNcMediaPolicy;
87798
+ }
87799
+ });
87287
87800
  Object.defineProperty(exports, "normalizeNodeId", {
87288
87801
  enumerable: true,
87289
87802
  get: function() {
@@ -87416,6 +87929,12 @@ Object.defineProperty(exports, "resolveModeNotifyPolicy", {
87416
87929
  return resolveModeNotifyPolicy;
87417
87930
  }
87418
87931
  });
87932
+ Object.defineProperty(exports, "resolveNcMediaImage", {
87933
+ enumerable: true,
87934
+ get: function() {
87935
+ return resolveNcMediaImage;
87936
+ }
87937
+ });
87419
87938
  Object.defineProperty(exports, "resolvePoolMemoryPolicy", {
87420
87939
  enumerable: true,
87421
87940
  get: function() {