@camstack/addon-provider-bosch 0.1.15 → 0.1.16

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.
@@ -1,4 +1,4 @@
1
- import { b as errMsg } from "./dist-hm2fhp2t.mjs";
1
+ import { b as errMsg } from "./dist-PdvgOyAy.mjs";
2
2
  //#region src/shared/oauth-callback.ts
3
3
  /** A code on its own: no scheme, no query, no separators. */
4
4
  var BARE_CODE = /^[A-Za-z0-9._~-]+$/;
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-ChJRdNGo.js");
1
+ const require_dist = require("./dist-BUFPeAeI.js");
2
2
  //#region src/shared/oauth-callback.ts
3
3
  /** A code on its own: no scheme, no query, no separators. */
4
4
  var BARE_CODE = /^[A-Za-z0-9._~-]+$/;
@@ -1,5 +1,5 @@
1
1
  require("node:crypto");
2
- //#region ../types/dist/event-category-7pZEBmVg.mjs
2
+ //#region ../types/dist/event-category-BfJwUd2S.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -316,6 +316,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
316
316
  */
317
317
  EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
318
318
  /**
319
+ * A camera's motion source has fired constantly with no subject for an hour
320
+ * (motion duty or session count over the bar, zero detections) — it is not
321
+ * blind, its motion zones or sensitivity want tuning (D907). Paired with
322
+ * {@link PipelineMotionCalm}.
323
+ */
324
+ EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
325
+ /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
326
+ EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
327
+ /**
319
328
  * Per-camera pipeline config was mutated by the orchestrator
320
329
  * (3-level settings change via `setAgentAddonDefaults` /
321
330
  * `setCameraStepToggle` / `setCameraPipelineForAgent` or a
@@ -5422,7 +5431,7 @@ var ZodIssueCode = {
5422
5431
  var ZodFirstPartyTypeKind;
5423
5432
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5424
5433
  //#endregion
5425
- //#region ../types/dist/sleep-CueztlR1.mjs
5434
+ //#region ../types/dist/sleep-DJFUfKvA.mjs
5426
5435
  /**
5427
5436
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5428
5437
  * window to float samples (D455).
@@ -7955,7 +7964,7 @@ var EntryDescriptorSchema = object({
7955
7964
  /** JSON Schema of the entry body; `secret: true` marks a password field. */
7956
7965
  fields: record(string(), unknown())
7957
7966
  }).strict();
