@camstack/addon-provider-dreame 0.2.138 → 0.2.139

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 (3) hide show
  1. package/dist/addon.js +370 -41
  2. package/dist/addon.mjs +370 -41
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -5459,7 +5459,7 @@ var ZodIssueCode$1 = {
5459
5459
  var ZodFirstPartyTypeKind$1;
5460
5460
  ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5461
5461
  //#endregion
5462
- //#region ../types/dist/sleep-yKL5gfrH.mjs
5462
+ //#region ../types/dist/sleep-BSuCCFjf.mjs
5463
5463
  /**
5464
5464
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5465
5465
  * window to float samples (D455).
@@ -17053,7 +17053,19 @@ var DeviceHistorySubjectSchema = discriminatedUnion("kind", [object({
17053
17053
  kind: literal("node"),
17054
17054
  nodeId: string().min(1)
17055
17055
  })]);
17056
+ /**
17057
+ * `enum` stores a STATE as the ordinal of its value in the series' value list
17058
+ * (`DeviceHistorySeriesInfo.values`, append-only, so an ordinal never changes
17059
+ * meaning); a rollup keeps the time spent in each state (`states`).
17060
+ */
17056
17061
  var DeviceHistoryKindSchema = _enum([
17062
+ "gauge",
17063
+ "counter",
17064
+ "boolean",
17065
+ "enum"
17066
+ ]);
17067
+ /** What a PRODUCER may declare. `enum` is cap-only: its value list is the cap field's. */
17068
+ var DeviceHistoryProducerKindSchema = _enum([
17057
17069
  "gauge",
17058
17070
  "counter",
17059
17071
  "boolean"
@@ -17090,7 +17102,13 @@ var SeriesInfoSchema = object({
17090
17102
  /** `null` is unknown (a `unitFrom` series whose device does not state a unit right now), never a guess. */
17091
17103
  unit: string().nullable(),
17092
17104
  displayName: string(),
17093
- source: _enum(["cap", "addon"]),
17105
+ source: _enum([
17106
+ "cap",
17107
+ "addon",
17108
+ "derived"
17109
+ ]),
17110
+ /** `enum`: the value of each ordinal (index = ordinal); `null` for every other kind. */
17111
+ values: array(string()).readonly().nullable(),
17094
17112
  firstTs: number(),
17095
17113
  lastTs: number()
17096
17114
  });
@@ -17104,17 +17122,31 @@ var QueryPointSchema = object({
17104
17122
  twMean: number().nullable(),
17105
17123
  min: number(),
17106
17124
  max: number(),
17107
- /** `null` is unknown, never zero (D393). */
17108
- last: number().nullable()
17125
+ /** `null` is unknown, never zero (D393). For an `enum` series: the ordinal of {@link state}. */
17126
+ last: number().nullable(),
17127
+ /**
17128
+ * The increase over the point: a `counter`'s growth since the previous point
17129
+ * or bucket (a drop is a reset, counted from zero), and for
17130
+ * {@link DEVICE_HISTORY_ENERGY_KEY} the kWh used in the bucket. `null` for
17131
+ * every other kind, and when it cannot be known.
17132
+ */
17133
+ delta: number().nullable(),
17134
+ /** `enum`: the state in force at the end of the point (the name of `last`); `null` otherwise. */
17135
+ state: string().nullable(),
17136
+ /** `enum` rollup: milliseconds spent in each state inside the bucket; `null` for raw points and other kinds. */
17137
+ states: record(string(), number()).nullable()
17109
17138
  });
17110
17139
  var QuerySeriesSchema = object({
17111
17140
  scope: string(),
17112
17141
  /** The last point STRICTLY BEFORE `from` in the chosen tier, so a step chart can start at the held value. */
17113
17142
  before: object({
17114
17143
  t: number(),
17115
- value: number().nullable()
17144
+ value: number().nullable(),
17145
+ state: string().nullable()
17116
17146
  }).nullable(),
17117
- points: array(QueryPointSchema).readonly()
17147
+ points: array(QueryPointSchema).readonly(),
17148
+ /** A derived key: the stored key its points were computed from; `null` for a stored series. */
17149
+ derivedFrom: string().nullable()
17118
17150
  });
17119
17151
  /** The window part of a query, shared by the device and node forms. */
17120
17152
  var QueryWindowShape = {
@@ -17130,6 +17162,23 @@ var QueryResultSchema = object({
17130
17162
  series: array(QuerySeriesSchema).readonly(),
17131
17163
  truncated: boolean()
17132
17164
  });
17165
+ /** One read of a batch: a device's key or a node's key (exactly one subject). */
17166
+ var QueryManyItemSchema = union([object({
17167
+ deviceId: number().int(),
17168
+ key: string(),
17169
+ scope: string().optional()
17170
+ }), object({
17171
+ forNodeId: string().min(1),
17172
+ key: string(),
17173
+ scope: string().optional()
17174
+ })]);
17175
+ var QueryManyEntrySchema = discriminatedUnion("ok", [object({
17176
+ ok: literal(true),
17177
+ result: QueryResultSchema
17178
+ }), object({
17179
+ ok: literal(false),
17180
+ error: string()
17181
+ })]);
17133
17182
  var TierStatusSchema = object({
17134
17183
  tier: DeviceHistoryResolutionSchema,
17135
17184
  /** `null` until the first background count answered. */
@@ -17185,16 +17234,22 @@ var DeviceHistoryStatusSchema = object({
17185
17234
  lastRefreshAt: number().nullable()
17186
17235
  })
17187
17236
  });
17188
- method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({ nodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), method(object({
17237
+ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({ forNodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), method(object({
17189
17238
  deviceId: number().int(),
17190
17239
  ...QueryWindowShape
17191
17240
  }), QueryResultSchema), method(object({
17192
- nodeId: string().min(1),
17241
+ forNodeId: string().min(1),
17193
17242
  ...QueryWindowShape
17194
17243
  }), QueryResultSchema, { auth: "admin" }), method(object({
17244
+ items: array(QueryManyItemSchema).min(1).max(24),
17245
+ from: QueryWindowShape.from,
17246
+ to: QueryWindowShape.to,
17247
+ resolution: QueryWindowShape.resolution,
17248
+ maxPoints: QueryWindowShape.maxPoints
17249
+ }), object({ results: array(QueryManyEntrySchema).readonly() }), { auth: "admin" }), method(object({
17195
17250
  name: string().regex(/^[a-z0-9-]+$/),
17196
17251
  subjectKind: _enum(["device", "node"]),
17197
- kind: DeviceHistoryKindSchema,
17252
+ kind: DeviceHistoryProducerKindSchema,
17198
17253
  unit: string().optional(),
17199
17254
  displayName: string().min(1),
17200
17255
  ingest: _enum(["points", "buckets"])
@@ -40432,14 +40487,106 @@ var LogEntrySchema = object({
40432
40487
  meta: record(string(), unknown()).optional(),
40433
40488
  tags: record(string(), string()).optional()
40434
40489
  });
40435
- method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
40436
- scope: array(string()).optional(),
40490
+ /**
40491
+ * A history READ against one destination (D898).
40492
+ *
40493
+ * Every filter is applied by the PROVIDER, before the limit — a filter the
40494
+ * browser applied after the limit is what made a rare device's lines
40495
+ * unreachable behind a busy one's. `before` / `after` are cursors the provider
40496
+ * minted (opaque to everyone else): a file position for the rotated files, a
40497
+ * nanosecond timestamp for Loki.
40498
+ *
40499
+ * A read is BOUNDED by `budgetMs`: a filter that matches nothing on a 30-day
40500
+ * store answers `done: false` with the cursor it reached and the bytes it
40501
+ * scanned, and the caller decides whether to go on. That is what makes a long
40502
+ * scan show progress and stop when asked — `cancelRead` ends the slice in
40503
+ * flight, and not asking for the next slice ends the scan.
40504
+ */
40505
+ var LogReadQuerySchema = object({
40506
+ /** Correlates `cancelRead`. Caller-chosen, unique per in-flight read. */
40507
+ requestId: string().min(1).max(64).optional(),
40508
+ /** The device the line is about (`tags.deviceId`, numeric). */
40509
+ deviceId: number().int().optional(),
40510
+ /**
40511
+ * The emitting addon — bare manifest id; `@<version>` / `::<sub>` suffixes
40512
+ * match. Not `addonId`: a cap router reads that name as "which provider".
40513
+ */
40514
+ fromAddonId: string().min(1).max(200).optional(),
40515
+ /**
40516
+ * The emitting node: matches the agent that emitted the line, the node
40517
+ * itself, or a worker under it (`<agent>/<runner>`) — the `agentId`
40518
+ * semantics of `matchesLogTags`. Not `nodeId`: a cap router reads that
40519
+ * name as "which node's provider".
40520
+ */
40521
+ fromNodeId: string().min(1).max(200).optional(),
40522
+ /** Any other tag, exact match (AND). */
40523
+ tags: record(string(), union([string(), number()])).optional(),
40524
+ /** Severity FLOOR: this level and above. */
40437
40525
  level: LogLevelSchema.optional(),
40438
- since: date().optional(),
40439
- until: date().optional(),
40440
- limit: number().optional(),
40441
- tags: record(string(), string()).optional()
40442
- }), array(LogEntrySchema).readonly());
40526
+ /** Case-insensitive substring over message, scope, tag values and meta values. */
40527
+ text: string().min(1).max(200).optional(),
40528
+ /** Epoch ms, inclusive. */
40529
+ since: number().optional(),
40530
+ /** Epoch ms, inclusive. */
40531
+ until: number().optional(),
40532
+ /** Older than this cursor (exclusive). Absent with `after` absent ⇒ from the newest. */
40533
+ before: string().min(1).max(1024).optional(),
40534
+ /** Newer than this cursor (exclusive). */
40535
+ after: string().min(1).max(1024).optional(),
40536
+ limit: number().int().min(1).max(1e3).optional(),
40537
+ /** Wall-clock bound of this slice. The provider caps it. */
40538
+ budgetMs: number().int().min(50).max(1e4).optional()
40539
+ });
40540
+ var LogReadResultSchema = object({
40541
+ /** Newest first. */
40542
+ entries: array(object({
40543
+ /** `<bootId>.<seq>` minted by the emitting LogManager — the dedupe key. */
40544
+ id: string().optional(),
40545
+ /** Epoch ms. */
40546
+ timestamp: number(),
40547
+ level: LogLevelSchema,
40548
+ scope: string().optional(),
40549
+ message: string(),
40550
+ tags: record(string(), union([string(), number()])).optional(),
40551
+ meta: record(string(), unknown()).optional()
40552
+ })),
40553
+ /** Pass as `before` for the next older page; null when nothing older exists. */
40554
+ nextBefore: string().nullable(),
40555
+ /** Pass as `after` to read what arrived since; null when unknown. */
40556
+ nextAfter: string().nullable(),
40557
+ /** Bytes this slice read (files) or received (remote). Progress, not a promise. */
40558
+ scannedBytes: number().int().nonnegative(),
40559
+ /**
40560
+ * True when the scan in this direction reached the end of the store.
40561
+ * False with fewer than `limit` entries means the budget ran out first —
40562
+ * call again with `nextBefore` to go on.
40563
+ */
40564
+ done: boolean(),
40565
+ /** True when `cancelRead` ended this slice early. */
40566
+ cancelled: boolean().optional()
40567
+ });
40568
+ var LogReadCapabilitiesSchema = object({
40569
+ /** False ⇒ this destination only ships lines (console, forwarder, an unconfigured Loki). */
40570
+ readable: boolean(),
40571
+ /** Why not, when `readable` is false — rendered next to the source. */
40572
+ reason: string().nullable(),
40573
+ /** Filters the provider applies itself. A false one is applied by nobody. */
40574
+ filters: object({
40575
+ deviceId: boolean(),
40576
+ addonId: boolean(),
40577
+ nodeId: boolean(),
40578
+ tags: boolean(),
40579
+ level: boolean(),
40580
+ text: boolean(),
40581
+ timeRange: boolean()
40582
+ }),
40583
+ /** How far back the store reaches, when the provider knows (days). */
40584
+ retentionDays: number().nullable()
40585
+ });
40586
+ 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() }), {
40587
+ kind: "mutation",
40588
+ auth: "admin"
40589
+ });
40443
40590
  /**
40444
40591
  * `login-method` — collection cap through which auth addons contribute
40445
40592
  * their pre-auth login surfaces to the login page. This is the SINGLE,
@@ -42157,9 +42304,11 @@ var alarmPanelCapability = {
42157
42304
  */
42158
42305
  durability: "restored",
42159
42306
  /**
42160
- * History (D850): none — enum state; arm/disarm history belongs in the events ledger.
42307
+ * History (D850): the panel's lifecycle state as an `enum` series —
42308
+ * change-only, no floor, so an `arming -> pending -> triggered` sequence of a
42309
+ * few seconds keeps every step. Who armed it stays in the events ledger.
42161
42310
  */
42162
- history: "none",
42311
+ history: { fields: { state: { kind: "enum" } } },
42163
42312
  /** Clock fields: written, but excluded from the compare that decides
42164
42313
  * whether persisting is worth a SQLite commit. */
42165
42314
  volatileStateFields: ["lastChangedAt"]
@@ -43037,6 +43186,33 @@ var NcRuleTargetSchema = object({
43037
43186
  params: record(string(), unknown()).optional()
43038
43187
  });
43039
43188
  /**
43189
+ * WHAT THE NOTIFICATION'S PICTURE IS (D897) — the ONE media choice of a rule.
43190
+ *
43191
+ * Every mode starts from the same CLEAN source frame of the trigger moment
43192
+ * (keyFrame → sceneFrame → lastSceneFrame, narrowed to the trigger instant and
43193
+ * to the zone that fired the rule) and renders it once at send time:
43194
+ * - `scene-boxes` — the whole scene, the subject outlined thick in the accent
43195
+ * colour and every OTHER track visible at that instant outlined thin, each
43196
+ * labelled with class and confidence ("dog 87%").
43197
+ * - `crop` — the subject cut out of that frame around its box at that instant.
43198
+ * - `clean` — the whole scene with nothing drawn on it.
43199
+ * - `none` — no picture.
43200
+ *
43201
+ * A mode that cannot be honoured (no box at that instant, a photograph with no
43202
+ * tracked subject) ships `clean` and names the reason in the log, per camera.
43203
+ * It replaces the `attach` × `frame` × `zoneCrop` triple, which let one rule
43204
+ * ship a crop on one event and a boxed scene on the next depending on which
43205
+ * stored kind had landed.
43206
+ */
43207
+ var NcMediaImageSchema = _enum([
43208
+ "scene-boxes",
43209
+ "crop",
43210
+ "clean",
43211
+ "none"
43212
+ ]);
43213
+ /**
43214
+ * @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
43215
+ *
43040
43216
  * Media attachment policy (P1 still-image subset).
43041
43217
  * - `best` — the best AVAILABLE subject image at dispatch time (D-3).
43042
43218
  * - `best-matching` — the media that explains WHY the rule fired: a rule
@@ -43050,6 +43226,8 @@ var NcRuleTargetSchema = object({
43050
43226
  * - `none` — no attachment.
43051
43227
  */
43052
43228
  /**
43229
+ * @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
43230
+ *
43053
43231
  * WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
43054
43232
  * conflate it with the selection strategy and betray the request: asking for
43055
43233
  * the clean scene frame on an object-event owner used to start at
@@ -43078,16 +43256,29 @@ var NcMediaFrameSchema = _enum([
43078
43256
  */
43079
43257
  var NcLinkedCameraModeSchema = _enum(["mosaic", "each"]);
43080
43258
  var NcMediaPolicySchema = object({
43259
+ /**
43260
+ * The picture — see {@link NcMediaImageSchema}. Absent on a rule nobody has
43261
+ * saved since D897: `normalizeNcMediaPolicy` derives it from the legacy
43262
+ * triple below, at load and at every write, and the store keeps only this.
43263
+ */
43264
+ image: NcMediaImageSchema.optional(),
43265
+ /**
43266
+ * Draw the zone that FIRED the rule on the picture (`scene-boxes` / `clean`;
43267
+ * a `crop` never shows it). Valid only on a rule whose trigger is a zone —
43268
+ * `conditions.zones` or an occupancy zone — and refused on save otherwise.
43269
+ * Replaces `zoneCrop`.
43270
+ */
43271
+ showTriggerZone: boolean().optional(),
43272
+ /** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
43081
43273
  attach: _enum([
43082
43274
  "best",
43083
43275
  "best-matching",
43084
43276
  "keyFrame",
43085
43277
  "none"
43086
- ]).default("best"),
43087
- /** What the still shows. Absent = `cropped` (the historical `best` shape). */
43278
+ ]).optional(),
43279
+ /** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
43088
43280
  frame: NcMediaFrameSchema.optional(),
43089
- /** Crop the attached still to the rule's condition-zone bbox (padded) —
43090
- * "show me the ZONE", not the whole scene or the subject crop. */
43281
+ /** @deprecated D897 — folded into `image: 'clean'` + `showTriggerZone` on save. */
43091
43282
  zoneCrop: boolean().optional(),
43092
43283
  /**
43093
43284
  * Also attach a short GIF cut from the stream broker's clip ring around the
@@ -43259,7 +43450,9 @@ var NcRuleInputSchema = object({
43259
43450
  * targets.
43260
43451
  */
43261
43452
  targetUsers: array(string()).optional(),
43262
- media: NcMediaPolicySchema.default({ attach: "best" }),
43453
+ /** Absent = the kind's default picture (`resolveNcMediaImage`): the subject crop for a
43454
+ * detection, the clean scene for a sensor or a sound. Set explicitly on save (D897). */
43455
+ media: NcMediaPolicySchema.default({}),
43263
43456
  throttle: NcThrottleSchema.default({
43264
43457
  cooldownSec: 60,
43265
43458
  scope: "rule-device"
@@ -44196,13 +44389,37 @@ var NcAlarmModeOpeningsSchema = object({
44196
44389
  /** Covered devices whose state could not be read (D49): neither open nor closed. */
44197
44390
  unknown: array(number().int())
44198
44391
  });
44392
+ /**
44393
+ * One alarm INPUT — a (rule, device) pair — the operator bypassed until the
44394
+ * next disarm ("Bypass this input until disarm" on a trigger notification, or
44395
+ * `nc.bypassAlarmInput`). Reported so an armed alarm with a silenced input
44396
+ * never looks fully armed (D62: off must never look like broken).
44397
+ */
44398
+ var NcAlarmInputBypassViewSchema = object({
44399
+ ruleId: string(),
44400
+ /** The rule's current name (its frozen name when the rule is gone). */
44401
+ ruleName: string(),
44402
+ /** The input: the sensor of the match, else its camera. */
44403
+ deviceId: number().int(),
44404
+ /** The input's current name. */
44405
+ name: string(),
44406
+ /** When it was bypassed (ms epoch). */
44407
+ since: number(),
44408
+ /** Triggers from this input dropped since. */
44409
+ dropped: number().int().min(0)
44410
+ });
44199
44411
  var NcAlarmLiveSchema = object({
44200
44412
  state: AlarmStateSchema,
44201
44413
  /** The mode being armed into (exit delay) or held; null when disarmed. */
44202
44414
  targetMode: AlarmArmModeSchema.nullable(),
44203
44415
  availableModes: array(AlarmArmModeSchema),
44204
44416
  openings: array(NcAlarmModeOpeningsSchema),
44205
- exclusions: array(NcAlarmExclusionViewSchema)
44417
+ exclusions: array(NcAlarmExclusionViewSchema),
44418
+ /**
44419
+ * Inputs bypassed for the rest of this arm session; cleared on disarm.
44420
+ * Defaulted so an older hub answer still parses (as "none known").
44421
+ */
44422
+ bypassedInputs: array(NcAlarmInputBypassViewSchema).default([])
44206
44423
  });
44207
44424
  var NcAlarmConfigSchema = object({
44208
44425
  /**
@@ -54946,9 +55163,11 @@ var connectivityCapability = {
54946
55163
  */
54947
55164
  durability: "restored",
54948
55165
  /**
54949
- * History (D850): none — duplicates device-status.online (one authority for availability).
55166
+ * History (D850): `connected` as a boolean series — change-only, no floor. It
55167
+ * is the upstream entity's own link (a HA connectivity sensor), not the
55168
+ * device's reachability, which stays `device-status.online`.
54950
55169
  */
54951
- history: "none",
55170
+ history: { fields: { connected: { kind: "boolean" } } },
54952
55171
  /** Clock fields: written, but excluded from the compare that decides
54953
55172
  * whether persisting is worth a SQLite commit. */
54954
55173
  volatileStateFields: ["lastChangedAt"]
@@ -55772,11 +55991,22 @@ var dishwasherCapability = {
55772
55991
  },
55773
55992
  runtimeState: DishwasherStatusSchema,
55774
55993
  durability: "session",
55775
- history: { fields: { progressPercent: {
55776
- kind: "gauge",
55777
- unit: "%",
55778
- deadband: 2
55779
- } } }
55994
+ history: { fields: {
55995
+ progressPercent: {
55996
+ kind: "gauge",
55997
+ unit: "%",
55998
+ deadband: 2
55999
+ },
56000
+ state: { kind: "enum" },
56001
+ operationState: { kind: "enum" },
56002
+ remainingSeconds: {
56003
+ kind: "gauge",
56004
+ unit: "s",
56005
+ minIntervalMs: 6e4
56006
+ },
56007
+ doorOpen: { kind: "boolean" },
56008
+ powerOn: { kind: "boolean" }
56009
+ } }
55780
56010
  };
55781
56011
  var DoorbellStatusSchema = object({
55782
56012
  /** Ms epoch of the last press. null = never observed since this provider started. */
@@ -55893,9 +56123,15 @@ var enumSensorCapability = {
55893
56123
  */
55894
56124
  durability: "restored",
55895
56125
  /**
55896
- * History (D850): none — text/enum state has no history (non-goal).
56126
+ * History (D850): the value as an `enum` series (an appliance's program or
56127
+ * operation state, an HVAC action). The option set is per device, so the
56128
+ * value list is LEARNED as values are first seen (bounded). A sensor with a
56129
+ * `format` carries a timestamp, not a state, and is not recorded.
55897
56130
  */
55898
- history: "none",
56131
+ history: { fields: { value: {
56132
+ kind: "enum",
56133
+ skipWhenSet: "format"
56134
+ } } },
55899
56135
  /** Clock fields: written, but excluded from the compare that decides
55900
56136
  * whether persisting is worth a SQLite commit. */
55901
56137
  volatileStateFields: ["lastFetchedAt"]
@@ -57869,9 +58105,10 @@ var lockControlCapability = {
57869
58105
  */
57870
58106
  durability: "restored",
57871
58107
  /**
57872
- * History (D850): none — enum state; lock events belong in the events ledger.
58108
+ * History (D850): the lock's state as an `enum` series — change-only, no
58109
+ * floor: a jam or an unlock lasting seconds is the edge an operator looks for.
57873
58110
  */
57874
- history: "none",
58111
+ history: { fields: { state: { kind: "enum" } } },
57875
58112
  /** Clock fields: written, but excluded from the compare that decides
57876
58113
  * whether persisting is worth a SQLite commit. */
57877
58114
  volatileStateFields: ["lastChangedAt"]
@@ -58045,9 +58282,18 @@ var mediaPlayerCapability = {
58045
58282
  */
58046
58283
  durability: "session",
58047
58284
  /**
58048
- * History (D850): none — `positionMs` moves continuously while playing; volume is transient.
58285
+ * History (D850): volume (a level an operator or an automation sets; the
58286
+ * default 10 s floor folds a slider drag into its end value) and mute.
58287
+ * `positionMs` is not recorded: it moves continuously while playing.
58049
58288
  */
58050
- history: "none"
58289
+ history: { fields: {
58290
+ volumeLevel: {
58291
+ kind: "gauge",
58292
+ unit: "%",
58293
+ deadband: 1
58294
+ },
58295
+ isMuted: { kind: "boolean" }
58296
+ } }
58051
58297
  };
58052
58298
  /**
58053
58299
  * mesh-network — collection cap for mesh-VPN providers.
@@ -63488,9 +63734,29 @@ var streamParamsCapability = {
63488
63734
  */
63489
63735
  durability: "restored",
63490
63736
  /**
63491
- * History (D850): none — encoder configuration.
63737
+ * History (D850): the configured bitrate and frame rate of the main and sub
63738
+ * profiles. Configuration, so change-only on the default floor: a point is an
63739
+ * operator's (or a tuner's) edit, which is exactly what a chart of a stream's
63740
+ * quality over time must show.
63492
63741
  */
63493
- history: "none",
63742
+ history: { fields: {
63743
+ "main.bitrate": {
63744
+ kind: "gauge",
63745
+ unit: "kbps"
63746
+ },
63747
+ "main.framerate": {
63748
+ kind: "gauge",
63749
+ unit: "fps"
63750
+ },
63751
+ "sub.bitrate": {
63752
+ kind: "gauge",
63753
+ unit: "kbps"
63754
+ },
63755
+ "sub.framerate": {
63756
+ kind: "gauge",
63757
+ unit: "fps"
63758
+ }
63759
+ } },
63494
63760
  /** Clock fields: written, but excluded from the compare that decides
63495
63761
  * whether persisting is worth a SQLite commit. */
63496
63762
  volatileStateFields: ["lastFetchedAt"]
@@ -66668,6 +66934,15 @@ var BaseDevice$1 = class {
66668
66934
  * Drivers can use the `getProbeFlags()` helper to read the flag bag
66669
66935
  * with a typed cast.
66670
66936
  *
66937
+ * Answer what you KNOW. A plain array is read as the complete list only
66938
+ * while this device is `online` and probed; return
66939
+ * `accessoryChildrenUnknown(reason)` whenever you cannot know the list right
66940
+ * now (no credentials, parent not connected, a failed or partial read) —
66941
+ * the kernel then deletes nothing. Return `accessoryChildrenComplete(list)`
66942
+ * to say "connected, and this is the complete list" explicitly. A shrink is
66943
+ * deleted only after a second agreeing complete read on a later probe (D49;
66944
+ * `packages/system/src/kernel/moleculer/accessory-prune-gate.ts`).
66945
+ *
66671
66946
  * Default: no children.
66672
66947
  */
66673
66948
  getAccessoryChildren() {
@@ -66691,6 +66966,22 @@ var BaseDevice$1 = class {
66691
66966
  return (this.runtimeState.getCapState("feature-probe")?.lastProbedAt ?? 0) > 0;
66692
66967
  }
66693
66968
  };
66969
+ function accessoryChildrenUnknown(reason, known) {
66970
+ return known === void 0 ? {
66971
+ kind: "unknown",
66972
+ reason
66973
+ } : {
66974
+ kind: "unknown",
66975
+ reason,
66976
+ known
66977
+ };
66978
+ }
66979
+ function accessoryChildrenComplete(children) {
66980
+ return {
66981
+ kind: "complete",
66982
+ children
66983
+ };
66984
+ }
66694
66985
  /**
66695
66986
  * Delays before retry rounds 1..N — the round count IS the bound.
66696
66987
  * 10 s catches "the hub was busy for a moment"; the full schedule
@@ -70799,7 +71090,19 @@ Object.freeze({
70799
71090
  addonId: null,
70800
71091
  access: "view"
70801
71092
  },
70802
- "logDestination.query": {
71093
+ "logDestination.cancelRead": {
71094
+ capName: "log-destination",
71095
+ capScope: "system",
71096
+ addonId: null,
71097
+ access: "create"
71098
+ },
71099
+ "logDestination.describeRead": {
71100
+ capName: "log-destination",
71101
+ capScope: "system",
71102
+ addonId: null,
71103
+ access: "view"
71104
+ },
71105
+ "logDestination.read": {
70803
71106
  capName: "log-destination",
70804
71107
  capScope: "system",
70805
71108
  addonId: null,
@@ -76806,6 +77109,11 @@ Object.freeze({
76806
77109
  form: "single",
76807
77110
  optional: false
76808
77111
  }],
77112
+ "logDestination.read": [{
77113
+ name: "deviceId",
77114
+ form: "single",
77115
+ optional: true
77116
+ }],
76809
77117
  "mediaPlayer.getStatus": [{
76810
77118
  name: "deviceId",
76811
77119
  form: "single",
@@ -134212,7 +134520,7 @@ var DreameChildDevice = class extends BaseDevice$1 {
134212
134520
  this.dreameDeviceId = persisted.dreameDeviceId;
134213
134521
  this.brokerId = persisted.brokerId;
134214
134522
  this.model = persisted.model;
134215
- this.online = true;
134523
+ this.online = dreameFacades.getDevice(this.brokerId, this.dreameDeviceId) !== null;
134216
134524
  this.updateSourceInfo({
134217
134525
  id: this.dreameDeviceId,
134218
134526
  system: "dreame"
@@ -183859,7 +184167,28 @@ var DreameContainerDevice = class extends BaseDevice$1 {
183859
184167
  system: "dreame"
183860
184168
  });
183861
184169
  }
184170
+ /**
184171
+ * The child list is known only while the cloud device is REACHABLE: every
184172
+ * presence-filtered child is derived from the live handle. Without it (no
184173
+ * credentials, cloud down, before the first connect) the answer is UNKNOWN —
184174
+ * the kernel then deletes nothing (D49; it deleted 97 accessories when this
184175
+ * answered only the core child) — and only the core child is named to spawn.
184176
+ */
183862
184177
  getAccessoryChildren() {
184178
+ const specs = this.buildChildSpecs();
184179
+ if (dreameFacades.getDevice(this.brokerId, this.dreameDeviceId) === null) {
184180
+ this.ctx.logger.info("DreameContainerDevice: cloud device not reachable; child list unknown", {
184181
+ tags: { deviceId: this.id },
184182
+ meta: {
184183
+ dreameDeviceId: this.dreameDeviceId,
184184
+ integrationId: this.brokerId
184185
+ }
184186
+ });
184187
+ return accessoryChildrenUnknown("dreame cloud device not reachable", specs.slice(0, 1));
184188
+ }
184189
+ return accessoryChildrenComplete(specs);
184190
+ }
184191
+ buildChildSpecs() {
183863
184192
  const kind = classifyDreameModel(this.model);
183864
184193
  if (kind === "unsupported") {
183865
184194
  this.ctx.logger.warn("DreameContainerDevice: unsupported model; no children", {
package/dist/addon.mjs CHANGED
@@ -5456,7 +5456,7 @@ var ZodIssueCode$1 = {
5456
5456
  var ZodFirstPartyTypeKind$1;
5457
5457
  ZodFirstPartyTypeKind$1 || (ZodFirstPartyTypeKind$1 = {});
5458
5458
  //#endregion
5459
- //#region ../types/dist/sleep-yKL5gfrH.mjs
5459
+ //#region ../types/dist/sleep-BSuCCFjf.mjs
5460
5460
  /**
5461
5461
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5462
5462
  * window to float samples (D455).
@@ -17050,7 +17050,19 @@ var DeviceHistorySubjectSchema = discriminatedUnion("kind", [object({
17050
17050
  kind: literal("node"),
17051
17051
  nodeId: string().min(1)
17052
17052
  })]);
17053
+ /**
17054
+ * `enum` stores a STATE as the ordinal of its value in the series' value list
17055
+ * (`DeviceHistorySeriesInfo.values`, append-only, so an ordinal never changes
17056
+ * meaning); a rollup keeps the time spent in each state (`states`).
17057
+ */
17053
17058
  var DeviceHistoryKindSchema = _enum([
17059
+ "gauge",
17060
+ "counter",
17061
+ "boolean",
17062
+ "enum"
17063
+ ]);
17064
+ /** What a PRODUCER may declare. `enum` is cap-only: its value list is the cap field's. */
17065
+ var DeviceHistoryProducerKindSchema = _enum([
17054
17066
  "gauge",
17055
17067
  "counter",
17056
17068
  "boolean"
@@ -17087,7 +17099,13 @@ var SeriesInfoSchema = object({
17087
17099
  /** `null` is unknown (a `unitFrom` series whose device does not state a unit right now), never a guess. */
17088
17100
  unit: string().nullable(),
17089
17101
  displayName: string(),
17090
- source: _enum(["cap", "addon"]),
17102
+ source: _enum([
17103
+ "cap",
17104
+ "addon",
17105
+ "derived"
17106
+ ]),
17107
+ /** `enum`: the value of each ordinal (index = ordinal); `null` for every other kind. */
17108
+ values: array(string()).readonly().nullable(),
17091
17109
  firstTs: number(),
17092
17110
  lastTs: number()
17093
17111
  });
@@ -17101,17 +17119,31 @@ var QueryPointSchema = object({
17101
17119
  twMean: number().nullable(),
17102
17120
  min: number(),
17103
17121
  max: number(),
17104
- /** `null` is unknown, never zero (D393). */
17105
- last: number().nullable()
17122
+ /** `null` is unknown, never zero (D393). For an `enum` series: the ordinal of {@link state}. */
17123
+ last: number().nullable(),
17124
+ /**
17125
+ * The increase over the point: a `counter`'s growth since the previous point
17126
+ * or bucket (a drop is a reset, counted from zero), and for
17127
+ * {@link DEVICE_HISTORY_ENERGY_KEY} the kWh used in the bucket. `null` for
17128
+ * every other kind, and when it cannot be known.
17129
+ */
17130
+ delta: number().nullable(),
17131
+ /** `enum`: the state in force at the end of the point (the name of `last`); `null` otherwise. */
17132
+ state: string().nullable(),
17133
+ /** `enum` rollup: milliseconds spent in each state inside the bucket; `null` for raw points and other kinds. */
17134
+ states: record(string(), number()).nullable()
17106
17135
  });
17107
17136
  var QuerySeriesSchema = object({
17108
17137
  scope: string(),
17109
17138
  /** The last point STRICTLY BEFORE `from` in the chosen tier, so a step chart can start at the held value. */
17110
17139
  before: object({
17111
17140
  t: number(),
17112
- value: number().nullable()
17141
+ value: number().nullable(),
17142
+ state: string().nullable()
17113
17143
  }).nullable(),
17114
- points: array(QueryPointSchema).readonly()
17144
+ points: array(QueryPointSchema).readonly(),
17145
+ /** A derived key: the stored key its points were computed from; `null` for a stored series. */
17146
+ derivedFrom: string().nullable()
17115
17147
  });
17116
17148
  /** The window part of a query, shared by the device and node forms. */
17117
17149
  var QueryWindowShape = {
@@ -17127,6 +17159,23 @@ var QueryResultSchema = object({
17127
17159
  series: array(QuerySeriesSchema).readonly(),
17128
17160
  truncated: boolean()
17129
17161
  });
17162
+ /** One read of a batch: a device's key or a node's key (exactly one subject). */
17163
+ var QueryManyItemSchema = union([object({
17164
+ deviceId: number().int(),
17165
+ key: string(),
17166
+ scope: string().optional()
17167
+ }), object({
17168
+ forNodeId: string().min(1),
17169
+ key: string(),
17170
+ scope: string().optional()
17171
+ })]);
17172
+ var QueryManyEntrySchema = discriminatedUnion("ok", [object({
17173
+ ok: literal(true),
17174
+ result: QueryResultSchema
17175
+ }), object({
17176
+ ok: literal(false),
17177
+ error: string()
17178
+ })]);
17130
17179
  var TierStatusSchema = object({
17131
17180
  tier: DeviceHistoryResolutionSchema,
17132
17181
  /** `null` until the first background count answered. */
@@ -17182,16 +17231,22 @@ var DeviceHistoryStatusSchema = object({
17182
17231
  lastRefreshAt: number().nullable()
17183
17232
  })
17184
17233
  });
17185
- method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({ nodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), method(object({
17234
+ method(object({ deviceId: number().int() }), array(SeriesInfoSchema).readonly()), method(object({ forNodeId: string().min(1) }), array(SeriesInfoSchema).readonly(), { auth: "admin" }), method(object({
17186
17235
  deviceId: number().int(),
17187
17236
  ...QueryWindowShape
17188
17237
  }), QueryResultSchema), method(object({
17189
- nodeId: string().min(1),
17238
+ forNodeId: string().min(1),
17190
17239
  ...QueryWindowShape
17191
17240
  }), QueryResultSchema, { auth: "admin" }), method(object({
17241
+ items: array(QueryManyItemSchema).min(1).max(24),
17242
+ from: QueryWindowShape.from,
17243
+ to: QueryWindowShape.to,
17244
+ resolution: QueryWindowShape.resolution,
17245
+ maxPoints: QueryWindowShape.maxPoints
17246
+ }), object({ results: array(QueryManyEntrySchema).readonly() }), { auth: "admin" }), method(object({
17192
17247
  name: string().regex(/^[a-z0-9-]+$/),
17193
17248
  subjectKind: _enum(["device", "node"]),
17194
- kind: DeviceHistoryKindSchema,
17249
+ kind: DeviceHistoryProducerKindSchema,
17195
17250
  unit: string().optional(),
17196
17251
  displayName: string().min(1),
17197
17252
  ingest: _enum(["points", "buckets"])
@@ -40429,14 +40484,106 @@ var LogEntrySchema = object({
40429
40484
  meta: record(string(), unknown()).optional(),
40430
40485
  tags: record(string(), string()).optional()
40431
40486
  });
40432
- method(LogEntrySchema, _void(), { kind: "mutation" }), method(object({
40433
- scope: array(string()).optional(),
40487
+ /**
40488
+ * A history READ against one destination (D898).
40489
+ *
40490
+ * Every filter is applied by the PROVIDER, before the limit — a filter the
40491
+ * browser applied after the limit is what made a rare device's lines
40492
+ * unreachable behind a busy one's. `before` / `after` are cursors the provider
40493
+ * minted (opaque to everyone else): a file position for the rotated files, a
40494
+ * nanosecond timestamp for Loki.
40495
+ *
40496
+ * A read is BOUNDED by `budgetMs`: a filter that matches nothing on a 30-day
40497
+ * store answers `done: false` with the cursor it reached and the bytes it
40498
+ * scanned, and the caller decides whether to go on. That is what makes a long
40499
+ * scan show progress and stop when asked — `cancelRead` ends the slice in
40500
+ * flight, and not asking for the next slice ends the scan.
40501
+ */
40502
+ var LogReadQuerySchema = object({
40503
+ /** Correlates `cancelRead`. Caller-chosen, unique per in-flight read. */
40504
+ requestId: string().min(1).max(64).optional(),
40505
+ /** The device the line is about (`tags.deviceId`, numeric). */
40506
+ deviceId: number().int().optional(),
40507
+ /**
40508
+ * The emitting addon — bare manifest id; `@<version>` / `::<sub>` suffixes
40509
+ * match. Not `addonId`: a cap router reads that name as "which provider".
40510
+ */
40511
+ fromAddonId: string().min(1).max(200).optional(),
40512
+ /**
40513
+ * The emitting node: matches the agent that emitted the line, the node
40514
+ * itself, or a worker under it (`<agent>/<runner>`) — the `agentId`
40515
+ * semantics of `matchesLogTags`. Not `nodeId`: a cap router reads that
40516
+ * name as "which node's provider".
40517
+ */
40518
+ fromNodeId: string().min(1).max(200).optional(),
40519
+ /** Any other tag, exact match (AND). */
40520
+ tags: record(string(), union([string(), number()])).optional(),
40521
+ /** Severity FLOOR: this level and above. */
40434
40522
  level: LogLevelSchema.optional(),
40435
- since: date().optional(),
40436
- until: date().optional(),
40437
- limit: number().optional(),
40438
- tags: record(string(), string()).optional()
40439
- }), array(LogEntrySchema).readonly());
40523
+ /** Case-insensitive substring over message, scope, tag values and meta values. */
40524
+ text: string().min(1).max(200).optional(),
40525
+ /** Epoch ms, inclusive. */
40526
+ since: number().optional(),
40527
+ /** Epoch ms, inclusive. */
40528
+ until: number().optional(),
40529
+ /** Older than this cursor (exclusive). Absent with `after` absent ⇒ from the newest. */
40530
+ before: string().min(1).max(1024).optional(),
40531
+ /** Newer than this cursor (exclusive). */
40532
+ after: string().min(1).max(1024).optional(),
40533
+ limit: number().int().min(1).max(1e3).optional(),
40534
+ /** Wall-clock bound of this slice. The provider caps it. */
40535
+ budgetMs: number().int().min(50).max(1e4).optional()
40536
+ });
40537
+ var LogReadResultSchema = object({
40538
+ /** Newest first. */
40539
+ entries: array(object({
40540
+ /** `<bootId>.<seq>` minted by the emitting LogManager — the dedupe key. */
40541
+ id: string().optional(),
40542
+ /** Epoch ms. */
40543
+ timestamp: number(),
40544
+ level: LogLevelSchema,
40545
+ scope: string().optional(),
40546
+ message: string(),
40547
+ tags: record(string(), union([string(), number()])).optional(),
40548
+ meta: record(string(), unknown()).optional()
40549
+ })),
40550
+ /** Pass as `before` for the next older page; null when nothing older exists. */
40551
+ nextBefore: string().nullable(),
40552
+ /** Pass as `after` to read what arrived since; null when unknown. */
40553
+ nextAfter: string().nullable(),
40554
+ /** Bytes this slice read (files) or received (remote). Progress, not a promise. */
40555
+ scannedBytes: number().int().nonnegative(),
40556
+ /**
40557
+ * True when the scan in this direction reached the end of the store.
40558
+ * False with fewer than `limit` entries means the budget ran out first —
40559
+ * call again with `nextBefore` to go on.
40560
+ */
40561
+ done: boolean(),
40562
+ /** True when `cancelRead` ended this slice early. */
40563
+ cancelled: boolean().optional()
40564
+ });
40565
+ var LogReadCapabilitiesSchema = object({
40566
+ /** False ⇒ this destination only ships lines (console, forwarder, an unconfigured Loki). */
40567
+ readable: boolean(),
40568
+ /** Why not, when `readable` is false — rendered next to the source. */
40569
+ reason: string().nullable(),
40570
+ /** Filters the provider applies itself. A false one is applied by nobody. */
40571
+ filters: object({
40572
+ deviceId: boolean(),
40573
+ addonId: boolean(),
40574
+ nodeId: boolean(),
40575
+ tags: boolean(),
40576
+ level: boolean(),
40577
+ text: boolean(),
40578
+ timeRange: boolean()
40579
+ }),
40580
+ /** How far back the store reaches, when the provider knows (days). */
40581
+ retentionDays: number().nullable()
40582
+ });
40583
+ 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() }), {
40584
+ kind: "mutation",
40585
+ auth: "admin"
40586
+ });
40440
40587
  /**
40441
40588
  * `login-method` — collection cap through which auth addons contribute
40442
40589
  * their pre-auth login surfaces to the login page. This is the SINGLE,
@@ -42154,9 +42301,11 @@ var alarmPanelCapability = {
42154
42301
  */
42155
42302
  durability: "restored",
42156
42303
  /**
42157
- * History (D850): none — enum state; arm/disarm history belongs in the events ledger.
42304
+ * History (D850): the panel's lifecycle state as an `enum` series —
42305
+ * change-only, no floor, so an `arming -> pending -> triggered` sequence of a
42306
+ * few seconds keeps every step. Who armed it stays in the events ledger.
42158
42307
  */
42159
- history: "none",
42308
+ history: { fields: { state: { kind: "enum" } } },
42160
42309
  /** Clock fields: written, but excluded from the compare that decides
42161
42310
  * whether persisting is worth a SQLite commit. */
42162
42311
  volatileStateFields: ["lastChangedAt"]
@@ -43034,6 +43183,33 @@ var NcRuleTargetSchema = object({
43034
43183
  params: record(string(), unknown()).optional()
43035
43184
  });
43036
43185
  /**
43186
+ * WHAT THE NOTIFICATION'S PICTURE IS (D897) — the ONE media choice of a rule.
43187
+ *
43188
+ * Every mode starts from the same CLEAN source frame of the trigger moment
43189
+ * (keyFrame → sceneFrame → lastSceneFrame, narrowed to the trigger instant and
43190
+ * to the zone that fired the rule) and renders it once at send time:
43191
+ * - `scene-boxes` — the whole scene, the subject outlined thick in the accent
43192
+ * colour and every OTHER track visible at that instant outlined thin, each
43193
+ * labelled with class and confidence ("dog 87%").
43194
+ * - `crop` — the subject cut out of that frame around its box at that instant.
43195
+ * - `clean` — the whole scene with nothing drawn on it.
43196
+ * - `none` — no picture.
43197
+ *
43198
+ * A mode that cannot be honoured (no box at that instant, a photograph with no
43199
+ * tracked subject) ships `clean` and names the reason in the log, per camera.
43200
+ * It replaces the `attach` × `frame` × `zoneCrop` triple, which let one rule
43201
+ * ship a crop on one event and a boxed scene on the next depending on which
43202
+ * stored kind had landed.
43203
+ */
43204
+ var NcMediaImageSchema = _enum([
43205
+ "scene-boxes",
43206
+ "crop",
43207
+ "clean",
43208
+ "none"
43209
+ ]);
43210
+ /**
43211
+ * @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
43212
+ *
43037
43213
  * Media attachment policy (P1 still-image subset).
43038
43214
  * - `best` — the best AVAILABLE subject image at dispatch time (D-3).
43039
43215
  * - `best-matching` — the media that explains WHY the rule fired: a rule
@@ -43047,6 +43223,8 @@ var NcRuleTargetSchema = object({
43047
43223
  * - `none` — no attachment.
43048
43224
  */
43049
43225
  /**
43226
+ * @deprecated Read only by `normalizeNcMediaPolicy` (D897) — see {@link NcMediaImageSchema}.
43227
+ *
43050
43228
  * WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
43051
43229
  * conflate it with the selection strategy and betray the request: asking for
43052
43230
  * the clean scene frame on an object-event owner used to start at
@@ -43075,16 +43253,29 @@ var NcMediaFrameSchema = _enum([
43075
43253
  */
43076
43254
  var NcLinkedCameraModeSchema = _enum(["mosaic", "each"]);
43077
43255
  var NcMediaPolicySchema = object({
43256
+ /**
43257
+ * The picture — see {@link NcMediaImageSchema}. Absent on a rule nobody has
43258
+ * saved since D897: `normalizeNcMediaPolicy` derives it from the legacy
43259
+ * triple below, at load and at every write, and the store keeps only this.
43260
+ */
43261
+ image: NcMediaImageSchema.optional(),
43262
+ /**
43263
+ * Draw the zone that FIRED the rule on the picture (`scene-boxes` / `clean`;
43264
+ * a `crop` never shows it). Valid only on a rule whose trigger is a zone —
43265
+ * `conditions.zones` or an occupancy zone — and refused on save otherwise.
43266
+ * Replaces `zoneCrop`.
43267
+ */
43268
+ showTriggerZone: boolean().optional(),
43269
+ /** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
43078
43270
  attach: _enum([
43079
43271
  "best",
43080
43272
  "best-matching",
43081
43273
  "keyFrame",
43082
43274
  "none"
43083
- ]).default("best"),
43084
- /** What the still shows. Absent = `cropped` (the historical `best` shape). */
43275
+ ]).optional(),
43276
+ /** @deprecated D897 — accepted from an editor that predates `image`, folded into it on save. */
43085
43277
  frame: NcMediaFrameSchema.optional(),
43086
- /** Crop the attached still to the rule's condition-zone bbox (padded) —
43087
- * "show me the ZONE", not the whole scene or the subject crop. */
43278
+ /** @deprecated D897 — folded into `image: 'clean'` + `showTriggerZone` on save. */
43088
43279
  zoneCrop: boolean().optional(),
43089
43280
  /**
43090
43281
  * Also attach a short GIF cut from the stream broker's clip ring around the
@@ -43256,7 +43447,9 @@ var NcRuleInputSchema = object({
43256
43447
  * targets.
43257
43448
  */
43258
43449
  targetUsers: array(string()).optional(),
43259
- media: NcMediaPolicySchema.default({ attach: "best" }),
43450
+ /** Absent = the kind's default picture (`resolveNcMediaImage`): the subject crop for a
43451
+ * detection, the clean scene for a sensor or a sound. Set explicitly on save (D897). */
43452
+ media: NcMediaPolicySchema.default({}),
43260
43453
  throttle: NcThrottleSchema.default({
43261
43454
  cooldownSec: 60,
43262
43455
  scope: "rule-device"
@@ -44193,13 +44386,37 @@ var NcAlarmModeOpeningsSchema = object({
44193
44386
  /** Covered devices whose state could not be read (D49): neither open nor closed. */
44194
44387
  unknown: array(number().int())
44195
44388
  });
44389
+ /**
44390
+ * One alarm INPUT — a (rule, device) pair — the operator bypassed until the
44391
+ * next disarm ("Bypass this input until disarm" on a trigger notification, or
44392
+ * `nc.bypassAlarmInput`). Reported so an armed alarm with a silenced input
44393
+ * never looks fully armed (D62: off must never look like broken).
44394
+ */
44395
+ var NcAlarmInputBypassViewSchema = object({
44396
+ ruleId: string(),
44397
+ /** The rule's current name (its frozen name when the rule is gone). */
44398
+ ruleName: string(),
44399
+ /** The input: the sensor of the match, else its camera. */
44400
+ deviceId: number().int(),
44401
+ /** The input's current name. */
44402
+ name: string(),
44403
+ /** When it was bypassed (ms epoch). */
44404
+ since: number(),
44405
+ /** Triggers from this input dropped since. */
44406
+ dropped: number().int().min(0)
44407
+ });
44196
44408
  var NcAlarmLiveSchema = object({
44197
44409
  state: AlarmStateSchema,
44198
44410
  /** The mode being armed into (exit delay) or held; null when disarmed. */
44199
44411
  targetMode: AlarmArmModeSchema.nullable(),
44200
44412
  availableModes: array(AlarmArmModeSchema),
44201
44413
  openings: array(NcAlarmModeOpeningsSchema),
44202
- exclusions: array(NcAlarmExclusionViewSchema)
44414
+ exclusions: array(NcAlarmExclusionViewSchema),
44415
+ /**
44416
+ * Inputs bypassed for the rest of this arm session; cleared on disarm.
44417
+ * Defaulted so an older hub answer still parses (as "none known").
44418
+ */
44419
+ bypassedInputs: array(NcAlarmInputBypassViewSchema).default([])
44203
44420
  });
44204
44421
  var NcAlarmConfigSchema = object({
44205
44422
  /**
@@ -54943,9 +55160,11 @@ var connectivityCapability = {
54943
55160
  */
54944
55161
  durability: "restored",
54945
55162
  /**
54946
- * History (D850): none — duplicates device-status.online (one authority for availability).
55163
+ * History (D850): `connected` as a boolean series — change-only, no floor. It
55164
+ * is the upstream entity's own link (a HA connectivity sensor), not the
55165
+ * device's reachability, which stays `device-status.online`.
54947
55166
  */
54948
- history: "none",
55167
+ history: { fields: { connected: { kind: "boolean" } } },
54949
55168
  /** Clock fields: written, but excluded from the compare that decides
54950
55169
  * whether persisting is worth a SQLite commit. */
54951
55170
  volatileStateFields: ["lastChangedAt"]
@@ -55769,11 +55988,22 @@ var dishwasherCapability = {
55769
55988
  },
55770
55989
  runtimeState: DishwasherStatusSchema,
55771
55990
  durability: "session",
55772
- history: { fields: { progressPercent: {
55773
- kind: "gauge",
55774
- unit: "%",
55775
- deadband: 2
55776
- } } }
55991
+ history: { fields: {
55992
+ progressPercent: {
55993
+ kind: "gauge",
55994
+ unit: "%",
55995
+ deadband: 2
55996
+ },
55997
+ state: { kind: "enum" },
55998
+ operationState: { kind: "enum" },
55999
+ remainingSeconds: {
56000
+ kind: "gauge",
56001
+ unit: "s",
56002
+ minIntervalMs: 6e4
56003
+ },
56004
+ doorOpen: { kind: "boolean" },
56005
+ powerOn: { kind: "boolean" }
56006
+ } }
55777
56007
  };
55778
56008
  var DoorbellStatusSchema = object({
55779
56009
  /** Ms epoch of the last press. null = never observed since this provider started. */
@@ -55890,9 +56120,15 @@ var enumSensorCapability = {
55890
56120
  */
55891
56121
  durability: "restored",
55892
56122
  /**
55893
- * History (D850): none — text/enum state has no history (non-goal).
56123
+ * History (D850): the value as an `enum` series (an appliance's program or
56124
+ * operation state, an HVAC action). The option set is per device, so the
56125
+ * value list is LEARNED as values are first seen (bounded). A sensor with a
56126
+ * `format` carries a timestamp, not a state, and is not recorded.
55894
56127
  */
55895
- history: "none",
56128
+ history: { fields: { value: {
56129
+ kind: "enum",
56130
+ skipWhenSet: "format"
56131
+ } } },
55896
56132
  /** Clock fields: written, but excluded from the compare that decides
55897
56133
  * whether persisting is worth a SQLite commit. */
55898
56134
  volatileStateFields: ["lastFetchedAt"]
@@ -57866,9 +58102,10 @@ var lockControlCapability = {
57866
58102
  */
57867
58103
  durability: "restored",
57868
58104
  /**
57869
- * History (D850): none — enum state; lock events belong in the events ledger.
58105
+ * History (D850): the lock's state as an `enum` series — change-only, no
58106
+ * floor: a jam or an unlock lasting seconds is the edge an operator looks for.
57870
58107
  */
57871
- history: "none",
58108
+ history: { fields: { state: { kind: "enum" } } },
57872
58109
  /** Clock fields: written, but excluded from the compare that decides
57873
58110
  * whether persisting is worth a SQLite commit. */
57874
58111
  volatileStateFields: ["lastChangedAt"]
@@ -58042,9 +58279,18 @@ var mediaPlayerCapability = {
58042
58279
  */
58043
58280
  durability: "session",
58044
58281
  /**
58045
- * History (D850): none — `positionMs` moves continuously while playing; volume is transient.
58282
+ * History (D850): volume (a level an operator or an automation sets; the
58283
+ * default 10 s floor folds a slider drag into its end value) and mute.
58284
+ * `positionMs` is not recorded: it moves continuously while playing.
58046
58285
  */
58047
- history: "none"
58286
+ history: { fields: {
58287
+ volumeLevel: {
58288
+ kind: "gauge",
58289
+ unit: "%",
58290
+ deadband: 1
58291
+ },
58292
+ isMuted: { kind: "boolean" }
58293
+ } }
58048
58294
  };
58049
58295
  /**
58050
58296
  * mesh-network — collection cap for mesh-VPN providers.
@@ -63485,9 +63731,29 @@ var streamParamsCapability = {
63485
63731
  */
63486
63732
  durability: "restored",
63487
63733
  /**
63488
- * History (D850): none — encoder configuration.
63734
+ * History (D850): the configured bitrate and frame rate of the main and sub
63735
+ * profiles. Configuration, so change-only on the default floor: a point is an
63736
+ * operator's (or a tuner's) edit, which is exactly what a chart of a stream's
63737
+ * quality over time must show.
63489
63738
  */
63490
- history: "none",
63739
+ history: { fields: {
63740
+ "main.bitrate": {
63741
+ kind: "gauge",
63742
+ unit: "kbps"
63743
+ },
63744
+ "main.framerate": {
63745
+ kind: "gauge",
63746
+ unit: "fps"
63747
+ },
63748
+ "sub.bitrate": {
63749
+ kind: "gauge",
63750
+ unit: "kbps"
63751
+ },
63752
+ "sub.framerate": {
63753
+ kind: "gauge",
63754
+ unit: "fps"
63755
+ }
63756
+ } },
63491
63757
  /** Clock fields: written, but excluded from the compare that decides
63492
63758
  * whether persisting is worth a SQLite commit. */
63493
63759
  volatileStateFields: ["lastFetchedAt"]
@@ -66665,6 +66931,15 @@ var BaseDevice$1 = class {
66665
66931
  * Drivers can use the `getProbeFlags()` helper to read the flag bag
66666
66932
  * with a typed cast.
66667
66933
  *
66934
+ * Answer what you KNOW. A plain array is read as the complete list only
66935
+ * while this device is `online` and probed; return
66936
+ * `accessoryChildrenUnknown(reason)` whenever you cannot know the list right
66937
+ * now (no credentials, parent not connected, a failed or partial read) —
66938
+ * the kernel then deletes nothing. Return `accessoryChildrenComplete(list)`
66939
+ * to say "connected, and this is the complete list" explicitly. A shrink is
66940
+ * deleted only after a second agreeing complete read on a later probe (D49;
66941
+ * `packages/system/src/kernel/moleculer/accessory-prune-gate.ts`).
66942
+ *
66668
66943
  * Default: no children.
66669
66944
  */
66670
66945
  getAccessoryChildren() {
@@ -66688,6 +66963,22 @@ var BaseDevice$1 = class {
66688
66963
  return (this.runtimeState.getCapState("feature-probe")?.lastProbedAt ?? 0) > 0;
66689
66964
  }
66690
66965
  };
66966
+ function accessoryChildrenUnknown(reason, known) {
66967
+ return known === void 0 ? {
66968
+ kind: "unknown",
66969
+ reason
66970
+ } : {
66971
+ kind: "unknown",
66972
+ reason,
66973
+ known
66974
+ };
66975
+ }
66976
+ function accessoryChildrenComplete(children) {
66977
+ return {
66978
+ kind: "complete",
66979
+ children
66980
+ };
66981
+ }
66691
66982
  /**
66692
66983
  * Delays before retry rounds 1..N — the round count IS the bound.
66693
66984
  * 10 s catches "the hub was busy for a moment"; the full schedule
@@ -70796,7 +71087,19 @@ Object.freeze({
70796
71087
  addonId: null,
70797
71088
  access: "view"
70798
71089
  },
70799
- "logDestination.query": {
71090
+ "logDestination.cancelRead": {
71091
+ capName: "log-destination",
71092
+ capScope: "system",
71093
+ addonId: null,
71094
+ access: "create"
71095
+ },
71096
+ "logDestination.describeRead": {
71097
+ capName: "log-destination",
71098
+ capScope: "system",
71099
+ addonId: null,
71100
+ access: "view"
71101
+ },
71102
+ "logDestination.read": {
70800
71103
  capName: "log-destination",
70801
71104
  capScope: "system",
70802
71105
  addonId: null,
@@ -76803,6 +77106,11 @@ Object.freeze({
76803
77106
  form: "single",
76804
77107
  optional: false
76805
77108
  }],
77109
+ "logDestination.read": [{
77110
+ name: "deviceId",
77111
+ form: "single",
77112
+ optional: true
77113
+ }],
76806
77114
  "mediaPlayer.getStatus": [{
76807
77115
  name: "deviceId",
76808
77116
  form: "single",
@@ -134209,7 +134517,7 @@ var DreameChildDevice = class extends BaseDevice$1 {
134209
134517
  this.dreameDeviceId = persisted.dreameDeviceId;
134210
134518
  this.brokerId = persisted.brokerId;
134211
134519
  this.model = persisted.model;
134212
- this.online = true;
134520
+ this.online = dreameFacades.getDevice(this.brokerId, this.dreameDeviceId) !== null;
134213
134521
  this.updateSourceInfo({
134214
134522
  id: this.dreameDeviceId,
134215
134523
  system: "dreame"
@@ -183856,7 +184164,28 @@ var DreameContainerDevice = class extends BaseDevice$1 {
183856
184164
  system: "dreame"
183857
184165
  });
183858
184166
  }
184167
+ /**
184168
+ * The child list is known only while the cloud device is REACHABLE: every
184169
+ * presence-filtered child is derived from the live handle. Without it (no
184170
+ * credentials, cloud down, before the first connect) the answer is UNKNOWN —
184171
+ * the kernel then deletes nothing (D49; it deleted 97 accessories when this
184172
+ * answered only the core child) — and only the core child is named to spawn.
184173
+ */
183859
184174
  getAccessoryChildren() {
184175
+ const specs = this.buildChildSpecs();
184176
+ if (dreameFacades.getDevice(this.brokerId, this.dreameDeviceId) === null) {
184177
+ this.ctx.logger.info("DreameContainerDevice: cloud device not reachable; child list unknown", {
184178
+ tags: { deviceId: this.id },
184179
+ meta: {
184180
+ dreameDeviceId: this.dreameDeviceId,
184181
+ integrationId: this.brokerId
184182
+ }
184183
+ });
184184
+ return accessoryChildrenUnknown("dreame cloud device not reachable", specs.slice(0, 1));
184185
+ }
184186
+ return accessoryChildrenComplete(specs);
184187
+ }
184188
+ buildChildSpecs() {
183860
184189
  const kind = classifyDreameModel(this.model);
183861
184190
  if (kind === "unsupported") {
183862
184191
  this.ctx.logger.warn("DreameContainerDevice: unsupported model; no children", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-dreame",
3
- "version": "0.2.138",
3
+ "version": "0.2.139",
4
4
  "description": "Dreame robot-vacuum / lawn-mower device-provider addon for CamStack — wraps the @apocaliss92/nodedreame Dreamehome cloud client",
5
5
  "keywords": [
6
6
  "camstack",