7958
- /** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
7967
+ /** What crosses the wire from an addon: JSON only, no Zod. An unknown key is refused. */
7959
7968
  var RecordKindDeclarationSchema = object({
7960
7969
  database: _enum(RECORD_DATABASES).default("settings"),
7961
7970
  class: _enum(RECORD_CLASSES),
@@ -7974,14 +7983,6 @@ var RecordKindDeclarationSchema = object({
7974
7983
  secretPaths: array(string().min(1)).default([]),
7975
7984
  /** The id key of each array that carries a secret (`{ headers: 'name' }`). */
7976
7985
  secretArrayKeys: record(string(), string()).default({}),
7977
- /**
7978
- * RETIRED (D900): the legacy table a kind adopted from during the records
7979
- * migration. Nothing declares it any more and nothing reads it; the schema
7980
- * still ACCEPTS it because the catalog rows the migration wrote carry it
7981
- * (an orphaned kind is never redeclared) and an addon built before the
7982
- * removal still sends it. Never set it.
7983
- */
7984
- adoptsFrom: string().min(1).optional(),
7985
7986
  /** Kinds that must agree through `transact` sit in one file under one family name. */
7986
7987
  transactFamily: string().min(1).optional(),
7987
7988
  entry: EntryDescriptorSchema.optional()
@@ -12681,17 +12682,6 @@ object({
12681
12682
  createdAt: number(),
12682
12683
  updatedAt: number()
12683
12684
  });
12684
- object({
12685
- id: string(),
12686
- label: string(),
12687
- isAdmin: boolean().default(false),
12688
- allowedProviders: AllowedProviderSchema,
12689
- allowedDevices: AllowedDevicesSchema,
12690
- tokenHash: string(),
12691
- tokenPrefix: string(),
12692
- createdAt: number(),
12693
- lastUsedAt: number().optional()
12694
- });
12695
12685
  object({
12696
12686
  id: string(),
12697
12687
  userId: string(),
@@ -16673,16 +16663,36 @@ var RecordKindStateSchema = _enum([
16673
16663
  var DeclareKindResultSchema = object({
16674
16664
  kindId: number().int(),
16675
16665
  state: RecordKindStateSchema,
16676
- createdIndexes: array(string()),
16677
- /**
16678
- * RETIRED (D900): always `null`. It carried the records-migration boot guard;
16679
- * it stays on the wire, null, because an addon built before the removal reads
16680
- * an ABSENT field as "adoption pending" and refuses to start.
16681
- */
16682
- adoptionPending: _null()
16666
+ createdIndexes: array(string())
16683
16667
  });
16684
16668
  /** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
16685
16669
  var SecretRefsList = array(string());
16670
+ /**
16671
+ * One op of a `transact`: the single-row writes, each on a kind of the caller.
16672
+ * All ops of one call share ONE database file and ONE `transactFamily`.
16673
+ */
16674
+ var RecordTransactOpSchema = discriminatedUnion("op", [
16675
+ object({
16676
+ op: literal("put"),
16677
+ kind: RecordKindNameSchema,
16678
+ record: RecordInputSchema,
16679
+ ifRev: number().int().min(0).optional()
16680
+ }),
16681
+ object({
16682
+ op: literal("patch"),
16683
+ kind: RecordKindNameSchema,
16684
+ id: RecordIdSchema,
16685
+ data: RecordBodySchema,
16686
+ at: number().int().nullable().optional(),
16687
+ expiresAt: number().int().nullable().optional(),
16688
+ ifRev: number().int().min(1).optional()
16689
+ }),
16690
+ object({
16691
+ op: literal("delete"),
16692
+ kind: RecordKindNameSchema,
16693
+ id: RecordIdSchema
16694
+ })
16695
+ ]);
16686
16696
  var RecordSecretRefsSchema = record(string(), record(string(), string()));
16687
16697
  method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string(), DeclareKindResultSchema) }), {
16688
16698
  kind: "mutation",
@@ -16789,6 +16799,16 @@ method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema)
16789
16799
  }), {
16790
16800
  kind: "mutation",
16791
16801
  auth: "admin"
16802
+ }), method(object({ ops: array(RecordTransactOpSchema).min(1).max(RECORD_BATCH_MAX) }), object({
16803
+ results: array(object({
16804
+ rev: number().int().nullable(),
16805
+ deleted: boolean()
16806
+ })),
16807
+ releasedRefs: SecretRefsList,
16808
+ secretRefs: SecretRefsList
16809
+ }), {
16810
+ kind: "mutation",
16811
+ auth: "admin"
16792
16812
  }), method(object({
16793
16813
  deviceId: number().int(),
16794
16814
  kinds: array(RecordKindNameSchema).optional()
@@ -42400,9 +42420,13 @@ var NcSystemEventKindSchema = _enum([
42400
42420
  "node-updating",
42401
42421
  "node-inference-unavailable",
42402
42422
  "detection-blind",
42423
+ "motion-noisy",
42424
+ "motion-calm",
42403
42425
  "recording-stalled",
42404
42426
  "recording-healthy",
42405
42427
  "recording-degraded",
42428
+ "device-attention-required",
42429
+ "device-attention-resolved",
42406
42430
  "storage-location-low",
42407
42431
  "storage-location-critical",
42408
42432
  "storage-location-ok",
@@ -55734,6 +55758,16 @@ var DishwasherStatusSchema = object({
55734
55758
  powerState: string().nullable(),
55735
55759
  saltLevel: DishwasherConsumableLevelSchema.nullable(),
55736
55760
  rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55761
+ /**
55762
+ * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55763
+ * combined care-and-filter reminder raised); false when every such reminder reads clear; null
55764
+ * when none is reported. A cleared reminder is not an unknown one.
55765
+ */
55766
+ filterCleaningDue: boolean().nullable(),
55767
+ /** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
55768
+ machineCareDue: boolean().nullable(),
55769
+ /** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
55770
+ machineCareRemainingRuns: number().int().nonnegative().nullable(),
55737
55771
  /** Option states: null when the appliance does not expose the option or has not said. */
55738
55772
  halfLoad: boolean().nullable(),
55739
55773
  hygienePlus: boolean().nullable(),
@@ -64384,16 +64418,6 @@ var UpdateUserInputSchema = object({
64384
64418
  allowedDevices: record(string(), union([array(string()), literal("*")])).optional(),
64385
64419
  scopes: array(TokenScopeSchema).optional()
64386
64420
  });
64387
- var ApiKeySummarySchema = object({
64388
- id: string(),
64389
- label: string(),
64390
- isAdmin: boolean().default(false),
64391
- allowedProviders: union([array(string()), literal("*")]).optional(),
64392
- allowedDevices: record(string(), union([array(string()), literal("*")])).optional(),
64393
- tokenPrefix: string(),
64394
- createdAt: number(),
64395
- lastUsedAt: number().optional()
64396
- });
64397
64421
  var OauthSessionSummarySchema = object({
64398
64422
  id: string(),
64399
64423
  userId: string(),
@@ -64415,8 +64439,7 @@ var TotpStatusSchema = object({
64415
64439
  confirmedAt: number().nullable()
64416
64440
  });
64417
64441
  /**
64418
- * user-management — singleton capability for user accounts and the
64419
- * legacy API-key rows.
64442
+ * user-management — singleton capability for user accounts.
64420
64443
  *
64421
64444
  * v2 model: every method gated by `auth: 'admin'`. Admin-only delegation
64422
64445
  * — the subset check on `setUserScopes` is moot
@@ -64472,10 +64495,6 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64472
64495
  }), UserSummarySchema.extend({ passwordHash: string() }).nullable(), {
64473
64496
  kind: "mutation",
64474
64497
  access: "view"
64475
- }), method(_void(), array(ApiKeySummarySchema), { auth: "admin" }), method(object({ id: string() }), object({ success: literal(true) }), {
64476
- kind: "mutation",
64477
- auth: "admin",
64478
- access: "delete"
64479
64498
  }), method(object({ userId: string() }), TotpSetupResultSchema, {
64480
64499
  kind: "mutation",
64481
64500
  auth: "admin",
@@ -73931,6 +73950,12 @@ Object.freeze({
73931
73950
  addonId: null,
73932
73951
  access: "view"
73933
73952
  },
73953
+ "records.transact": {
73954
+ capName: "records",
73955
+ capScope: "system",
73956
+ addonId: null,
73957
+ access: "create"
73958
+ },
73934
73959
  "sceneMonitor.captureReference": {
73935
73960
  capName: "scene-monitor",
73936
73961
  capScope: "device",
@@ -75263,12 +75288,6 @@ Object.freeze({
75263
75288
  addonId: null,
75264
75289
  access: "view"
75265
75290
  },
75266
- "userManagement.listApiKeys": {
75267
- capName: "user-management",
75268
- capScope: "system",
75269
- addonId: null,
75270
- access: "view"
75271
- },
75272
75291
  "userManagement.listExternalIdentities": {
75273
75292
  capName: "user-management",
75274
75293
  capScope: "system",
@@ -75323,12 +75342,6 @@ Object.freeze({
75323
75342
  addonId: null,
75324
75343
  access: "create"
75325
75344
  },
75326
- "userManagement.revokeApiKey": {
75327
- capName: "user-management",
75328
- capScope: "system",
75329
- addonId: null,
75330
- access: "delete"
75331
- },
75332
75345
  "userManagement.revokeOauthSession": {
75333
75346
  capName: "user-management",
75334
75347
  capScope: "system",
@@ -78693,9 +78706,13 @@ new Map(Object.entries({
78693
78706
  "stream-online": "device-events",
78694
78707
  "stream-offline": "device-events",
78695
78708
  "detection-blind": "device-events",
78709
+ "motion-noisy": "device-events",
78710
+ "motion-calm": "device-events",
78696
78711
  "recording-stalled": "device-events",
78697
78712
  "recording-healthy": "device-events",
78698
78713
  "recording-degraded": "device-events",
78714
+ "device-attention-required": "device-events",
78715
+ "device-attention-resolved": "device-events",
78699
78716
  "node-online": "system",
78700
78717
  "node-offline": "system",
78701
78718
  "node-restarting": "system",
@@ -78778,6 +78795,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
78778
78795
  label: "Detecting nothing",
78779
78796
  kinds: ["detection-blind"]
78780
78797
  },
78798
+ {
78799
+ id: "motion-noise",
78800
+ family: "device-events",
78801
+ label: "Motion without a subject",
78802
+ kinds: ["motion-noisy", "motion-calm"]
78803
+ },
78781
78804
  {
78782
78805
  id: "recording",
78783
78806
  family: "device-events",
@@ -78788,6 +78811,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
78788
78811
  "recording-degraded"
78789
78812
  ]
78790
78813
  },
78814
+ {
78815
+ id: "device-attention",
78816
+ family: "device-events",
78817
+ label: "Needs attention",
78818
+ kinds: ["device-attention-required", "device-attention-resolved"]
78819
+ },
78791
78820
  {
78792
78821
  id: "nodes",
78793
78822
  family: "system",
@@ -78927,6 +78956,7 @@ var ALERT_EPISODE = [
78927
78956
  "alert-error",
78928
78957
  "alert-critical-resolved"
78929
78958
  ];
78959
+ var DEVICE_ATTENTION = ["device-attention-required", "device-attention-resolved"];
78930
78960
  var UPDATES = [
78931
78961
  "addon-update-available",
78932
78962
  "server-update-available",
@@ -78956,9 +78986,12 @@ var DEVICE_EVENTS = [
78956
78986
  "stream-online",
78957
78987
  "stream-offline",
78958
78988
  "detection-blind",
78989
+ "motion-noisy",
78990
+ "motion-calm",
78959
78991
  "recording-stalled",
78960
78992
  "recording-healthy",
78961
78993
  "recording-degraded",
78994
+ ...DEVICE_ATTENTION,
78962
78995
  ...ALARM
78963
78996
  ];
78964
78997
  /** Every kind a summary may speak about — the two summarisable families. */
@@ -79126,7 +79159,9 @@ var STATE_SUMMARY_VARS = [
79126
79159
  [...RULE_TEXT],
79127
79160
  [...RULE_TEXT],
79128
79161
  [...RULE_TEXT],
79129
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79162
+ [...RULE_TEXT],
79163
+ [...RULE_TEXT],
79164
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79130
79165
  [...RULE_TEXT],
79131
79166
  [...RULE_TEXT],
79132
79167
  [...RULE_TEXT],
@@ -79148,11 +79183,11 @@ var STATE_SUMMARY_VARS = [
79148
79183
  [...RULE_TEXT],
79149
79184
  [...RULE_TEXT],
79150
79185
  [...RULE_TEXT],
79186
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79151
79187
  ([...RULE_TEXT], [...ALERT_EPISODE]),
79188
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79152
79189
  ([...RULE_TEXT], [...ALERT_EPISODE]),
79153
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79154
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79155
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79190
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79156
79191
  [...RULE_TEXT],
79157
79192
  [...RULE_TEXT],
79158
79193
  [...RULE_TEXT],
@@ -79228,6 +79263,15 @@ new Map([
79228
79263
  snapshotLabel: "Tanks low or full now",
79229
79264
  snapshotSection: "tanks"
79230
79265
  },
79266
+ {
79267
+ id: "motion-noise",
79268
+ family: "device-events",
79269
+ label: "Motion without a subject (constant / calm again)",
79270
+ bad: ["motion-noisy"],
79271
+ recovery: ["motion-calm"],
79272
+ snapshotLabel: "Cameras with constant motion now",
79273
+ snapshotSection: null
79274
+ },
79231
79275
  {
79232
79276
  id: "recording-health",
79233
79277
  family: "device-events",
@@ -79237,6 +79281,15 @@ new Map([
79237
79281
  snapshotLabel: "Recordings stalled now",
79238
79282
  snapshotSection: null
79239
79283
  },
79284
+ {
79285
+ id: "device-attention",
79286
+ family: "device-events",
79287
+ label: "Device needs attention (raised / resolved)",
79288
+ bad: ["device-attention-required"],
79289
+ recovery: ["device-attention-resolved"],
79290
+ snapshotLabel: "Devices needing attention now",
79291
+ snapshotSection: null
79292
+ },
79240
79293
  {
79241
79294
  id: "node-connectivity",
79242
79295
  family: "system",
@@ -1,5 +1,5 @@
1
1
  import "node:crypto";
2
- //#region ../types/dist/event-category-7pZEBmVg.mjs
2
+ //#region ../types/dist/event-category-BfJwUd2S.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -316,6 +316,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
316
316
  */
317
317
  EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
318
318
  /**
319
+ * A camera's motion source has fired constantly with no subject for an hour
320
+ * (motion duty or session count over the bar, zero detections) — it is not
321
+ * blind, its motion zones or sensitivity want tuning (D907). Paired with
322
+ * {@link PipelineMotionCalm}.
323
+ */
324
+ EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
325
+ /** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
326
+ EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
327
+ /**
319
328
  * Per-camera pipeline config was mutated by the orchestrator
320
329
  * (3-level settings change via `setAgentAddonDefaults` /
321
330
  * `setCameraStepToggle` / `setCameraPipelineForAgent` or a
@@ -5422,7 +5431,7 @@ var ZodIssueCode = {
5422
5431
  var ZodFirstPartyTypeKind;
5423
5432
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5424
5433
  //#endregion
5425
- //#region ../types/dist/sleep-CueztlR1.mjs
5434
+ //#region ../types/dist/sleep-DJFUfKvA.mjs
5426
5435
  /**
5427
5436
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5428
5437
  * window to float samples (D455).
@@ -7955,7 +7964,7 @@ var EntryDescriptorSchema = object({
7955
7964
  /** JSON Schema of the entry body; `secret: true` marks a password field. */
7956
7965
  fields: record(string(), unknown())
7957
7966
  }).strict();
7958
- /** What crosses the wire and sits in the engine's catalog: JSON only, no Zod. */
7967
+ /** What crosses the wire from an addon: JSON only, no Zod. An unknown key is refused. */
7959
7968
  var RecordKindDeclarationSchema = object({
7960
7969
  database: _enum(RECORD_DATABASES).default("settings"),
7961
7970
  class: _enum(RECORD_CLASSES),
@@ -7974,14 +7983,6 @@ var RecordKindDeclarationSchema = object({
7974
7983
  secretPaths: array(string().min(1)).default([]),
7975
7984
  /** The id key of each array that carries a secret (`{ headers: 'name' }`). */
7976
7985
  secretArrayKeys: record(string(), string()).default({}),
7977
- /**
7978
- * RETIRED (D900): the legacy table a kind adopted from during the records
7979
- * migration. Nothing declares it any more and nothing reads it; the schema
7980
- * still ACCEPTS it because the catalog rows the migration wrote carry it
7981
- * (an orphaned kind is never redeclared) and an addon built before the
7982
- * removal still sends it. Never set it.
7983
- */
7984
- adoptsFrom: string().min(1).optional(),
7985
7986
  /** Kinds that must agree through `transact` sit in one file under one family name. */
7986
7987
  transactFamily: string().min(1).optional(),
7987
7988
  entry: EntryDescriptorSchema.optional()
@@ -12681,17 +12682,6 @@ object({
12681
12682
  createdAt: number(),
12682
12683
  updatedAt: number()
12683
12684
  });
12684
- object({
12685
- id: string(),
12686
- label: string(),
12687
- isAdmin: boolean().default(false),
12688
- allowedProviders: AllowedProviderSchema,
12689
- allowedDevices: AllowedDevicesSchema,
12690
- tokenHash: string(),
12691
- tokenPrefix: string(),
12692
- createdAt: number(),
12693
- lastUsedAt: number().optional()
12694
- });
12695
12685
  object({
12696
12686
  id: string(),
12697
12687
  userId: string(),
@@ -16673,16 +16663,36 @@ var RecordKindStateSchema = _enum([
16673
16663
  var DeclareKindResultSchema = object({
16674
16664
  kindId: number().int(),
16675
16665
  state: RecordKindStateSchema,
16676
- createdIndexes: array(string()),
16677
- /**
16678
- * RETIRED (D900): always `null`. It carried the records-migration boot guard;
16679
- * it stays on the wire, null, because an addon built before the removal reads
16680
- * an ABSENT field as "adoption pending" and refuses to start.
16681
- */
16682
- adoptionPending: _null()
16666
+ createdIndexes: array(string())
16683
16667
  });
16684
16668
  /** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
16685
16669
  var SecretRefsList = array(string());
16670
+ /**
16671
+ * One op of a `transact`: the single-row writes, each on a kind of the caller.
16672
+ * All ops of one call share ONE database file and ONE `transactFamily`.
16673
+ */
16674
+ var RecordTransactOpSchema = discriminatedUnion("op", [
16675
+ object({
16676
+ op: literal("put"),
16677
+ kind: RecordKindNameSchema,
16678
+ record: RecordInputSchema,
16679
+ ifRev: number().int().min(0).optional()
16680
+ }),
16681
+ object({
16682
+ op: literal("patch"),
16683
+ kind: RecordKindNameSchema,
16684
+ id: RecordIdSchema,
16685
+ data: RecordBodySchema,
16686
+ at: number().int().nullable().optional(),
16687
+ expiresAt: number().int().nullable().optional(),
16688
+ ifRev: number().int().min(1).optional()
16689
+ }),
16690
+ object({
16691
+ op: literal("delete"),
16692
+ kind: RecordKindNameSchema,
16693
+ id: RecordIdSchema
16694
+ })
16695
+ ]);
16686
16696
  var RecordSecretRefsSchema = record(string(), record(string(), string()));
16687
16697
  method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string(), DeclareKindResultSchema) }), {
16688
16698
  kind: "mutation",
@@ -16789,6 +16799,16 @@ method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema)
16789
16799
  }), {
16790
16800
  kind: "mutation",
16791
16801
  auth: "admin"
16802
+ }), method(object({ ops: array(RecordTransactOpSchema).min(1).max(RECORD_BATCH_MAX) }), object({
16803
+ results: array(object({
16804
+ rev: number().int().nullable(),
16805
+ deleted: boolean()
16806
+ })),
16807
+ releasedRefs: SecretRefsList,
16808
+ secretRefs: SecretRefsList
16809
+ }), {
16810
+ kind: "mutation",
16811
+ auth: "admin"
16792
16812
  }), method(object({
16793
16813
  deviceId: number().int(),
16794
16814
  kinds: array(RecordKindNameSchema).optional()
@@ -42400,9 +42420,13 @@ var NcSystemEventKindSchema = _enum([
42400
42420
  "node-updating",
42401
42421
  "node-inference-unavailable",
42402
42422
  "detection-blind",
42423
+ "motion-noisy",
42424
+ "motion-calm",
42403
42425
  "recording-stalled",
42404
42426
  "recording-healthy",
42405
42427
  "recording-degraded",
42428
+ "device-attention-required",
42429
+ "device-attention-resolved",
42406
42430
  "storage-location-low",
42407
42431
  "storage-location-critical",
42408
42432
  "storage-location-ok",
@@ -55734,6 +55758,16 @@ var DishwasherStatusSchema = object({
55734
55758
  powerState: string().nullable(),
55735
55759
  saltLevel: DishwasherConsumableLevelSchema.nullable(),
55736
55760
  rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
55761
+ /**
55762
+ * True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
55763
+ * combined care-and-filter reminder raised); false when every such reminder reads clear; null
55764
+ * when none is reported. A cleared reminder is not an unknown one.
55765
+ */
55766
+ filterCleaningDue: boolean().nullable(),
55767
+ /** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
55768
+ machineCareDue: boolean().nullable(),
55769
+ /** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
55770
+ machineCareRemainingRuns: number().int().nonnegative().nullable(),
55737
55771
  /** Option states: null when the appliance does not expose the option or has not said. */
55738
55772
  halfLoad: boolean().nullable(),
55739
55773
  hygienePlus: boolean().nullable(),
@@ -64384,16 +64418,6 @@ var UpdateUserInputSchema = object({
64384
64418
  allowedDevices: record(string(), union([array(string()), literal("*")])).optional(),
64385
64419
  scopes: array(TokenScopeSchema).optional()
64386
64420
  });
64387
- var ApiKeySummarySchema = object({
64388
- id: string(),
64389
- label: string(),
64390
- isAdmin: boolean().default(false),
64391
- allowedProviders: union([array(string()), literal("*")]).optional(),
64392
- allowedDevices: record(string(), union([array(string()), literal("*")])).optional(),
64393
- tokenPrefix: string(),
64394
- createdAt: number(),
64395
- lastUsedAt: number().optional()
64396
- });
64397
64421
  var OauthSessionSummarySchema = object({
64398
64422
  id: string(),
64399
64423
  userId: string(),
@@ -64415,8 +64439,7 @@ var TotpStatusSchema = object({
64415
64439
  confirmedAt: number().nullable()
64416
64440
  });
64417
64441
  /**
64418
- * user-management — singleton capability for user accounts and the
64419
- * legacy API-key rows.
64442
+ * user-management — singleton capability for user accounts.
64420
64443
  *
64421
64444
  * v2 model: every method gated by `auth: 'admin'`. Admin-only delegation
64422
64445
  * — the subset check on `setUserScopes` is moot
@@ -64472,10 +64495,6 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
64472
64495
  }), UserSummarySchema.extend({ passwordHash: string() }).nullable(), {
64473
64496
  kind: "mutation",
64474
64497
  access: "view"
64475
- }), method(_void(), array(ApiKeySummarySchema), { auth: "admin" }), method(object({ id: string() }), object({ success: literal(true) }), {
64476
- kind: "mutation",
64477
- auth: "admin",
64478
- access: "delete"
64479
64498
  }), method(object({ userId: string() }), TotpSetupResultSchema, {
64480
64499
  kind: "mutation",
64481
64500
  auth: "admin",
@@ -73931,6 +73950,12 @@ Object.freeze({
73931
73950
  addonId: null,
73932
73951
  access: "view"
73933
73952
  },
73953
+ "records.transact": {
73954
+ capName: "records",
73955
+ capScope: "system",
73956
+ addonId: null,
73957
+ access: "create"
73958
+ },
73934
73959
  "sceneMonitor.captureReference": {
73935
73960
  capName: "scene-monitor",
73936
73961
  capScope: "device",
@@ -75263,12 +75288,6 @@ Object.freeze({
75263
75288
  addonId: null,
75264
75289
  access: "view"
75265
75290
  },
75266
- "userManagement.listApiKeys": {
75267
- capName: "user-management",
75268
- capScope: "system",
75269
- addonId: null,
75270
- access: "view"
75271
- },
75272
75291
  "userManagement.listExternalIdentities": {
75273
75292
  capName: "user-management",
75274
75293
  capScope: "system",
@@ -75323,12 +75342,6 @@ Object.freeze({
75323
75342
  addonId: null,
75324
75343
  access: "create"
75325
75344
  },
75326
- "userManagement.revokeApiKey": {
75327
- capName: "user-management",
75328
- capScope: "system",
75329
- addonId: null,
75330
- access: "delete"
75331
- },
75332
75345
  "userManagement.revokeOauthSession": {
75333
75346
  capName: "user-management",
75334
75347
  capScope: "system",
@@ -78693,9 +78706,13 @@ new Map(Object.entries({
78693
78706
  "stream-online": "device-events",
78694
78707
  "stream-offline": "device-events",
78695
78708
  "detection-blind": "device-events",
78709
+ "motion-noisy": "device-events",
78710
+ "motion-calm": "device-events",
78696
78711
  "recording-stalled": "device-events",
78697
78712
  "recording-healthy": "device-events",
78698
78713
  "recording-degraded": "device-events",
78714
+ "device-attention-required": "device-events",
78715
+ "device-attention-resolved": "device-events",
78699
78716
  "node-online": "system",
78700
78717
  "node-offline": "system",
78701
78718
  "node-restarting": "system",
@@ -78778,6 +78795,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
78778
78795
  label: "Detecting nothing",
78779
78796
  kinds: ["detection-blind"]
78780
78797
  },
78798
+ {
78799
+ id: "motion-noise",
78800
+ family: "device-events",
78801
+ label: "Motion without a subject",
78802
+ kinds: ["motion-noisy", "motion-calm"]
78803
+ },
78781
78804
  {
78782
78805
  id: "recording",
78783
78806
  family: "device-events",
@@ -78788,6 +78811,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
78788
78811
  "recording-degraded"
78789
78812
  ]
78790
78813
  },
78814
+ {
78815
+ id: "device-attention",
78816
+ family: "device-events",
78817
+ label: "Needs attention",
78818
+ kinds: ["device-attention-required", "device-attention-resolved"]
78819
+ },
78791
78820
  {
78792
78821
  id: "nodes",
78793
78822
  family: "system",
@@ -78927,6 +78956,7 @@ var ALERT_EPISODE = [
78927
78956
  "alert-error",
78928
78957
  "alert-critical-resolved"
78929
78958
  ];
78959
+ var DEVICE_ATTENTION = ["device-attention-required", "device-attention-resolved"];
78930
78960
  var UPDATES = [
78931
78961
  "addon-update-available",
78932
78962
  "server-update-available",
@@ -78956,9 +78986,12 @@ var DEVICE_EVENTS = [
78956
78986
  "stream-online",
78957
78987
  "stream-offline",
78958
78988
  "detection-blind",
78989
+ "motion-noisy",
78990
+ "motion-calm",
78959
78991
  "recording-stalled",
78960
78992
  "recording-healthy",
78961
78993
  "recording-degraded",
78994
+ ...DEVICE_ATTENTION,
78962
78995
  ...ALARM
78963
78996
  ];
78964
78997
  /** Every kind a summary may speak about — the two summarisable families. */
@@ -79126,7 +79159,9 @@ var STATE_SUMMARY_VARS = [
79126
79159
  [...RULE_TEXT],
79127
79160
  [...RULE_TEXT],
79128
79161
  [...RULE_TEXT],
79129
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79162
+ [...RULE_TEXT],
79163
+ [...RULE_TEXT],
79164
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79130
79165
  [...RULE_TEXT],
79131
79166
  [...RULE_TEXT],
79132
79167
  [...RULE_TEXT],
@@ -79148,11 +79183,11 @@ var STATE_SUMMARY_VARS = [
79148
79183
  [...RULE_TEXT],
79149
79184
  [...RULE_TEXT],
79150
79185
  [...RULE_TEXT],
79186
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79151
79187
  ([...RULE_TEXT], [...ALERT_EPISODE]),
79188
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79152
79189
  ([...RULE_TEXT], [...ALERT_EPISODE]),
79153
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79154
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79155
- ([...RULE_TEXT], [...ALERT_EPISODE]),
79190
+ ([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
79156
79191
  [...RULE_TEXT],
79157
79192
  [...RULE_TEXT],
79158
79193
  [...RULE_TEXT],
@@ -79228,6 +79263,15 @@ new Map([
79228
79263
  snapshotLabel: "Tanks low or full now",
79229
79264
  snapshotSection: "tanks"
79230
79265
  },
79266
+ {
79267
+ id: "motion-noise",
79268
+ family: "device-events",
79269
+ label: "Motion without a subject (constant / calm again)",
79270
+ bad: ["motion-noisy"],
79271
+ recovery: ["motion-calm"],
79272
+ snapshotLabel: "Cameras with constant motion now",
79273
+ snapshotSection: null
79274
+ },
79231
79275
  {
79232
79276
  id: "recording-health",
79233
79277
  family: "device-events",
@@ -79237,6 +79281,15 @@ new Map([
79237
79281
  snapshotLabel: "Recordings stalled now",
79238
79282
  snapshotSection: null
79239
79283
  },
79284
+ {
79285
+ id: "device-attention",
79286
+ family: "device-events",
79287
+ label: "Device needs attention (raised / resolved)",
79288
+ bad: ["device-attention-required"],
79289
+ recovery: ["device-attention-resolved"],
79290
+ snapshotLabel: "Devices needing attention now",
79291
+ snapshotSection: null
79292
+ },
79240
79293
  {
79241
79294
  id: "node-connectivity",
79242
79295
  family: "system",
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-ChJRdNGo.js");
3
- const require_account_integration_offline = require("../account-integration-offline-Bf6PYmtk.js");
2
+ const require_dist = require("../dist-BUFPeAeI.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-BTvqsjjH.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_tls = require("node:tls");
6
6
  let node_zlib = require("node:zlib");
@@ -1400,7 +1400,7 @@ function buildHomeConnectFormSchema() {
1400
1400
  id: "gateway",
1401
1401
  title: "Home Connect",
1402
1402
  titleKey: "provider-bosch:home-connect.s_gateway.title",
1403
- description: "Create the login link and open it in a browser, then sign in. The browser cannot open the app and stops on an address starting with hcauth://auth/prod?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. The appliances are then downloaded and spoken to on the local network.",
1403
+ description: "Open the login link, sign in, then paste the address the browser stops on (hcauth://auth/prod?code=…). Chrome: DevTools > Network > last redirect > Location.",
1404
1404
  descriptionKey: "provider-bosch:home-connect.s_gateway.description",
1405
1405
  columns: 1,
1406
1406
  fields: [
@@ -3785,6 +3785,16 @@ function consumableFromEvents(view, nearlyEmpty, empty) {
3785
3785
  if (gone.includes(false) || nearly.includes(false)) return "ok";
3786
3786
  return null;
3787
3787
  }
3788
+ /** Any listed reminder raised → `true`; else any reading clear → `false`; none reported → `null`. */
3789
+ function reminderDue(view, shortNames) {
3790
+ const states = eventStates(view, shortNames);
3791
+ if (states.includes(true)) return true;
3792
+ return states.includes(false) ? false : null;
3793
+ }
3794
+ /** A non-negative whole count, or `null`. */
3795
+ function countOf(raw) {
3796
+ return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : null;
3797
+ }
3788
3798
  function programKey(raw) {
3789
3799
  return stringOf(raw);
3790
3800
  }
@@ -3818,6 +3828,9 @@ var COLD_DISHWASHER_STATUS = {
3818
3828
  powerState: null,
3819
3829
  saltLevel: null,
3820
3830
  rinseAidLevel: null,
3831
+ filterCleaningDue: null,
3832
+ machineCareDue: null,
3833
+ machineCareRemainingRuns: null,
3821
3834
  halfLoad: null,
3822
3835
  hygienePlus: null,
3823
3836
  extraDry: null,
@@ -3874,6 +3887,13 @@ function dishwasherStatusFromFeatures(input) {
3874
3887
  powerState: powerRaw,
3875
3888
  saltLevel: consumableFromEvents(input, ["SaltNearlyEmpty"], ["SaltEmpty", "SaltLack"]),
3876
3889
  rinseAidLevel: consumableFromEvents(input, ["RinseAidNearlyEmpty"], ["RinseAidEmpty", "RinseAidLack"]),
3890
+ filterCleaningDue: reminderDue(input, [
3891
+ "SmartFilterCleaningReminder",
3892
+ "CheckFilterSystem",
3893
+ "MachineCareAndFilterCleaningReminder"
3894
+ ]),
3895
+ machineCareDue: reminderDue(input, ["MachineCareReminder", "MachineCareAndFilterCleaningReminder"]),
3896
+ machineCareRemainingRuns: countOf(valueOf(input, findEntity(description, ["status"], ["RemainingProgramRuns"]))),
3877
3897
  halfLoad: optionBool(input, ["HalfLoad"]),
3878
3898
  hygienePlus: optionBool(input, ["HygienePlus"]),
3879
3899
  extraDry: optionBool(input, ["ExtraDry"]),
@@ -4219,7 +4239,7 @@ var LEGACY_CHILD_KEYS = {
4219
4239
  role: require_dist.DeviceRole.NumericSensor
4220
4240
  },
4221
4241
  "remote-control-level": {
4222
- key: "BSH.Common.Status.RemoteControlLevel",
4242
+ key: "BSH.Common.Setting.RemoteControlLevel",
4223
4243
  cap: "enum-sensor",
4224
4244
  role: require_dist.DeviceRole.EnumSensor
4225
4245
  },
@@ -4245,6 +4265,28 @@ var LEGACY_CHILD_KEYS = {
4245
4265
  }
4246
4266
  };
4247
4267
  /**
4268
+ * Keys the old fixed catalog guessed WRONG and persisted, mapped to the key the appliance really
4269
+ * lists. The remote-control level is a SETTING; the catalog filed it as a status, so a container
4270
+ * saved then carries `remote-control-level` on a key no description has, next to the derived
4271
+ * child the real key produced — one label, two devices.
4272
+ */
4273
+ var SUPERSEDED_LEGACY_KEYS = { "BSH.Common.Status.RemoteControlLevel": "BSH.Common.Setting.RemoteControlLevel" };
4274
+ /**
4275
+ * A persisted binding with a superseded legacy key re-pointed at the real one (same suffix, so
4276
+ * the same device); every other binding unchanged.
4277
+ */
4278
+ function withCurrentLegacyKey(binding) {
4279
+ const current = SUPERSEDED_LEGACY_KEYS[binding.key];
4280
+ return current === void 0 ? binding : {
4281
+ ...binding,
4282
+ key: current
4283
+ };
4284
+ }
4285
+ /** Whether a suffix is the one a key would derive — i.e. not an identity inherited from the old catalog. */
4286
+ function isDerivedSuffix(binding) {
4287
+ return binding.stableIdSuffix === slugFeatureKey(binding.key);
4288
+ }
4289
+ /**
4248
4290
  * The bindings that keep a container's EXISTING children alive until its description has been
4249
4291
  * read once: a container saved with the old fixed `children` list has no `entities` yet, and a
4250
4292
  * spec without those children would make the kernel delete them (removal by absence) before any
@@ -4288,6 +4330,20 @@ function keysMissingFromDescription(persisted, description) {
4288
4330
  return new Set(persisted.filter((b) => !isSyntheticKey(b.key) && description.entityByName(b.key) === void 0).map((b) => b.key));
4289
4331
  }
4290
4332
  /**
4333
+ * One row per Home Connect key. Two rows on one key are one entity filed twice (an identity from
4334
+ * the old catalog and the one derivation gave it): the older identity — the suffix that is NOT
4335
+ * the key's own slug — is the device the operator already has, so it stays and the twin leaves
4336
+ * (the kernel removes a child its spec no longer lists).
4337
+ */
4338
+ function oneRowPerKey(rows) {
4339
+ const byKey = /* @__PURE__ */ new Map();
4340
+ for (const row of rows) {
4341
+ const held = byKey.get(row.key);
4342
+ if (held === void 0 || isDerivedSuffix(held) && !isDerivedSuffix(row)) byKey.set(row.key, row);
4343
+ }
4344
+ return [...byKey.values()];
4345
+ }
4346
+ /**
4291
4347
  * The bindings a container should carry: what the description derives now, plus what it
4292
4348
  * already had. A child leaves only when its entity is missing from TWO agreeing reads (D49):
4293
4349
  * `missingBefore` is what the previous read lacked — one description that omits an entity is
@@ -4296,10 +4352,11 @@ function keysMissingFromDescription(persisted, description) {
4296
4352
  * derived model (legacy children) keeps its device ids instead of being rebuilt.
4297
4353
  */
4298
4354
  function mergeChildBindings(persisted, derived, description, missingBefore = /* @__PURE__ */ new Set()) {
4299
- const missingNow = keysMissingFromDescription(persisted, description);
4355
+ const rows = oneRowPerKey(persisted.map(withCurrentLegacyKey));
4356
+ const missingNow = keysMissingFromDescription(rows, description);
4300
4357
  const out = /* @__PURE__ */ new Map();
4301
4358
  const suffixByKey = /* @__PURE__ */ new Map();
4302
- for (const kept of persisted) {
4359
+ for (const kept of rows) {
4303
4360
  if (missingNow.has(kept.key) && missingBefore.has(kept.key)) continue;
4304
4361
  out.set(kept.stableIdSuffix, kept);
4305
4362
  suffixByKey.set(kept.key, kept);
@@ -1,5 +1,5 @@
1
- import { A as object, C as defineCustomActions, D as array, E as _enum, F as EventCategory, M as string, N as union, O as literal, P as unknown, S as customAction, T as isSecretMarkerLike, a as binaryCapability, b as errMsg, c as deviceAdoptionCapability, d as eventEmitterCapability, j as record, l as dishwasherCapability, m as powerMeterCapability, n as BaseDeviceProvider, p as numericSensorCapability, r as DishwasherOperationStateSchema, s as connectionTestCapability, t as BaseDevice, u as enumSensorCapability, v as DeviceRole, w as isSecretMarker, x as createEvent, y as DeviceType } from "../dist-hm2fhp2t.mjs";
2
- import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-jlQzb2JO.mjs";
1
+ import { A as object, C as defineCustomActions, D as array, E as _enum, F as EventCategory, M as string, N as union, O as literal, P as unknown, S as customAction, T as isSecretMarkerLike, a as binaryCapability, b as errMsg, c as deviceAdoptionCapability, d as eventEmitterCapability, j as record, l as dishwasherCapability, m as powerMeterCapability, n as BaseDeviceProvider, p as numericSensorCapability, r as DishwasherOperationStateSchema, s as connectionTestCapability, t as BaseDevice, u as enumSensorCapability, v as DeviceRole, w as isSecretMarker, x as createEvent, y as DeviceType } from "../dist-PdvgOyAy.mjs";
2
+ import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-ASUhiSjp.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { connect } from "node:tls";
5
5
  import { inflateRawSync } from "node:zlib";
@@ -1399,7 +1399,7 @@ function buildHomeConnectFormSchema() {
1399
1399
  id: "gateway",
1400
1400
  title: "Home Connect",
1401
1401
  titleKey: "provider-bosch:home-connect.s_gateway.title",
1402
- description: "Create the login link and open it in a browser, then sign in. The browser cannot open the app and stops on an address starting with hcauth://auth/prod?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. The appliances are then downloaded and spoken to on the local network.",
1402
+ description: "Open the login link, sign in, then paste the address the browser stops on (hcauth://auth/prod?code=…). Chrome: DevTools > Network > last redirect > Location.",
1403
1403
  descriptionKey: "provider-bosch:home-connect.s_gateway.description",
1404
1404
  columns: 1,
1405
1405
  fields: [
@@ -3784,6 +3784,16 @@ function consumableFromEvents(view, nearlyEmpty, empty) {
3784
3784
  if (gone.includes(false) || nearly.includes(false)) return "ok";
3785
3785
  return null;
3786
3786
  }
3787
+ /** Any listed reminder raised → `true`; else any reading clear → `false`; none reported → `null`. */
3788
+ function reminderDue(view, shortNames) {
3789
+ const states = eventStates(view, shortNames);
3790
+ if (states.includes(true)) return true;
3791
+ return states.includes(false) ? false : null;
3792
+ }
3793
+ /** A non-negative whole count, or `null`. */
3794
+ function countOf(raw) {
3795
+ return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? raw : null;
3796
+ }
3787
3797
  function programKey(raw) {
3788
3798
  return stringOf(raw);
3789
3799
  }
@@ -3817,6 +3827,9 @@ var COLD_DISHWASHER_STATUS = {
3817
3827
  powerState: null,
3818
3828
  saltLevel: null,
3819
3829
  rinseAidLevel: null,
3830
+ filterCleaningDue: null,
3831
+ machineCareDue: null,
3832
+ machineCareRemainingRuns: null,
3820
3833
  halfLoad: null,
3821
3834
  hygienePlus: null,
3822
3835
  extraDry: null,
@@ -3873,6 +3886,13 @@ function dishwasherStatusFromFeatures(input) {
3873
3886
  powerState: powerRaw,
3874
3887
  saltLevel: consumableFromEvents(input, ["SaltNearlyEmpty"], ["SaltEmpty", "SaltLack"]),
3875
3888
  rinseAidLevel: consumableFromEvents(input, ["RinseAidNearlyEmpty"], ["RinseAidEmpty", "RinseAidLack"]),
3889
+ filterCleaningDue: reminderDue(input, [
3890
+ "SmartFilterCleaningReminder",
3891
+ "CheckFilterSystem",
3892
+ "MachineCareAndFilterCleaningReminder"
3893
+ ]),
3894
+ machineCareDue: reminderDue(input, ["MachineCareReminder", "MachineCareAndFilterCleaningReminder"]),
3895
+ machineCareRemainingRuns: countOf(valueOf(input, findEntity(description, ["status"], ["RemainingProgramRuns"]))),
3876
3896
  halfLoad: optionBool(input, ["HalfLoad"]),
3877
3897
  hygienePlus: optionBool(input, ["HygienePlus"]),
3878
3898
  extraDry: optionBool(input, ["ExtraDry"]),
@@ -4218,7 +4238,7 @@ var LEGACY_CHILD_KEYS = {
4218
4238
  role: DeviceRole.NumericSensor
4219
4239
  },
4220
4240
  "remote-control-level": {
4221
- key: "BSH.Common.Status.RemoteControlLevel",
4241
+ key: "BSH.Common.Setting.RemoteControlLevel",
4222
4242
  cap: "enum-sensor",
4223
4243
  role: DeviceRole.EnumSensor
4224
4244
  },
@@ -4244,6 +4264,28 @@ var LEGACY_CHILD_KEYS = {
4244
4264
  }
4245
4265
  };
4246
4266
  /**
4267
+ * Keys the old fixed catalog guessed WRONG and persisted, mapped to the key the appliance really
4268
+ * lists. The remote-control level is a SETTING; the catalog filed it as a status, so a container
4269
+ * saved then carries `remote-control-level` on a key no description has, next to the derived
4270
+ * child the real key produced — one label, two devices.
4271
+ */
4272
+ var SUPERSEDED_LEGACY_KEYS = { "BSH.Common.Status.RemoteControlLevel": "BSH.Common.Setting.RemoteControlLevel" };
4273
+ /**
4274
+ * A persisted binding with a superseded legacy key re-pointed at the real one (same suffix, so
4275
+ * the same device); every other binding unchanged.
4276
+ */
4277
+ function withCurrentLegacyKey(binding) {
4278
+ const current = SUPERSEDED_LEGACY_KEYS[binding.key];
4279
+ return current === void 0 ? binding : {
4280
+ ...binding,
4281
+ key: current
4282
+ };
4283
+ }
4284
+ /** Whether a suffix is the one a key would derive — i.e. not an identity inherited from the old catalog. */
4285
+ function isDerivedSuffix(binding) {
4286
+ return binding.stableIdSuffix === slugFeatureKey(binding.key);
4287
+ }
4288
+ /**
4247
4289
  * The bindings that keep a container's EXISTING children alive until its description has been
4248
4290
  * read once: a container saved with the old fixed `children` list has no `entities` yet, and a
4249
4291
  * spec without those children would make the kernel delete them (removal by absence) before any
@@ -4287,6 +4329,20 @@ function keysMissingFromDescription(persisted, description) {
4287
4329
  return new Set(persisted.filter((b) => !isSyntheticKey(b.key) && description.entityByName(b.key) === void 0).map((b) => b.key));
4288
4330
  }
4289
4331
  /**
4332
+ * One row per Home Connect key. Two rows on one key are one entity filed twice (an identity from
4333
+ * the old catalog and the one derivation gave it): the older identity — the suffix that is NOT
4334
+ * the key's own slug — is the device the operator already has, so it stays and the twin leaves
4335
+ * (the kernel removes a child its spec no longer lists).
4336
+ */
4337
+ function oneRowPerKey(rows) {
4338
+ const byKey = /* @__PURE__ */ new Map();
4339
+ for (const row of rows) {
4340
+ const held = byKey.get(row.key);
4341
+ if (held === void 0 || isDerivedSuffix(held) && !isDerivedSuffix(row)) byKey.set(row.key, row);
4342
+ }
4343
+ return [...byKey.values()];
4344
+ }
4345
+ /**
4290
4346
  * The bindings a container should carry: what the description derives now, plus what it
4291
4347
  * already had. A child leaves only when its entity is missing from TWO agreeing reads (D49):
4292
4348
  * `missingBefore` is what the previous read lacked — one description that omits an entity is
@@ -4295,10 +4351,11 @@ function keysMissingFromDescription(persisted, description) {
4295
4351
  * derived model (legacy children) keeps its device ids instead of being rebuilt.
4296
4352
  */
4297
4353
  function mergeChildBindings(persisted, derived, description, missingBefore = /* @__PURE__ */ new Set()) {
4298
- const missingNow = keysMissingFromDescription(persisted, description);
4354
+ const rows = oneRowPerKey(persisted.map(withCurrentLegacyKey));
4355
+ const missingNow = keysMissingFromDescription(rows, description);
4299
4356
  const out = /* @__PURE__ */ new Map();
4300
4357
  const suffixByKey = /* @__PURE__ */ new Map();
4301
- for (const kept of persisted) {
4358
+ for (const kept of rows) {
4302
4359
  if (missingNow.has(kept.key) && missingBefore.has(kept.key)) continue;
4303
4360
  out.set(kept.stableIdSuffix, kept);
4304
4361
  suffixByKey.set(kept.key, kept);
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-ChJRdNGo.js");
3
- const require_account_integration_offline = require("../account-integration-offline-Bf6PYmtk.js");
2
+ const require_dist = require("../dist-BUFPeAeI.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-BTvqsjjH.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  //#region src/homecom/custom-actions.ts
6
6
  var homeComActions = require_dist.defineCustomActions({
@@ -187,7 +187,7 @@ function buildHomeComFormSchema() {
187
187
  id: "account",
188
188
  title: "HomeCom account",
189
189
  titleKey: "provider-bosch:homecom.s_account.title",
190
- description: "Create the login link and open it in a browser, then sign in with your SingleKey ID. The browser cannot open the app and stops on an address starting with com.bosch.tt.dashtt.pointt://app/login?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. Tokens can also be pasted by hand in the fields below.",
190
+ description: "Sign in with your SingleKey ID, then paste the address the browser stops on (com.bosch.tt.dashtt.pointt://app/login?code=…). Find it in DevTools > Network.",
191
191
  descriptionKey: "provider-bosch:homecom.s_account.description",
192
192
  columns: 1,
193
193
  fields: [
@@ -1,5 +1,5 @@
1
- import { A as object, C as defineCustomActions, E as _enum, F as EventCategory, M as string, O as literal, S as customAction, T as isSecretMarkerLike, _ as waterHeaterCapability, b as errMsg, c as deviceAdoptionCapability, n as BaseDeviceProvider, o as climateControlCapability, s as connectionTestCapability, t as BaseDevice, w as isSecretMarker, y as DeviceType } from "../dist-hm2fhp2t.mjs";
2
- import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-jlQzb2JO.mjs";
1
+ import { A as object, C as defineCustomActions, E as _enum, F as EventCategory, M as string, O as literal, S as customAction, T as isSecretMarkerLike, _ as waterHeaterCapability, b as errMsg, c as deviceAdoptionCapability, n as BaseDeviceProvider, o as climateControlCapability, s as connectionTestCapability, t as BaseDevice, w as isSecretMarker, y as DeviceType } from "../dist-PdvgOyAy.mjs";
2
+ import { n as cascadeRemoveDevicesForIntegration, r as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-ASUhiSjp.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  //#region src/homecom/custom-actions.ts
5
5
  var homeComActions = defineCustomActions({
@@ -186,7 +186,7 @@ function buildHomeComFormSchema() {
186
186
  id: "account",
187
187
  title: "HomeCom account",
188
188
  titleKey: "provider-bosch:homecom.s_account.title",
189
- description: "Create the login link and open it in a browser, then sign in with your SingleKey ID. The browser cannot open the app and stops on an address starting with com.bosch.tt.dashtt.pointt://app/login?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. Tokens can also be pasted by hand in the fields below.",
189
+ description: "Sign in with your SingleKey ID, then paste the address the browser stops on (com.bosch.tt.dashtt.pointt://app/login?code=…). Find it in DevTools > Network.",
190
190
  descriptionKey: "provider-bosch:homecom.s_account.description",
191
191
  columns: 1,
192
192
  fields: [
package/dist/shc/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
4
  //#endregion
5
- const require_dist = require("../dist-ChJRdNGo.js");
5
+ const require_dist = require("../dist-BUFPeAeI.js");
6
6
  let node_crypto = require("node:crypto");
7
7
  let node_https = require("node:https");
8
8
  let node_child_process = require("node:child_process");
@@ -1,4 +1,4 @@
1
- import { A as object, C as defineCustomActions, D as array, E as _enum, F as EventCategory, M as string, O as literal, S as customAction, b as errMsg, c as deviceAdoptionCapability, f as heatingValveCapability, g as temperatureSensorCapability, h as switchCapability, i as batteryCapability, k as number, n as BaseDeviceProvider, o as climateControlCapability, s as connectionTestCapability, t as BaseDevice, y as DeviceType } from "../dist-hm2fhp2t.mjs";
1
+ import { A as object, C as defineCustomActions, D as array, E as _enum, F as EventCategory, M as string, O as literal, S as customAction, b as errMsg, c as deviceAdoptionCapability, f as heatingValveCapability, g as temperatureSensorCapability, h as switchCapability, i as batteryCapability, k as number, n as BaseDeviceProvider, o as climateControlCapability, s as connectionTestCapability, t as BaseDevice, y as DeviceType } from "../dist-PdvgOyAy.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { request } from "node:https";
package/i18n/en.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "bosch-home-connect.name": "Bosch Home Connect",
4
4
  "bosch-homecom.name": "Bosch HomeCom",
5
5
  "homecom.s_account.title": "HomeCom account",
6
- "homecom.s_account.description": "Create the login link and open it in a browser, then sign in with your SingleKey ID. The browser cannot open the app and stops on an address starting with com.bosch.tt.dashtt.pointt://app/login?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. Tokens can also be pasted by hand in the fields below.",
6
+ "homecom.s_account.description": "Sign in with your SingleKey ID, then paste the address the browser stops on (com.bosch.tt.dashtt.pointt://app/login?code=…). Find it in DevTools > Network.",
7
7
  "homecom.s_account.__homecom-begin.label": "HomeCom",
8
8
  "homecom.s_account.authorizeUrl.label": "Login link",
9
9
  "homecom.s_account.callback.label": "Redirect address or code",
@@ -18,7 +18,7 @@
18
18
  "homecom.s_account.brand.label": "Brand",
19
19
  "homecom.s_account.region.label": "Region",
20
20
  "home-connect.s_gateway.title": "Home Connect",
21
- "home-connect.s_gateway.description": "Create the login link and open it in a browser, then sign in. The browser cannot open the app and stops on an address starting with hcauth://auth/prod?code=. Paste that whole address below (or only the code) and press Complete sign-in. The address is shown in Chrome and Edge under DevTools (F12) > Network, with Preserve log ticked before you sign in: select the last redirect and copy its Location header. In Firefox use Network > Headers > Location; in Safari use Develop > Show Web Inspector > Network. A code works once and expires within minutes. The appliances are then downloaded and spoken to on the local network.",
21
+ "home-connect.s_gateway.description": "Open the login link, sign in, then paste the address the browser stops on (hcauth://auth/prod?code=…). Chrome: DevTools > Network > last redirect > Location.",
22
22
  "home-connect.s_gateway.__home-connect-begin.label": "Home Connect",
23
23
  "home-connect.s_gateway.authorizeUrl.label": "Login link",
24
24
  "home-connect.s_gateway.callback.label": "Redirect address or code",
package/i18n/it.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "bosch-home-connect.name": "Bosch Home Connect",
4
4
  "bosch-homecom.name": "Bosch HomeCom",
5
5
  "homecom.s_account.title": "Account HomeCom",
6
- "homecom.s_account.description": "Crea il link di accesso, aprilo in un browser e accedi con il tuo SingleKey ID. Il browser non riesce ad aprire l'app e si ferma su un indirizzo che inizia con com.bosch.tt.dashtt.pointt://app/login?code=. Incolla qui sotto l'intero indirizzo (o solo il codice) e premi Completa accesso. L'indirizzo si vede in Chrome ed Edge in DevTools (F12) > Network, con Preserve log attivo prima di accedere: seleziona l'ultimo reindirizzamento e copia l'intestazione Location. In Firefox usa Network > Headers > Location; in Safari usa Sviluppo > Mostra Web Inspector > Network. Un codice vale una sola volta e scade in pochi minuti. I token si possono anche incollare a mano nei campi qui sotto.",
6
+ "homecom.s_account.description": "Accedi con il tuo SingleKey ID, poi incolla l'indirizzo su cui si ferma il browser (com.bosch.tt.dashtt.pointt://app/login?code=…). Lo trovi in DevTools > Network.",
7
7
  "homecom.s_account.__homecom-begin.label": "HomeCom",
8
8
  "homecom.s_account.authorizeUrl.label": "Link di accesso",
9
9
  "homecom.s_account.callback.label": "Indirizzo di reindirizzamento o codice",
@@ -18,7 +18,7 @@
18
18
  "homecom.s_account.brand.label": "Marchio",
19
19
  "homecom.s_account.region.label": "Regione",
20
20
  "home-connect.s_gateway.title": "Home Connect",
21
- "home-connect.s_gateway.description": "Crea il link di accesso, aprilo in un browser e accedi. Il browser non riesce ad aprire l'app e si ferma su un indirizzo che inizia con hcauth://auth/prod?code=. Incolla qui sotto l'intero indirizzo (o solo il codice) e premi Completa accesso. L'indirizzo si vede in Chrome ed Edge in DevTools (F12) > Network, con Preserve log attivo prima di accedere: seleziona l'ultimo reindirizzamento e copia l'intestazione Location. In Firefox usa Network > Headers > Location; in Safari usa Sviluppo > Mostra Web Inspector > Network. Un codice vale una sola volta e scade in pochi minuti. Gli elettrodomestici vengono poi scaricati e usati sulla rete locale.",
21
+ "home-connect.s_gateway.description": "Apri il link di accesso, accedi, poi incolla l'indirizzo su cui si ferma il browser (hcauth://auth/prod?code=…). Chrome: DevTools > Network > ultimo redirect > Location.",
22
22
  "home-connect.s_gateway.__home-connect-begin.label": "Home Connect",
23
23
  "home-connect.s_gateway.authorizeUrl.label": "Link di accesso",
24
24
  "home-connect.s_gateway.callback.label": "Indirizzo di reindirizzamento o codice",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-bosch",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Bosch smart-home device-provider addons for CamStack — SHC, Home Connect, and HomeCom cloud integrations (scaffold)",
5
5
  "keywords": [
6
6
  "camstack",