@camstack/addon-provider-bosch 0.1.34 → 0.1.36

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,32 +1,32 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-DOr0p9V1.js");
3
- const require_account_integration_offline = require("../account-integration-offline-B7f80oHo.js");
2
+ const require_bosch_instances = require("../bosch-instances-CXmuRkef.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-Bnm17sAE.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");
7
7
  let node_dns_promises = require("node:dns/promises");
8
8
  //#region src/home-connect/custom-actions.ts
9
- var homeConnectActions = require_dist.defineCustomActions({
10
- beginSignIn: require_dist.customAction(require_dist.object({}), require_dist.object({
11
- attemptId: require_dist.string().min(1),
12
- authorizeUrl: require_dist.string().min(1),
13
- summary: require_dist.string()
9
+ var homeConnectActions = require_bosch_instances.defineCustomActions({
10
+ beginSignIn: require_bosch_instances.customAction(require_bosch_instances.object({}), require_bosch_instances.object({
11
+ attemptId: require_bosch_instances.string().min(1),
12
+ authorizeUrl: require_bosch_instances.string().min(1),
13
+ summary: require_bosch_instances.string()
14
14
  }), {
15
15
  kind: "mutation",
16
16
  auth: "admin"
17
17
  }),
18
- finishSignIn: require_dist.customAction(require_dist.object({
19
- attemptId: require_dist.string().min(1),
20
- callback: require_dist.string().min(1)
21
- }), require_dist.object({
22
- token: require_dist.string().min(1).meta({ secret: true }),
23
- refresh: require_dist.string().optional().meta({ secret: true }),
24
- accountLabel: require_dist.string(),
18
+ finishSignIn: require_bosch_instances.customAction(require_bosch_instances.object({
19
+ attemptId: require_bosch_instances.string().min(1),
20
+ callback: require_bosch_instances.string().min(1)
21
+ }), require_bosch_instances.object({
22
+ token: require_bosch_instances.string().min(1).meta({ secret: true }),
23
+ refresh: require_bosch_instances.string().optional().meta({ secret: true }),
24
+ accountLabel: require_bosch_instances.string(),
25
25
  /** JSON of the paired appliances — no credential on it. */
26
- appliances: require_dist.string().min(1),
26
+ appliances: require_bosch_instances.string().min(1),
27
27
  /** JSON of `haId -> { psk, iv64? }`; stored in the keychain, never in `appliances`. */
28
- applianceSecrets: require_dist.string().min(1).meta({ secret: true }),
29
- summary: require_dist.string()
28
+ applianceSecrets: require_bosch_instances.string().min(1).meta({ secret: true }),
29
+ summary: require_bosch_instances.string()
30
30
  }), {
31
31
  kind: "mutation",
32
32
  auth: "admin"
@@ -36,21 +36,21 @@ var homeConnectActions = require_dist.defineCustomActions({
36
36
  * app-scheme redirect and finished the exchange, then the same fields `finishSignIn` returns.
37
37
  * Claimed once. A failed exchange answers with its operator-facing message as an error.
38
38
  */
39
- claimSignIn: require_dist.customAction(require_dist.object({ attemptId: require_dist.string().min(1) }), require_dist.object({
40
- pending: require_dist.boolean(),
41
- token: require_dist.string().optional().meta({ secret: true }),
42
- refresh: require_dist.string().optional().meta({ secret: true }),
43
- accountLabel: require_dist.string().optional(),
44
- appliances: require_dist.string().optional(),
45
- applianceSecrets: require_dist.string().optional().meta({ secret: true }),
46
- summary: require_dist.string().optional()
39
+ claimSignIn: require_bosch_instances.customAction(require_bosch_instances.object({ attemptId: require_bosch_instances.string().min(1) }), require_bosch_instances.object({
40
+ pending: require_bosch_instances.boolean(),
41
+ token: require_bosch_instances.string().optional().meta({ secret: true }),
42
+ refresh: require_bosch_instances.string().optional().meta({ secret: true }),
43
+ accountLabel: require_bosch_instances.string().optional(),
44
+ appliances: require_bosch_instances.string().optional(),
45
+ applianceSecrets: require_bosch_instances.string().optional().meta({ secret: true }),
46
+ summary: require_bosch_instances.string().optional()
47
47
  }), {
48
48
  kind: "mutation",
49
49
  auth: "admin"
50
50
  }),
51
- signOut: require_dist.customAction(require_dist.object({}), require_dist.object({
52
- signedOut: require_dist.literal(true),
53
- summary: require_dist.string()
51
+ signOut: require_bosch_instances.customAction(require_bosch_instances.object({}), require_bosch_instances.object({
52
+ signedOut: require_bosch_instances.literal(true),
53
+ summary: require_bosch_instances.string()
54
54
  }), {
55
55
  kind: "mutation",
56
56
  auth: "admin"
@@ -73,12 +73,12 @@ async function trackHomeConnectContainers(deps, trigger) {
73
73
  } catch (err) {
74
74
  deps.logger.warn("Home Connect could not list its devices to watch their children", { meta: {
75
75
  trigger,
76
- error: require_dist.errMsg(err)
76
+ error: require_bosch_instances.errMsg(err)
77
77
  } });
78
78
  return 0;
79
79
  }
80
80
  for (const d of devices) {
81
- if (d.type !== require_dist.DeviceType.Container || deps.reconciler.tracks(d.id)) continue;
81
+ if (d.type !== require_bosch_instances.DeviceType.Container || deps.reconciler.tracks(d.id)) continue;
82
82
  const cfg = await deps.loadConfig(d.id).catch(() => ({}));
83
83
  const brokerId = cfg["brokerId"];
84
84
  const haId = cfg["haId"];
@@ -1004,35 +1004,26 @@ async function finishHomeConnectSignIn(input, store, fetchImpl = homeConnectLogi
1004
1004
  }, fetchImpl);
1005
1005
  }
1006
1006
  var homeConnectSignInAttempts = require_account_integration_offline.createSignInAttemptStore();
1007
- var HomeConnectModeSchema = require_dist._enum(["AES", "TLS"]);
1007
+ var HomeConnectModeSchema = require_bosch_instances._enum(["AES", "TLS"]);
1008
1008
  function isPlainObject$1(value) {
1009
1009
  return value !== null && typeof value === "object" && !Array.isArray(value);
1010
1010
  }
1011
- var homeConnectDeviceDescriptionSchema = require_dist.union([require_dist.string(), require_dist.record(require_dist.string(), require_dist.unknown())]).optional();
1012
- require_dist.object({
1013
- host: require_dist.string().min(1),
1014
- psk: require_dist.string().min(1).meta({ secret: true }),
1011
+ var homeConnectDeviceDescriptionSchema = require_bosch_instances.union([require_bosch_instances.string(), require_bosch_instances.record(require_bosch_instances.string(), require_bosch_instances.unknown())]).optional();
1012
+ require_bosch_instances.object({
1013
+ host: require_bosch_instances.string().min(1),
1014
+ psk: require_bosch_instances.string().min(1).meta({ secret: true }),
1015
1015
  mode: HomeConnectModeSchema.default("AES"),
1016
- iv64: require_dist.string().optional(),
1016
+ iv64: require_bosch_instances.string().optional(),
1017
1017
  deviceDescription: homeConnectDeviceDescriptionSchema
1018
1018
  });
1019
1019
  /** Setting key of the keychain-stored credentials of every paired appliance. */
1020
1020
  var APPLIANCE_SECRETS_KEY = "applianceSecrets";
1021
- /**
1022
- * The integration-settings keys that hold a credential — what a write from this addon names
1023
- * as `secretKeys` so the hub moves them into the keychain.
1024
- */
1025
- var HOME_CONNECT_SECRET_KEYS = [
1026
- "token",
1027
- "refresh",
1028
- APPLIANCE_SECRETS_KEY
1029
- ];
1030
1021
  /** One appliance as persisted in the integration's `appliances` setting: no credential on it. */
1031
- var homeConnectApplianceRowSchema = require_dist.object({
1032
- haId: require_dist.string().min(1),
1033
- name: require_dist.string(),
1034
- type: require_dist.string(),
1035
- host: require_dist.string().min(1),
1022
+ var homeConnectApplianceRowSchema = require_bosch_instances.object({
1023
+ haId: require_bosch_instances.string().min(1),
1024
+ name: require_bosch_instances.string(),
1025
+ type: require_bosch_instances.string(),
1026
+ host: require_bosch_instances.string().min(1),
1036
1027
  mode: HomeConnectModeSchema,
1037
1028
  deviceDescription: homeConnectDeviceDescriptionSchema
1038
1029
  });
@@ -1042,28 +1033,28 @@ var homeConnectApplianceRowSchema = require_dist.object({
1042
1033
  * Read once, adopted into the keychain, then never written again.
1043
1034
  */
1044
1035
  var legacyApplianceRowSchema = homeConnectApplianceRowSchema.extend({
1045
- psk: require_dist.string().optional(),
1046
- iv64: require_dist.string().optional()
1036
+ psk: require_bosch_instances.string().optional(),
1037
+ iv64: require_bosch_instances.string().optional()
1047
1038
  });
1048
1039
  /** What the keychain holds per appliance. */
1049
- var homeConnectApplianceSecretSchema = require_dist.object({
1050
- psk: require_dist.string().min(1),
1051
- iv64: require_dist.string().optional()
1040
+ var homeConnectApplianceSecretSchema = require_bosch_instances.object({
1041
+ psk: require_bosch_instances.string().min(1),
1042
+ iv64: require_bosch_instances.string().optional()
1052
1043
  });
1053
1044
  /** `applianceSecrets`: one string in the keychain, JSON of `haId -> { psk, iv64? }`. */
1054
- var homeConnectApplianceSecretsSchema = require_dist.record(require_dist.string(), homeConnectApplianceSecretSchema);
1045
+ var homeConnectApplianceSecretsSchema = require_bosch_instances.record(require_bosch_instances.string(), homeConnectApplianceSecretSchema);
1055
1046
  /** One appliance in memory: its row and its credential together. */
1056
1047
  var homeConnectStoredApplianceSchema = homeConnectApplianceRowSchema.extend({
1057
- psk: require_dist.string().min(1),
1058
- iv64: require_dist.string().optional()
1048
+ psk: require_bosch_instances.string().min(1),
1049
+ iv64: require_bosch_instances.string().optional()
1059
1050
  });
1060
1051
  /** The integration is the Home Connect account. Profiles are downloaded once at sign-in. */
1061
- var homeConnectConfigSchema = require_dist.object({
1062
- token: require_dist.string().min(1).describe("Home Connect access token").meta({ secret: true }),
1063
- refresh: require_dist.string().optional().describe("Home Connect refresh token").meta({ secret: true }),
1064
- appliances: require_dist.array(homeConnectStoredApplianceSchema).optional(),
1052
+ var homeConnectConfigSchema = require_bosch_instances.object({
1053
+ token: require_bosch_instances.string().min(1).describe("Home Connect access token").meta({ secret: true }),
1054
+ refresh: require_bosch_instances.string().optional().describe("Home Connect refresh token").meta({ secret: true }),
1055
+ appliances: require_bosch_instances.array(homeConnectStoredApplianceSchema).optional(),
1065
1056
  /** Shown on the sign-in field. The JWT subject, not a credential. */
1066
- accountLabel: require_dist.string().optional()
1057
+ accountLabel: require_bosch_instances.string().optional()
1067
1058
  });
1068
1059
  function parseJsonValue(raw) {
1069
1060
  if (typeof raw !== "string") return raw;
@@ -1086,7 +1077,7 @@ function legacyRowsOf(raw) {
1086
1077
  return rows;
1087
1078
  }
1088
1079
  function readApplianceSecrets(raw) {
1089
- if (require_dist.isSecretMarker(raw) || require_dist.isSecretMarkerLike(raw)) return { kind: "unresolved" };
1080
+ if (require_bosch_instances.isSecretMarker(raw) || require_bosch_instances.isSecretMarkerLike(raw)) return { kind: "unresolved" };
1090
1081
  const value = parseJsonValue(raw);
1091
1082
  if (value === void 0 || value === null) return { kind: "none" };
1092
1083
  const parsed = homeConnectApplianceSecretsSchema.safeParse(value);
@@ -1128,7 +1119,7 @@ function splitApplianceSecrets(appliances) {
1128
1119
  };
1129
1120
  }
1130
1121
  /**
1131
- * Before `integrations.setSettings`: keep objects as-is (serializes as `json`), parse
1122
+ * Before the record write: keep objects as-is (serializes as `json`), parse
1132
1123
  * textarea JSON strings into objects so they are not re-serialized as `string` and
1133
1124
  * corrupted on read by `deserializeSetting(String(object))` — and move any credential
1134
1125
  * still sitting on an appliance row into `applianceSecrets`, so a row is never written
@@ -1185,29 +1176,6 @@ function moveInlineSecrets(settings) {
1185
1176
  ...Object.keys(merged).length > 0 ? { [APPLIANCE_SECRETS_KEY]: JSON.stringify(merged) } : {}
1186
1177
  };
1187
1178
  }
1188
- /**
1189
- * One-time adopt: the settings that must be written so a pairing key found on an appliance
1190
- * row moves into the keychain. `null` when nothing needs moving. The caller writes it with
1191
- * {@link HOME_CONNECT_SECRET_KEYS} as `secretKeys`.
1192
- */
1193
- function legacyApplianceSecretPatch(settings) {
1194
- const moved = moveInlineSecrets({
1195
- ...settings,
1196
- appliances: parseJsonValue(settings["appliances"])
1197
- });
1198
- const rows = moved["appliances"];
1199
- const secrets = moved[APPLIANCE_SECRETS_KEY];
1200
- if (!Array.isArray(rows) || typeof secrets !== "string") return null;
1201
- const parsedRows = [];
1202
- for (const row of rows) {
1203
- const parsed = homeConnectApplianceRowSchema.safeParse(row);
1204
- if (parsed.success) parsedRows.push(parsed.data);
1205
- }
1206
- return {
1207
- appliances: parsedRows,
1208
- applianceSecrets: secrets
1209
- };
1210
- }
1211
1179
  function connectionFromSettings(settings) {
1212
1180
  const normalized = homeConnectSettingsForPersist(settings);
1213
1181
  const rows = legacyRowsOf(normalized["appliances"]);
@@ -1238,7 +1206,7 @@ function hasNonEmptyString(settings, key) {
1238
1206
  function homeConnectSettingsGap(settings) {
1239
1207
  if (connectionFromSettings(settings) !== null) return null;
1240
1208
  const token = settings["token"];
1241
- if (require_dist.isSecretMarker(token) || require_dist.isSecretMarkerLike(token)) return "token-unresolved-marker";
1209
+ if (require_bosch_instances.isSecretMarker(token) || require_bosch_instances.isSecretMarkerLike(token)) return "token-unresolved-marker";
1242
1210
  if (!hasNonEmptyString(settings, "token")) return "token-missing";
1243
1211
  return "schema-invalid";
1244
1212
  }
@@ -1250,7 +1218,7 @@ function logHomeConnectSettingsGap(logger, integrationId, settings) {
1250
1218
  logger.warn("Home Connect integration has incomplete account settings — skipping", { meta: {
1251
1219
  integrationId,
1252
1220
  gap,
1253
- tokenIsSecretMarker: require_dist.isSecretMarker(token),
1221
+ tokenIsSecretMarker: require_bosch_instances.isSecretMarker(token),
1254
1222
  tokenType: typeof token,
1255
1223
  hasToken: hasNonEmptyString(settings, "token"),
1256
1224
  hasRefresh: hasNonEmptyString(settings, "refresh")
@@ -1478,7 +1446,7 @@ function homeConnectDishwasherEntityName(containerName) {
1478
1446
  return base.length > 0 ? `Dishwasher ${base}` : "Dishwasher";
1479
1447
  }
1480
1448
  function deviceTypeForApplianceType(type) {
1481
- if (type.toLowerCase().includes("dishwasher")) return require_dist.DeviceType.Container;
1449
+ if (type.toLowerCase().includes("dishwasher")) return require_bosch_instances.DeviceType.Container;
1482
1450
  return null;
1483
1451
  }
1484
1452
  /**
@@ -1491,7 +1459,7 @@ function dishwasherContainerCandidate(app, adoptedId) {
1491
1459
  const children = [{
1492
1460
  childNativeId: `${app.haId}#dishwasher`,
1493
1461
  name: homeConnectDishwasherEntityName(name),
1494
- type: require_dist.DeviceType.Dishwasher,
1462
+ type: require_bosch_instances.DeviceType.Dishwasher,
1495
1463
  status: "online",
1496
1464
  metadata: {
1497
1465
  serialNumber: app.haId,
@@ -1504,7 +1472,7 @@ function dishwasherContainerCandidate(app, adoptedId) {
1504
1472
  return {
1505
1473
  childNativeId: app.haId,
1506
1474
  name,
1507
- type: require_dist.DeviceType.Container,
1475
+ type: require_bosch_instances.DeviceType.Container,
1508
1476
  status: "online",
1509
1477
  metadata: {
1510
1478
  serialNumber: app.haId,
@@ -1580,7 +1548,7 @@ function buildHomeConnectAdoptionProvider(deps) {
1580
1548
  lastDiscoveryAt: null,
1581
1549
  candidateCount: 0,
1582
1550
  adoptedCount: 0,
1583
- lastError: require_dist.errMsg(err)
1551
+ lastError: require_bosch_instances.errMsg(err)
1584
1552
  };
1585
1553
  }
1586
1554
  },
@@ -1629,7 +1597,7 @@ function buildHomeConnectAdoptionProvider(deps) {
1629
1597
  logger.warn("home-connect adopt failed", { meta: {
1630
1598
  haId,
1631
1599
  integrationId,
1632
- error: require_dist.errMsg(err)
1600
+ error: require_bosch_instances.errMsg(err)
1633
1601
  } });
1634
1602
  failures++;
1635
1603
  }
@@ -2403,7 +2371,7 @@ var HomeConnectSession = class {
2403
2371
  this.#logger?.warn("Home Connect frame dropped — undecodable", {
2404
2372
  tags: this.#logTags,
2405
2373
  meta: {
2406
- error: require_dist.errMsg(err),
2374
+ error: require_bosch_instances.errMsg(err),
2407
2375
  droppedSoFar: n
2408
2376
  }
2409
2377
  });
@@ -2411,7 +2379,7 @@ var HomeConnectSession = class {
2411
2379
  #warn(message, err) {
2412
2380
  this.#logger?.warn(`Home Connect ${message}`, {
2413
2381
  tags: this.#logTags,
2414
- meta: { error: require_dist.errMsg(err) }
2382
+ meta: { error: require_bosch_instances.errMsg(err) }
2415
2383
  });
2416
2384
  }
2417
2385
  #handleWireClosed() {
@@ -2523,7 +2491,7 @@ var HomeConnectSession = class {
2523
2491
  } catch (err) {
2524
2492
  clearTimeout(timer);
2525
2493
  this.#pending.delete(outgoing.msgID);
2526
- reject(err instanceof Error ? err : new Error(require_dist.errMsg(err)));
2494
+ reject(err instanceof Error ? err : new Error(require_bosch_instances.errMsg(err)));
2527
2495
  }
2528
2496
  });
2529
2497
  }
@@ -2762,7 +2730,7 @@ function createProtocolHomeConnectClient(input) {
2762
2730
  meta: {
2763
2731
  haId,
2764
2732
  attempt,
2765
- error: require_dist.errMsg(err)
2733
+ error: require_bosch_instances.errMsg(err)
2766
2734
  }
2767
2735
  });
2768
2736
  setLink("disconnected");
@@ -3171,7 +3139,7 @@ async function enrichHomeConnectConnection(connection, fetchImpl, hooks = {}) {
3171
3139
  missing: []
3172
3140
  };
3173
3141
  const token = connection.token;
3174
- if (require_dist.isSecretMarker(token) || require_dist.isSecretMarkerLike(token)) return {
3142
+ if (require_bosch_instances.isSecretMarker(token) || require_bosch_instances.isSecretMarkerLike(token)) return {
3175
3143
  connection,
3176
3144
  changed: false,
3177
3145
  tokenRotated: false,
@@ -3180,7 +3148,7 @@ async function enrichHomeConnectConnection(connection, fetchImpl, hooks = {}) {
3180
3148
  const refreshStored = connection.refresh ?? "";
3181
3149
  const state = {
3182
3150
  token,
3183
- refresh: require_dist.isSecretMarker(refreshStored) || require_dist.isSecretMarkerLike(refreshStored) ? "" : refreshStored,
3151
+ refresh: require_bosch_instances.isSecretMarker(refreshStored) || require_bosch_instances.isSecretMarkerLike(refreshStored) ? "" : refreshStored,
3184
3152
  rotated: false,
3185
3153
  refreshTried: false
3186
3154
  };
@@ -3199,7 +3167,7 @@ async function enrichHomeConnectConnection(connection, fetchImpl, hooks = {}) {
3199
3167
  } catch (err) {
3200
3168
  hooks.onWarn?.("Home Connect IDDF fetch failed", {
3201
3169
  haId: row.haId,
3202
- error: require_dist.errMsg(err)
3170
+ error: require_bosch_instances.errMsg(err)
3203
3171
  });
3204
3172
  }
3205
3173
  if (result === null || !result.ok) {
@@ -3266,9 +3234,9 @@ async function openStoredOrAccount(connection, deps) {
3266
3234
  let missing = [];
3267
3235
  if ((working.appliances ?? []).length > 0) {
3268
3236
  const token = working.token;
3269
- if (require_dist.isSecretMarker(token) || require_dist.isSecretMarkerLike(token)) deps.logger?.warn("Home Connect skipping IDDF enrich — access token not resolved yet", {
3237
+ if (require_bosch_instances.isSecretMarker(token) || require_bosch_instances.isSecretMarkerLike(token)) deps.logger?.warn("Home Connect skipping IDDF enrich — access token not resolved yet", {
3270
3238
  tags: { integrationId: deps.integrationId },
3271
- meta: { tokenIsSecretMarker: require_dist.isSecretMarker(token) }
3239
+ meta: { tokenIsSecretMarker: require_bosch_instances.isSecretMarker(token) }
3272
3240
  });
3273
3241
  const enriched = await enrichHomeConnectConnection(working, deps.fetchImpl ?? homeConnectLoginFetch, enrichLogHooks(deps.logger, deps.integrationId));
3274
3242
  working = enriched.connection;
@@ -3396,7 +3364,7 @@ var HomeConnectIntegrationManager = class {
3396
3364
  this.#refreshStatus();
3397
3365
  this.#scheduleIddfRetry();
3398
3366
  } catch (err) {
3399
- this.#error = require_dist.errMsg(err);
3367
+ this.#error = require_bosch_instances.errMsg(err);
3400
3368
  this.#lastCheckedAt = Date.now();
3401
3369
  this.#refreshStatus();
3402
3370
  const appliances = client.getAppliances();
@@ -3472,7 +3440,7 @@ var HomeConnectIntegrationManager = class {
3472
3440
  tags: { integrationId: this.#id },
3473
3441
  meta: {
3474
3442
  haId: row.haId,
3475
- error: require_dist.errMsg(err)
3443
+ error: require_bosch_instances.errMsg(err)
3476
3444
  }
3477
3445
  });
3478
3446
  });
@@ -3486,7 +3454,7 @@ var HomeConnectIntegrationManager = class {
3486
3454
  } catch (err) {
3487
3455
  this.#logger.warn("Home Connect IDDF retry failed", {
3488
3456
  tags: { integrationId: this.#id },
3489
- meta: { error: require_dist.errMsg(err) }
3457
+ meta: { error: require_bosch_instances.errMsg(err) }
3490
3458
  });
3491
3459
  }
3492
3460
  this.#scheduleIddfRetry();
@@ -3507,7 +3475,7 @@ var HomeConnectIntegrationManager = class {
3507
3475
  } catch (err) {
3508
3476
  this.#logger.warn("HomeConnectIntegrationManager: client close failed", {
3509
3477
  tags: { integrationId: this.#id },
3510
- meta: { error: require_dist.errMsg(err) }
3478
+ meta: { error: require_bosch_instances.errMsg(err) }
3511
3479
  });
3512
3480
  }
3513
3481
  this.#onDisconnected(this.#id);
@@ -3566,7 +3534,7 @@ var HomeConnectClientRegistry = class {
3566
3534
  } catch (err) {
3567
3535
  this.#logger.warn("HomeConnectClientRegistry: applyConnection failed", { meta: {
3568
3536
  integrationId,
3569
- error: require_dist.errMsg(err)
3537
+ error: require_bosch_instances.errMsg(err)
3570
3538
  } });
3571
3539
  }
3572
3540
  return;
@@ -3592,7 +3560,7 @@ var HomeConnectClientRegistry = class {
3592
3560
  } catch (err) {
3593
3561
  this.#logger.warn("HomeConnectClientRegistry: manager start failed", { meta: {
3594
3562
  integrationId,
3595
- error: require_dist.errMsg(err)
3563
+ error: require_bosch_instances.errMsg(err)
3596
3564
  } });
3597
3565
  }
3598
3566
  }
@@ -3605,7 +3573,7 @@ var HomeConnectClientRegistry = class {
3605
3573
  } catch (err) {
3606
3574
  this.#logger.warn("HomeConnectClientRegistry: remove stop failed", { meta: {
3607
3575
  integrationId,
3608
- error: require_dist.errMsg(err)
3576
+ error: require_bosch_instances.errMsg(err)
3609
3577
  } });
3610
3578
  }
3611
3579
  }
@@ -3621,7 +3589,7 @@ var HomeConnectClientRegistry = class {
3621
3589
  } catch (err) {
3622
3590
  this.#logger.warn("HomeConnectClientRegistry: shutdown stop failed", { meta: {
3623
3591
  integrationId: id,
3624
- error: require_dist.errMsg(err)
3592
+ error: require_bosch_instances.errMsg(err)
3625
3593
  } });
3626
3594
  }
3627
3595
  }));
@@ -3675,7 +3643,7 @@ function buildHomeConnectConnectionTestProvider(deps) {
3675
3643
  detail: account.summary
3676
3644
  };
3677
3645
  } catch (err) {
3678
- const message = require_dist.errMsg(err);
3646
+ const message = require_bosch_instances.errMsg(err);
3679
3647
  if (message.includes("rejected")) return {
3680
3648
  outcome: "rejected",
3681
3649
  error: "Home Connect refused this account token. Sign in again."
@@ -3691,33 +3659,23 @@ function buildHomeConnectConnectionTestProvider(deps) {
3691
3659
  }
3692
3660
  //#endregion
3693
3661
  //#region src/home-connect/home-connect-connection-persist.ts
3694
- function locked(value) {
3695
- return require_dist.isSecretMarker(value) || require_dist.isSecretMarkerLike(value);
3696
- }
3697
3662
  /**
3698
3663
  * Persist what a connection learned at runtime — enriched IDDF entity maps and a rotated
3699
- * access / refresh token — in ONE `setSettings` write. The tokens are named in `secretKeys`
3700
- * so they land in the keychain, never on the plain blob. Writes nothing when a stored secret
3701
- * cannot be read right now: the write would drop a key it cannot see or be refused. Never
3702
- * throws and never logs a value.
3664
+ * access / refresh token — in ONE patch of the record. Writes nothing when the stored secrets
3665
+ * cannot be read right now: the patch would replace a key it cannot see. Never throws and
3666
+ * never logs a value.
3703
3667
  */
3704
3668
  function buildHomeConnectConnectionPersister(deps) {
3705
3669
  return async (integrationId, connection) => {
3706
3670
  if (!connection.appliances || connection.appliances.length === 0) return;
3707
3671
  try {
3708
- const settings = await deps.getSettings(integrationId);
3709
- const stored = readApplianceSecrets(settings[APPLIANCE_SECRETS_KEY]);
3710
- const lockedTokens = ["token", "refresh"].filter((key) => locked(settings[key]));
3711
- if (stored.kind === "unresolved" || stored.kind === "invalid" || lockedTokens.length > 0) {
3712
- deps.logger.warn("Home Connect not persisting the connection — stored secrets are locked or unreadable", {
3713
- tags: { integrationId },
3714
- meta: {
3715
- applianceSecrets: stored.kind,
3716
- lockedTokens
3717
- }
3718
- });
3672
+ const stored = await deps.read(integrationId);
3673
+ if (stored === null) return;
3674
+ if (stored.locked) {
3675
+ deps.logger.warn("Home Connect not persisting the connection — stored secrets are locked or unreadable", { tags: { integrationId } });
3719
3676
  return;
3720
3677
  }
3678
+ const settings = stored.settings;
3721
3679
  const refresh = connection.refresh ?? "";
3722
3680
  const merged = homeConnectSettingsForPersist({
3723
3681
  ...settings,
@@ -3725,15 +3683,16 @@ function buildHomeConnectConnectionPersister(deps) {
3725
3683
  ...refresh.length > 0 ? { refresh } : {},
3726
3684
  appliances: mergeAppliancesForPersist(settings["appliances"], connection.appliances)
3727
3685
  });
3728
- await deps.setSettings({
3729
- id: integrationId,
3730
- settings: merged,
3731
- secretKeys: [...HOME_CONNECT_SECRET_KEYS]
3686
+ await deps.patch(integrationId, {
3687
+ token: merged["token"],
3688
+ ...merged["refresh"] !== void 0 ? { refresh: merged["refresh"] } : {},
3689
+ appliances: merged["appliances"],
3690
+ ...merged["applianceSecrets"] !== void 0 ? { [APPLIANCE_SECRETS_KEY]: merged[APPLIANCE_SECRETS_KEY] } : {}
3732
3691
  });
3733
3692
  } catch (err) {
3734
3693
  deps.logger.warn("Home Connect failed to persist the connection", {
3735
3694
  tags: { integrationId },
3736
- meta: { error: require_dist.errMsg(err) }
3695
+ meta: { error: require_bosch_instances.errMsg(err) }
3737
3696
  });
3738
3697
  }
3739
3698
  };
@@ -3850,7 +3809,7 @@ var OPERATION_TO_STATE = {
3850
3809
  Error: "error"
3851
3810
  };
3852
3811
  function operationStateOf(raw) {
3853
- const parsed = require_dist.DishwasherOperationStateSchema.safeParse(raw);
3812
+ const parsed = require_bosch_instances.DishwasherOperationStateSchema.safeParse(raw);
3854
3813
  return parsed.success ? parsed.data : null;
3855
3814
  }
3856
3815
  /** The reported state of EVERY listed event the description has — each read on its own. */
@@ -4108,14 +4067,14 @@ function dishwasherConsumablesFromFeatures(view) {
4108
4067
  //#endregion
4109
4068
  //#region src/home-connect/home-connect-child-bindings.ts
4110
4069
  /** The capability a bound child registers. */
4111
- var HomeConnectChildCapSchema = require_dist._enum([
4070
+ var HomeConnectChildCapSchema = require_bosch_instances._enum([
4112
4071
  "numeric-sensor",
4113
4072
  "power-meter",
4114
4073
  "enum-sensor",
4115
4074
  "binary"
4116
4075
  ]);
4117
4076
  /** How the raw value becomes the slice value. */
4118
- var HomeConnectChildConvertSchema = require_dist._enum([
4077
+ var HomeConnectChildConvertSchema = require_bosch_instances._enum([
4119
4078
  "none",
4120
4079
  "energy-total-kwh",
4121
4080
  "event-active"
@@ -4124,18 +4083,18 @@ var HomeConnectChildConvertSchema = require_dist._enum([
4124
4083
  * One appliance entity exposed as one child device. Persisted on the container, so a
4125
4084
  * child's identity (`stableIdSuffix`) survives restarts and description reloads.
4126
4085
  */
4127
- var HomeConnectChildBindingSchema = require_dist.object({
4086
+ var HomeConnectChildBindingSchema = require_bosch_instances.object({
4128
4087
  /** Stable, derived from the feature key — never from a uid, which differs per model. */
4129
- stableIdSuffix: require_dist.string().min(1),
4088
+ stableIdSuffix: require_bosch_instances.string().min(1),
4130
4089
  /** Feature key the child reads (`BSH.Common.Status.DoorState`, `HomeConnect.Network.rssi`). */
4131
- key: require_dist.string().min(1),
4090
+ key: require_bosch_instances.string().min(1),
4132
4091
  cap: HomeConnectChildCapSchema,
4133
4092
  convert: HomeConnectChildConvertSchema,
4134
- role: require_dist._enum(require_dist.DeviceRole),
4093
+ role: require_bosch_instances._enum(require_bosch_instances.DeviceRole),
4135
4094
  /** Display name, without the appliance label. */
4136
- name: require_dist.string().min(1),
4095
+ name: require_bosch_instances.string().min(1),
4137
4096
  /** Unit of an info field the description does not declare (`dBm` for a signal strength). */
4138
- unit: require_dist.string().min(1).optional()
4097
+ unit: require_bosch_instances.string().min(1).optional()
4139
4098
  });
4140
4099
  function slugFeatureKey(key) {
4141
4100
  return key.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -4171,10 +4130,10 @@ function valueClassOf(entity, current) {
4171
4130
  return null;
4172
4131
  }
4173
4132
  function roleFor(entity, cls, unit) {
4174
- if (cls === "enum") return require_dist.DeviceRole.EnumSensor;
4175
- if (cls === "binary") return entity.name.endsWith("Connected") ? require_dist.DeviceRole.ConnectivitySensor : require_dist.DeviceRole.BinarySensor;
4176
- if (unit === "°C" || unit === "°F") return require_dist.DeviceRole.TemperatureSensor;
4177
- return require_dist.DeviceRole.NumericSensor;
4133
+ if (cls === "enum") return require_bosch_instances.DeviceRole.EnumSensor;
4134
+ if (cls === "binary") return entity.name.endsWith("Connected") ? require_bosch_instances.DeviceRole.ConnectivitySensor : require_bosch_instances.DeviceRole.BinarySensor;
4135
+ if (unit === "°C" || unit === "°F") return require_bosch_instances.DeviceRole.TemperatureSensor;
4136
+ return require_bosch_instances.DeviceRole.NumericSensor;
4178
4137
  }
4179
4138
  function isCumulativeEnergy(entity) {
4180
4139
  return featureShortName(entity.name) === "EnergyConsumption" && entity.name.includes(".Statistic.");
@@ -4216,7 +4175,7 @@ function bindingForEntity(entity, current) {
4216
4175
  name: "Energy total",
4217
4176
  cap: "power-meter",
4218
4177
  convert: "energy-total-kwh",
4219
- role: require_dist.DeviceRole.EnergySensor
4178
+ role: require_bosch_instances.DeviceRole.EnergySensor
4220
4179
  };
4221
4180
  return {
4222
4181
  ...base,
@@ -4244,7 +4203,7 @@ function bindingForInfo(key, current) {
4244
4203
  ...base,
4245
4204
  cap: "numeric-sensor",
4246
4205
  convert: "none",
4247
- role: require_dist.DeviceRole.NumericSensor,
4206
+ role: require_bosch_instances.DeviceRole.NumericSensor,
4248
4207
  ...unit !== void 0 ? { unit } : {}
4249
4208
  };
4250
4209
  }
@@ -4252,13 +4211,13 @@ function bindingForInfo(key, current) {
4252
4211
  ...base,
4253
4212
  cap: "binary",
4254
4213
  convert: "none",
4255
- role: require_dist.DeviceRole.BinarySensor
4214
+ role: require_bosch_instances.DeviceRole.BinarySensor
4256
4215
  };
4257
4216
  if (typeof current === "string") return {
4258
4217
  ...base,
4259
4218
  cap: "enum-sensor",
4260
4219
  convert: "none",
4261
- role: require_dist.DeviceRole.EnumSensor
4220
+ role: require_bosch_instances.DeviceRole.EnumSensor
4262
4221
  };
4263
4222
  return null;
4264
4223
  }
@@ -4323,8 +4282,8 @@ function childSliceFromValue(input) {
4323
4282
  case "numeric-sensor": {
4324
4283
  if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
4325
4284
  const unit = input.entity === void 0 ? binding.unit ?? null : resolveUnit(input.entity);
4326
- const quantity = unit === null ? "none" : require_dist.quantityFromUnit(unit);
4327
- const stored = quantity === void 0 || quantity === "device" ? null : require_dist.ingestReading({
4285
+ const quantity = unit === null ? "none" : require_bosch_instances.quantityFromUnit(unit);
4286
+ const stored = quantity === void 0 || quantity === "device" ? null : require_bosch_instances.ingestReading({
4328
4287
  value: raw,
4329
4288
  rawUnit: unit ?? void 0,
4330
4289
  quantity
@@ -4343,47 +4302,47 @@ var LEGACY_CHILD_KEYS = {
4343
4302
  "energy-forecast": {
4344
4303
  key: "BSH.Common.Option.EnergyForecast",
4345
4304
  cap: "numeric-sensor",
4346
- role: require_dist.DeviceRole.NumericSensor
4305
+ role: require_bosch_instances.DeviceRole.NumericSensor
4347
4306
  },
4348
4307
  "water-forecast": {
4349
4308
  key: "BSH.Common.Option.WaterForecast",
4350
4309
  cap: "numeric-sensor",
4351
- role: require_dist.DeviceRole.NumericSensor
4310
+ role: require_bosch_instances.DeviceRole.NumericSensor
4352
4311
  },
4353
4312
  "energy-consumed": {
4354
4313
  key: "BSH.Common.Option.EnergyConsumption",
4355
4314
  cap: "numeric-sensor",
4356
- role: require_dist.DeviceRole.NumericSensor
4315
+ role: require_bosch_instances.DeviceRole.NumericSensor
4357
4316
  },
4358
4317
  "water-consumed": {
4359
4318
  key: "BSH.Common.Option.WaterConsumption",
4360
4319
  cap: "numeric-sensor",
4361
- role: require_dist.DeviceRole.NumericSensor
4320
+ role: require_bosch_instances.DeviceRole.NumericSensor
4362
4321
  },
4363
4322
  "remote-control-level": {
4364
4323
  key: "BSH.Common.Setting.RemoteControlLevel",
4365
4324
  cap: "enum-sensor",
4366
- role: require_dist.DeviceRole.EnumSensor
4325
+ role: require_bosch_instances.DeviceRole.EnumSensor
4367
4326
  },
4368
4327
  "delayed-start": {
4369
4328
  key: "BSH.Common.Option.StartInRelative",
4370
4329
  cap: "numeric-sensor",
4371
- role: require_dist.DeviceRole.NumericSensor
4330
+ role: require_bosch_instances.DeviceRole.NumericSensor
4372
4331
  },
4373
4332
  "interior-light": {
4374
4333
  key: "BSH.Common.Setting.AmbientLightEnabled",
4375
4334
  cap: "binary",
4376
- role: require_dist.DeviceRole.BinarySensor
4335
+ role: require_bosch_instances.DeviceRole.BinarySensor
4377
4336
  },
4378
4337
  connectivity: {
4379
4338
  key: "BSH.Common.Status.BackendConnected",
4380
4339
  cap: "binary",
4381
- role: require_dist.DeviceRole.ConnectivitySensor
4340
+ role: require_bosch_instances.DeviceRole.ConnectivitySensor
4382
4341
  },
4383
4342
  "program-phase": {
4384
4343
  key: "Dishcare.Dishwasher.Status.ProgramPhase",
4385
4344
  cap: "enum-sensor",
4386
- role: require_dist.DeviceRole.EnumSensor
4345
+ role: require_bosch_instances.DeviceRole.EnumSensor
4387
4346
  }
4388
4347
  };
4389
4348
  /**
@@ -4586,7 +4545,7 @@ var HomeConnectChildReconciler = class {
4586
4545
  } catch (err) {
4587
4546
  this.#deps.logger.warn("Home Connect child reconcile failed", {
4588
4547
  tags: { deviceId },
4589
- meta: { error: require_dist.errMsg(err) }
4548
+ meta: { error: require_bosch_instances.errMsg(err) }
4590
4549
  });
4591
4550
  }
4592
4551
  }
@@ -4691,12 +4650,12 @@ function assertProgramOptions(description, program, options) {
4691
4650
  }
4692
4651
  //#endregion
4693
4652
  //#region src/home-connect/devices/home-connect-dishwasher-device.ts
4694
- var homeConnectDishwasherSchema = require_dist.object({
4695
- haId: require_dist.string().min(1),
4696
- brokerId: require_dist.string().min(1),
4697
- applianceType: require_dist.string().optional(),
4698
- system: require_dist.literal("home-connect").optional(),
4699
- integrationId: require_dist.string().optional()
4653
+ var homeConnectDishwasherSchema = require_bosch_instances.object({
4654
+ haId: require_bosch_instances.string().min(1),
4655
+ brokerId: require_bosch_instances.string().min(1),
4656
+ applianceType: require_bosch_instances.string().optional(),
4657
+ system: require_bosch_instances.literal("home-connect").optional(),
4658
+ integrationId: require_bosch_instances.string().optional()
4700
4659
  });
4701
4660
  var DISH_CAP = "dishwasher";
4702
4661
  var CONSUMABLES_CAP = "consumables";
@@ -4717,14 +4676,14 @@ var OPTION_NAMES = {
4717
4676
  intensiveZone: ["IntensivZone", "IntensiveZone"],
4718
4677
  varioSpeedPlus: ["VarioSpeedPlus", "VarioSpeed"]
4719
4678
  };
4720
- var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4679
+ var HomeConnectDishwasherDevice = class extends require_bosch_instances.BaseDevice {
4721
4680
  features = [];
4722
4681
  #haId;
4723
4682
  #brokerId;
4724
4683
  #unwatch = null;
4725
4684
  constructor(ctx) {
4726
4685
  const persisted = homeConnectDishwasherSchema.parse(ctx.persistedConfig ?? {});
4727
- super(ctx, homeConnectDishwasherSchema, { type: require_dist.DeviceType.Dishwasher });
4686
+ super(ctx, homeConnectDishwasherSchema, { type: require_bosch_instances.DeviceType.Dishwasher });
4728
4687
  this.#haId = persisted.haId;
4729
4688
  this.#brokerId = persisted.brokerId;
4730
4689
  this.updateSourceInfo({
@@ -4738,7 +4697,7 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4738
4697
  this.registerConsumablesCap();
4739
4698
  this.registerRunningCap();
4740
4699
  this.runtimeState.setCapState(DISH_CAP, COLD_DISHWASHER_STATUS);
4741
- this.runtimeState.setCapState(RUNNING_CAP, require_dist.RUNNING_STATE_COLD);
4700
+ this.runtimeState.setCapState(RUNNING_CAP, require_bosch_instances.RUNNING_STATE_COLD);
4742
4701
  this.markOnline(false);
4743
4702
  this.#unwatch = homeConnectConnections.watch(this.#brokerId, this.#haId, (event) => this.recomputeSlice(event));
4744
4703
  this.recomputeSlice({ kind: "client" });
@@ -4791,7 +4750,7 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4791
4750
  this.runtimeState.setCapState(CONSUMABLES_CAP, next);
4792
4751
  }
4793
4752
  registerConsumablesCap() {
4794
- this.ctx.registerNativeCap(require_dist.consumablesCapability, {
4753
+ this.ctx.registerNativeCap(require_bosch_instances.consumablesCapability, {
4795
4754
  getStatus: async () => this.runtimeState.getCapState(CONSUMABLES_CAP) ?? CONSUMABLES_EMPTY,
4796
4755
  reset: async ({ key }) => {
4797
4756
  throw new Error(`"${key}" has no reset on a dishwasher — refilling it is the reset`);
@@ -4828,13 +4787,13 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4828
4787
  } catch (err) {
4829
4788
  this.ctx.logger.warn(`Home Connect ${what} failed`, {
4830
4789
  tags: { deviceId: this.id },
4831
- meta: { error: require_dist.errMsg(err) }
4790
+ meta: { error: require_bosch_instances.errMsg(err) }
4832
4791
  });
4833
4792
  throw err;
4834
4793
  }
4835
4794
  }
4836
4795
  registerDishwasherCap() {
4837
- this.ctx.registerNativeCap(require_dist.dishwasherCapability, {
4796
+ this.ctx.registerNativeCap(require_bosch_instances.dishwasherCapability, {
4838
4797
  getStatus: async () => this.runtimeState.getCapState(DISH_CAP) ?? COLD_DISHWASHER_STATUS,
4839
4798
  getOptions: async () => dishwasherOptionsFromDescription(this.view()),
4840
4799
  start: async ({ program, options }) => {
@@ -4872,22 +4831,22 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4872
4831
  });
4873
4832
  }
4874
4833
  registerRunningCap() {
4875
- this.ctx.registerNativeCap(require_dist.runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? require_dist.RUNNING_STATE_COLD });
4834
+ this.ctx.registerNativeCap(require_bosch_instances.runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? require_bosch_instances.RUNNING_STATE_COLD });
4876
4835
  }
4877
4836
  publishRunningSlice(slice) {
4878
4837
  const fetchedAt = Date.now();
4879
4838
  const previous = this.runtimeState.getCapState(RUNNING_CAP);
4880
- const next = require_dist.runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.remaining);
4839
+ const next = require_bosch_instances.runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.remaining);
4881
4840
  this.runtimeState.setCapState(RUNNING_CAP, next);
4882
4841
  }
4883
4842
  };
4884
4843
  //#endregion
4885
4844
  //#region src/home-connect/devices/home-connect-event-device.ts
4886
- var homeConnectEventSchema = require_dist.object({
4887
- haId: require_dist.string().min(1),
4888
- brokerId: require_dist.string().min(1),
4889
- system: require_dist.literal("home-connect").optional(),
4890
- integrationId: require_dist.string().optional()
4845
+ var homeConnectEventSchema = require_bosch_instances.object({
4846
+ haId: require_bosch_instances.string().min(1),
4847
+ brokerId: require_bosch_instances.string().min(1),
4848
+ system: require_bosch_instances.literal("home-connect").optional(),
4849
+ integrationId: require_bosch_instances.string().optional()
4891
4850
  });
4892
4851
  var EVENT_CAP = "event-emitter";
4893
4852
  /**
@@ -4898,7 +4857,7 @@ var EVENT_CAP = "event-emitter";
4898
4857
  * A value seen while the link is still being established (the handshake's initial values)
4899
4858
  * is the baseline, not a new event: a reconnect must not announce "program finished" again.
4900
4859
  */
4901
- var HomeConnectEventDevice = class extends require_dist.BaseDevice {
4860
+ var HomeConnectEventDevice = class extends require_bosch_instances.BaseDevice {
4902
4861
  features = [];
4903
4862
  #haId;
4904
4863
  #brokerId;
@@ -4908,7 +4867,7 @@ var HomeConnectEventDevice = class extends require_dist.BaseDevice {
4908
4867
  #unwatch = null;
4909
4868
  constructor(ctx) {
4910
4869
  const persisted = homeConnectEventSchema.parse(ctx.persistedConfig ?? {});
4911
- super(ctx, homeConnectEventSchema, { type: require_dist.DeviceType.EventEmitter });
4870
+ super(ctx, homeConnectEventSchema, { type: require_bosch_instances.DeviceType.EventEmitter });
4912
4871
  this.#haId = persisted.haId;
4913
4872
  this.#brokerId = persisted.brokerId;
4914
4873
  this.updateSourceInfo({
@@ -4977,7 +4936,7 @@ var HomeConnectEventDevice = class extends require_dist.BaseDevice {
4977
4936
  timestamp: Date.now(),
4978
4937
  seq: ++this.#seq
4979
4938
  };
4980
- this.ctx.eventBus.emit(require_dist.createEvent(require_dist.EventCategory.EventEmitted, {
4939
+ this.ctx.eventBus.emit(require_bosch_instances.createEvent(require_bosch_instances.EventCategory.EventEmitted, {
4981
4940
  type: "device",
4982
4941
  id: this.stableId,
4983
4942
  deviceId: this.id,
@@ -4986,7 +4945,7 @@ var HomeConnectEventDevice = class extends require_dist.BaseDevice {
4986
4945
  this.publish(types, previous, fire);
4987
4946
  }
4988
4947
  registerCap() {
4989
- this.ctx.registerNativeCap(require_dist.eventEmitterCapability, { getStatus: async () => this.runtimeState.getCapState(EVENT_CAP) ?? {
4948
+ this.ctx.registerNativeCap(require_bosch_instances.eventEmitterCapability, { getStatus: async () => this.runtimeState.getCapState(EVENT_CAP) ?? {
4990
4949
  eventTypes: [],
4991
4950
  lastEvent: null,
4992
4951
  eventCountSinceStart: 0
@@ -4995,18 +4954,18 @@ var HomeConnectEventDevice = class extends require_dist.BaseDevice {
4995
4954
  };
4996
4955
  //#endregion
4997
4956
  //#region src/home-connect/devices/home-connect-sensor-device.ts
4998
- var homeConnectSensorSchema = require_dist.object({
4999
- haId: require_dist.string().min(1),
5000
- brokerId: require_dist.string().min(1),
4957
+ var homeConnectSensorSchema = require_bosch_instances.object({
4958
+ haId: require_bosch_instances.string().min(1),
4959
+ brokerId: require_bosch_instances.string().min(1),
5001
4960
  /**
5002
4961
  * The entity this child reads. Absent on a child persisted by the fixed-catalog build,
5003
4962
  * which wrote `sensorKind` instead — see {@link resolveSensorBinding}.
5004
4963
  */
5005
4964
  binding: HomeConnectChildBindingSchema.optional(),
5006
4965
  /** Fixed-catalog children only: the old kind, which is also their stable suffix. */
5007
- sensorKind: require_dist.string().min(1).optional(),
5008
- system: require_dist.literal("home-connect").optional(),
5009
- integrationId: require_dist.string().optional()
4966
+ sensorKind: require_bosch_instances.string().min(1).optional(),
4967
+ system: require_bosch_instances.literal("home-connect").optional(),
4968
+ integrationId: require_bosch_instances.string().optional()
5010
4969
  });
5011
4970
  /**
5012
4971
  * The binding of a persisted child row. A restored child's config is the row the KERNEL
@@ -5045,7 +5004,7 @@ var NEVER_BINARY = {
5045
5004
  * entity it reads is its `binding.key` — one key, never "the first of several that
5046
5005
  * happens to be present".
5047
5006
  */
5048
- var HomeConnectSensorDevice = class extends require_dist.BaseDevice {
5007
+ var HomeConnectSensorDevice = class extends require_bosch_instances.BaseDevice {
5049
5008
  features = [];
5050
5009
  #haId;
5051
5010
  #brokerId;
@@ -5111,32 +5070,32 @@ var HomeConnectSensorDevice = class extends require_dist.BaseDevice {
5111
5070
  registerCap() {
5112
5071
  switch (this.#binding.cap) {
5113
5072
  case "numeric-sensor":
5114
- this.ctx.registerNativeCap(require_dist.numericSensorCapability, { getStatus: async () => this.runtimeState.getCapState("numeric-sensor") ?? NEVER_NUMERIC });
5073
+ this.ctx.registerNativeCap(require_bosch_instances.numericSensorCapability, { getStatus: async () => this.runtimeState.getCapState("numeric-sensor") ?? NEVER_NUMERIC });
5115
5074
  return;
5116
5075
  case "power-meter":
5117
- this.ctx.registerNativeCap(require_dist.powerMeterCapability, { getStatus: async () => this.runtimeState.getCapState("power-meter") ?? NEVER_POWER });
5076
+ this.ctx.registerNativeCap(require_bosch_instances.powerMeterCapability, { getStatus: async () => this.runtimeState.getCapState("power-meter") ?? NEVER_POWER });
5118
5077
  return;
5119
5078
  case "enum-sensor":
5120
- this.ctx.registerNativeCap(require_dist.enumSensorCapability, { getStatus: async () => this.runtimeState.getCapState("enum-sensor") ?? NEVER_ENUM });
5079
+ this.ctx.registerNativeCap(require_bosch_instances.enumSensorCapability, { getStatus: async () => this.runtimeState.getCapState("enum-sensor") ?? NEVER_ENUM });
5121
5080
  return;
5122
5081
  case "binary":
5123
- this.ctx.registerNativeCap(require_dist.binaryCapability, { getStatus: async () => this.runtimeState.getCapState("binary") ?? NEVER_BINARY });
5082
+ this.ctx.registerNativeCap(require_bosch_instances.binaryCapability, { getStatus: async () => this.runtimeState.getCapState("binary") ?? NEVER_BINARY });
5124
5083
  return;
5125
5084
  }
5126
5085
  }
5127
5086
  };
5128
5087
  //#endregion
5129
5088
  //#region src/home-connect/devices/home-connect-appliance-device.ts
5130
- var homeConnectApplianceSchema = require_dist.object({
5131
- haId: require_dist.string().min(1),
5132
- brokerId: require_dist.string().min(1),
5133
- applianceType: require_dist.string().optional(),
5089
+ var homeConnectApplianceSchema = require_bosch_instances.object({
5090
+ haId: require_bosch_instances.string().min(1),
5091
+ brokerId: require_bosch_instances.string().min(1),
5092
+ applianceType: require_bosch_instances.string().optional(),
5134
5093
  /** One entry per appliance entity exposed as a child, maintained from the appliance's description. */
5135
- entities: require_dist.array(require_dist.unknown()).optional(),
5094
+ entities: require_bosch_instances.array(require_bosch_instances.unknown()).optional(),
5136
5095
  /** Children persisted before the description-derived model; read only to keep them alive. */
5137
- children: require_dist.array(require_dist.unknown()).optional(),
5138
- system: require_dist.literal("home-connect").optional(),
5139
- integrationId: require_dist.string().optional()
5096
+ children: require_bosch_instances.array(require_bosch_instances.unknown()).optional(),
5097
+ system: require_bosch_instances.literal("home-connect").optional(),
5098
+ integrationId: require_bosch_instances.string().optional()
5140
5099
  });
5141
5100
  /** Device metadata keys the `/ci/info` fields map onto (the conventional `DeviceMetadata` keys). */
5142
5101
  var INFO_TO_METADATA = {
@@ -5151,7 +5110,7 @@ var INFO_TO_METADATA = {
5151
5110
  mac: "mac"
5152
5111
  };
5153
5112
  /** One Home Connect appliance as a container: the dishwasher, an event emitter, and one child per entity. */
5154
- var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5113
+ var HomeConnectApplianceDevice = class extends require_bosch_instances.BaseDevice {
5155
5114
  features = [];
5156
5115
  integrationId;
5157
5116
  brokerId;
@@ -5161,7 +5120,7 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5161
5120
  #lastInfo = "";
5162
5121
  constructor(ctx) {
5163
5122
  const cfg = homeConnectApplianceSchema.parse(ctx.persistedConfig ?? {});
5164
- super(ctx, homeConnectApplianceSchema, { type: require_dist.DeviceType.Container });
5123
+ super(ctx, homeConnectApplianceSchema, { type: require_bosch_instances.DeviceType.Container });
5165
5124
  this.brokerId = cfg.brokerId;
5166
5125
  this.haId = cfg.haId;
5167
5126
  this.integrationId = cfg.integrationId;
@@ -5208,7 +5167,7 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5208
5167
  } catch (err) {
5209
5168
  this.ctx.logger.warn("Home Connect could not publish the appliance info", {
5210
5169
  tags: { deviceId: this.id },
5211
- meta: { error: require_dist.errMsg(err) }
5170
+ meta: { error: require_bosch_instances.errMsg(err) }
5212
5171
  });
5213
5172
  }
5214
5173
  }
@@ -5226,7 +5185,7 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5226
5185
  const out = [{
5227
5186
  stableIdSuffix: "dishwasher",
5228
5187
  meta: {
5229
- type: require_dist.DeviceType.Dishwasher,
5188
+ type: require_bosch_instances.DeviceType.Dishwasher,
5230
5189
  name: homeConnectDishwasherEntityName(containerName),
5231
5190
  linkDeviceId: this.id,
5232
5191
  ...integration
@@ -5240,7 +5199,7 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5240
5199
  if (bindings.some((b) => b.convert === "event-active")) out.push({
5241
5200
  stableIdSuffix: "events",
5242
5201
  meta: {
5243
- type: require_dist.DeviceType.EventEmitter,
5202
+ type: require_bosch_instances.DeviceType.EventEmitter,
5244
5203
  name: `${containerName} — Events`,
5245
5204
  linkDeviceId: this.id,
5246
5205
  ...integration
@@ -5251,7 +5210,7 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5251
5210
  for (const binding of bindings) out.push({
5252
5211
  stableIdSuffix: binding.stableIdSuffix,
5253
5212
  meta: {
5254
- type: require_dist.DeviceType.Sensor,
5213
+ type: require_bosch_instances.DeviceType.Sensor,
5255
5214
  role: binding.role,
5256
5215
  name: `${containerName} — ${binding.name}`,
5257
5216
  linkDeviceId: this.id,
@@ -5266,57 +5225,151 @@ var HomeConnectApplianceDevice = class extends require_dist.BaseDevice {
5266
5225
  return out;
5267
5226
  }
5268
5227
  };
5269
- //#endregion
5270
- //#region src/home-connect/home-connect-secret-adopt.ts
5228
+ var homeConnectConnectionsEntryKind = require_bosch_instances.defineEntryKind("connections", {
5229
+ title: "Home Connect accounts",
5230
+ schema: require_bosch_instances.entryBody({
5231
+ token: require_bosch_instances.string().optional().meta({ secret: true }),
5232
+ refresh: require_bosch_instances.string().optional().meta({ secret: true }),
5233
+ /** JSON of `haId -> { psk, iv64? }`: one string in the keychain. */
5234
+ applianceSecrets: require_bosch_instances.string().optional().meta({ secret: true }),
5235
+ appliances: require_bosch_instances.array(homeConnectApplianceRowSchema).optional(),
5236
+ accountLabel: require_bosch_instances.string().optional()
5237
+ }),
5238
+ writeTrigger: "an operator signs in, edits or removes a Home Connect account, or a connection stores what it learned",
5239
+ maxDataBytes: 1024 * 1024
5240
+ });
5241
+ /** Every kind this addon declares, keyed by its name. */
5242
+ var homeConnectRecordKinds = { connections: homeConnectConnectionsEntryKind };
5243
+ var LEGACY_KEYS = [
5244
+ "token",
5245
+ "refresh",
5246
+ APPLIANCE_SECRETS_KEY,
5247
+ "appliances",
5248
+ "accountLabel",
5249
+ "accountEmail",
5250
+ "accountPassword",
5251
+ "authorizeUrl",
5252
+ "verifier",
5253
+ "callback",
5254
+ "state"
5255
+ ];
5256
+ var SECRET_KEYS = [
5257
+ "token",
5258
+ "refresh",
5259
+ APPLIANCE_SECRETS_KEY
5260
+ ];
5261
+ /** The `appliances` row value as an array: a JSON string is parsed, anything else is as stored. */
5262
+ function parseStoredRows(raw) {
5263
+ if (typeof raw !== "string") return raw;
5264
+ try {
5265
+ return JSON.parse(raw);
5266
+ } catch {
5267
+ return;
5268
+ }
5269
+ }
5270
+ function text(value) {
5271
+ return typeof value === "string" && value.length > 0 ? value : void 0;
5272
+ }
5271
5273
  /**
5272
- * One-time adopt: an integration saved before the keychain move carries each appliance's
5273
- * pairing key (`psk`, `iv64`) on its row, in clear text. Plan the move into `applianceSecrets`
5274
- * (keychain), with the rows stripped.
5275
- *
5276
- * `null` when there is nothing to move — settings already migrated, or the stored keys are
5277
- * locked (the move could not see what it would replace). Idempotent.
5274
+ * The record body of one account, from its legacy rows (secrets resolved). A pairing key still
5275
+ * sitting on an appliance row (the shape before the keychain move) is carried into
5276
+ * `applianceSecrets` here, once, and never again.
5278
5277
  */
5279
- function planLegacyApplianceSecretAdopt(deps, integrationId, settings) {
5280
- const patch = legacyApplianceSecretPatch(settings);
5281
- if (patch === null) return null;
5282
- const next = {
5283
- ...settings,
5284
- ...patch
5278
+ function homeConnectBodyFromRows(values, log, integration) {
5279
+ const dropped = Object.keys(values).filter((key) => !LEGACY_KEYS.includes(key));
5280
+ if (dropped.length > 0) log.warn(`integration '${integration.id}': legacy settings nothing reads any more are dropped: ${dropped.join(", ")}`);
5281
+ const normalized = homeConnectSettingsForPersist({ ...values });
5282
+ const storedRows = parseStoredRows(values["appliances"]);
5283
+ if (Array.isArray(storedRows)) for (const row of storedRows) {
5284
+ const parsed = homeConnectApplianceRowSchema.safeParse(row);
5285
+ if (parsed.success) continue;
5286
+ const haId = typeof row === "object" && row !== null && typeof Reflect.get(row, "haId") === "string" ? String(Reflect.get(row, "haId")) : "(no haId)";
5287
+ const paths = parsed.error.issues.map((issue) => issue.path.join(".") || "(row)").join(", ");
5288
+ log.warn(`integration '${integration.id}': appliance row '${haId}' could not be read and is dropped (invalid: ${paths})`);
5289
+ }
5290
+ const appliances = [];
5291
+ const keptRows = normalized["appliances"];
5292
+ if (Array.isArray(keptRows)) for (const row of keptRows) {
5293
+ const parsed = homeConnectApplianceRowSchema.safeParse(row);
5294
+ if (parsed.success) appliances.push(parsed.data);
5295
+ }
5296
+ const token = text(normalized["token"]);
5297
+ const refresh = text(normalized["refresh"]);
5298
+ const applianceSecrets = text(normalized[APPLIANCE_SECRETS_KEY]);
5299
+ const accountLabel = text(normalized["accountLabel"]);
5300
+ return {
5301
+ name: integration.name,
5302
+ ...token !== void 0 ? { token } : {},
5303
+ ...refresh !== void 0 ? { refresh } : {},
5304
+ ...applianceSecrets !== void 0 ? { applianceSecrets } : {},
5305
+ ...appliances.length > 0 ? { appliances } : {},
5306
+ ...accountLabel !== void 0 ? { accountLabel } : {}
5285
5307
  };
5308
+ }
5309
+ /** The whole `bosch-home-connect` catalogue (D987): offered to the engine at `onInitialize`. */
5310
+ var HOME_CONNECT_MIGRATIONS = [require_bosch_instances.boschRowsMigration({
5311
+ addonId: "bosch-home-connect",
5312
+ id: "bosch-home-connect/2026-11-05-integration-rows-to-record",
5313
+ description: "Move every Home Connect account into a typed instance record keyed by its registry id (pairing keys still on an appliance row go to the appliance secrets), then clear the legacy integration settings rows and their keychain values",
5314
+ fixtureMark: "a legacy setting key the migration does not know",
5315
+ kind: homeConnectConnectionsEntryKind,
5316
+ bodyFrom: homeConnectBodyFromRows
5317
+ })];
5318
+ function homeConnectRowsPorts(deps) {
5319
+ return require_bosch_instances.boschRowsPorts({
5320
+ ...deps,
5321
+ kind: homeConnectConnectionsEntryKind
5322
+ });
5323
+ }
5324
+ async function homeConnectStoredOf(instances, id) {
5325
+ const read = await instances.readResolved(id);
5326
+ if (read === null) return null;
5286
5327
  return {
5287
- settings: next,
5288
- persist: async () => {
5289
- try {
5290
- await deps.setSettings({
5291
- id: integrationId,
5292
- settings: next,
5293
- secretKeys: [...HOME_CONNECT_SECRET_KEYS]
5294
- });
5295
- deps.logger.info("Home Connect moved the appliance pairing keys into the keychain", {
5296
- tags: { integrationId },
5297
- meta: { appliances: patch.appliances.length }
5298
- });
5299
- } catch (err) {
5300
- deps.logger.warn("Home Connect could not move the appliance pairing keys into the keychain", {
5301
- tags: { integrationId },
5302
- meta: { error: require_dist.errMsg(err) }
5303
- });
5304
- }
5305
- }
5328
+ settings: { ...read.body },
5329
+ locked: read.secrets === "unavailable"
5330
+ };
5331
+ }
5332
+ function buildHomeConnectInstances(records, deps) {
5333
+ const handle = records.kind(homeConnectConnectionsEntryKind);
5334
+ const instances = new require_bosch_instances.RecordIntegrationInstances(records, homeConnectConnectionsEntryKind, {
5335
+ description: {
5336
+ role: "devices",
5337
+ instanceMode: "multiple",
5338
+ kind: "account",
5339
+ canTest: true
5340
+ },
5341
+ formSchema: () => buildHomeConnectFormSchema(),
5342
+ initialBody: (name) => ({ name }),
5343
+ configured: (body) => connectionFromSettings(body) !== null,
5344
+ onChanged: async (_id, change) => {
5345
+ if (change !== "deleted") await deps.onChanged();
5346
+ },
5347
+ test: (input) => require_bosch_instances.testBoschInstance({
5348
+ ...input,
5349
+ tester: deps.tester,
5350
+ handle,
5351
+ secretKeys: SECRET_KEYS
5352
+ })
5353
+ });
5354
+ return {
5355
+ instances,
5356
+ handle,
5357
+ provider: require_bosch_instances.keepBodyKeys(instances.toProvider(), new Set(Object.keys(homeConnectConnectionsEntryKind.schema.shape)))
5306
5358
  };
5307
5359
  }
5308
5360
  //#endregion
5309
5361
  //#region src/home-connect/addon.ts
5310
- var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvider {
5362
+ var BoschHomeConnectProviderAddon = class extends require_bosch_instances.BaseDeviceProvider {
5311
5363
  addonId = "bosch-home-connect";
5312
5364
  providerName = "Bosch Home Connect";
5313
5365
  deviceClasses = {
5314
- [require_dist.DeviceType.Container]: HomeConnectApplianceDevice,
5315
- [require_dist.DeviceType.Dishwasher]: HomeConnectDishwasherDevice,
5316
- [require_dist.DeviceType.Sensor]: HomeConnectSensorDevice,
5317
- [require_dist.DeviceType.EventEmitter]: HomeConnectEventDevice
5366
+ [require_bosch_instances.DeviceType.Container]: HomeConnectApplianceDevice,
5367
+ [require_bosch_instances.DeviceType.Dishwasher]: HomeConnectDishwasherDevice,
5368
+ [require_bosch_instances.DeviceType.Sensor]: HomeConnectSensorDevice,
5369
+ [require_bosch_instances.DeviceType.EventEmitter]: HomeConnectEventDevice
5318
5370
  };
5319
5371
  clients = null;
5372
+ instances = null;
5320
5373
  reconciler = null;
5321
5374
  loginProxy = null;
5322
5375
  loginPlane = null;
@@ -5325,6 +5378,19 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5325
5378
  }
5326
5379
  async onInitialize() {
5327
5380
  const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
5381
+ const records = this.ctx.records;
5382
+ if (records === void 0) throw new Error("bosch-home-connect: ctx.records is required (hub-only addon)");
5383
+ await records.declare(homeConnectRecordKinds);
5384
+ await this.runMigrations(require_bosch_instances.defineAddonMigrations(HOME_CONNECT_MIGRATIONS, homeConnectRowsPorts({
5385
+ api: require_bosch_instances.defaultIntegrationApiOver(this.ctx.api),
5386
+ records,
5387
+ warn: (message) => this.ctx.logger.warn(message)
5388
+ })));
5389
+ const built = buildHomeConnectInstances(records, {
5390
+ onChanged: () => this.reconcileIntegrations(),
5391
+ tester: this.buildConnectionTestProvider()
5392
+ });
5393
+ this.instances = built;
5328
5394
  await this.serveLoginProxy();
5329
5395
  this.clients = new HomeConnectClientRegistry(this.ctx.logger, { onConnectionUpdated: (integrationId, connection) => {
5330
5396
  this.persistIntegrationAppliances(integrationId, connection);
@@ -5344,12 +5410,16 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5344
5410
  providers: [
5345
5411
  ...regs,
5346
5412
  {
5347
- capability: require_dist.deviceAdoptionCapability,
5413
+ capability: require_bosch_instances.deviceAdoptionCapability,
5348
5414
  provider: this.buildAdoptionProvider()
5349
5415
  },
5350
5416
  {
5351
- capability: require_dist.connectionTestCapability,
5417
+ capability: require_bosch_instances.connectionTestCapability,
5352
5418
  provider: this.buildConnectionTestProvider()
5419
+ },
5420
+ {
5421
+ capability: require_bosch_instances.integrationInstancesCapability,
5422
+ provider: built.provider
5353
5423
  }
5354
5424
  ],
5355
5425
  customActions: homeConnectActions,
@@ -5382,7 +5452,7 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5382
5452
  }
5383
5453
  /** The hub's HTTPS face for the vendor's login pages (D955): admin session only. */
5384
5454
  async serveLoginProxy() {
5385
- const proxy = new require_dist.VendorLoginProxy({
5455
+ const proxy = new require_bosch_instances.VendorLoginProxy({
5386
5456
  addonId: this.ctx.id,
5387
5457
  logger: this.ctx.logger
5388
5458
  });
@@ -5394,7 +5464,7 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5394
5464
  }) ?? null;
5395
5465
  if (this.loginPlane !== null) this.loginProxy = proxy;
5396
5466
  } catch (err) {
5397
- this.ctx.logger.warn("Home Connect login proxy failed to serve — sign-in falls back to paste", { meta: { error: require_dist.errMsg(err) } });
5467
+ this.ctx.logger.warn("Home Connect login proxy failed to serve — sign-in falls back to paste", { meta: { error: require_bosch_instances.errMsg(err) } });
5398
5468
  }
5399
5469
  }
5400
5470
  async onShutdown() {
@@ -5406,9 +5476,10 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5406
5476
  try {
5407
5477
  await this.clients?.shutdown();
5408
5478
  } catch (err) {
5409
- this.ctx.logger.warn("Home Connect shutdown error", { meta: { error: require_dist.errMsg(err) } });
5479
+ this.ctx.logger.warn("Home Connect shutdown error", { meta: { error: require_bosch_instances.errMsg(err) } });
5410
5480
  }
5411
5481
  this.clients = null;
5482
+ this.instances = null;
5412
5483
  await super.onShutdown();
5413
5484
  }
5414
5485
  requireClients() {
@@ -5420,14 +5491,14 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5420
5491
  if (typeof integrationId !== "string" || integrationId.length === 0) throw new Error("home-connect generateStableId: brokerId required");
5421
5492
  const haId = config?.["haId"];
5422
5493
  if (typeof haId !== "string" || haId.length === 0) throw new Error("home-connect generateStableId: haId required");
5423
- if (type === require_dist.DeviceType.Container) return `home-connect:${integrationId}:${haId}:appliance`;
5494
+ if (type === require_bosch_instances.DeviceType.Container) return `home-connect:${integrationId}:${haId}:appliance`;
5424
5495
  return `home-connect:${integrationId}:${haId}`;
5425
5496
  }
5426
5497
  /** Enriched IDDF maps and a rotated token pair, in one keychain-aware write. */
5427
5498
  persistIntegrationAppliances(integrationId, connection) {
5428
5499
  return buildHomeConnectConnectionPersister({
5429
- getSettings: (id) => this.ctx.api.integrations.getSettings.query({ id }),
5430
- setSettings: (input) => this.ctx.api.integrations.setSettings.mutate(input),
5500
+ read: (id) => homeConnectStoredOf(this.requireInstances().instances, id),
5501
+ patch: (id, patch) => this.requireInstances().handle.patch(id, patch),
5431
5502
  logger: this.ctx.logger
5432
5503
  })(integrationId, connection);
5433
5504
  }
@@ -5436,15 +5507,14 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5436
5507
  try {
5437
5508
  const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id && i.enabled);
5438
5509
  const surviving = /* @__PURE__ */ new Set();
5439
- const secretMoves = [];
5440
5510
  for (const integration of mine) try {
5441
- const stored = await this.ctx.api.integrations.getSettings.query({ id: integration.id });
5442
- const adopt = planLegacyApplianceSecretAdopt({
5443
- setSettings: (input) => this.ctx.api.integrations.setSettings.mutate(input),
5444
- logger: this.ctx.logger
5445
- }, integration.id, stored);
5446
- if (adopt !== null) secretMoves.push(adopt);
5447
- const settings = adopt?.settings ?? stored;
5511
+ const stored = await homeConnectStoredOf(this.requireInstances().instances, integration.id);
5512
+ if (stored === null) continue;
5513
+ if (stored.locked) {
5514
+ this.ctx.logger.warn("Home Connect reconcile skipped: the keychain is locked", { meta: { integrationId: integration.id } });
5515
+ continue;
5516
+ }
5517
+ const settings = stored.settings;
5448
5518
  const connection = connectionFromSettings(settings);
5449
5519
  if (!connection) {
5450
5520
  logHomeConnectSettingsGap(this.ctx.logger, integration.id, settings);
@@ -5465,10 +5535,9 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5465
5535
  } catch (err) {
5466
5536
  this.ctx.logger.warn("Home Connect reconcile failed for integration", { meta: {
5467
5537
  integrationId: integration.id,
5468
- error: require_dist.errMsg(err)
5538
+ error: require_bosch_instances.errMsg(err)
5469
5539
  } });
5470
5540
  }
5471
- for (const move of secretMoves) move.persist();
5472
5541
  const vanished = reg.list().filter((id) => !surviving.has(id));
5473
5542
  await reg.retain(surviving);
5474
5543
  const deviceReg = this.ctx.kernel.deviceRegistry;
@@ -5482,7 +5551,7 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5482
5551
  logger: this.ctx.logger
5483
5552
  });
5484
5553
  } catch (err) {
5485
- this.ctx.logger.warn("Home Connect integration reconcile failed", { meta: { error: require_dist.errMsg(err) } });
5554
+ this.ctx.logger.warn("Home Connect integration reconcile failed", { meta: { error: require_bosch_instances.errMsg(err) } });
5486
5555
  }
5487
5556
  }
5488
5557
  subscribeIntegrationLifecycle() {
@@ -5491,9 +5560,9 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5491
5560
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
5492
5561
  this.reconcileIntegrations();
5493
5562
  };
5494
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationEnabled }, handler);
5495
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDisabled }, handler);
5496
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDeleted }, handler);
5563
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
5564
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
5565
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
5497
5566
  }
5498
5567
  buildConnectionTestProvider() {
5499
5568
  return buildHomeConnectConnectionTestProvider({ logger: this.ctx.logger });
@@ -5520,7 +5589,7 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5520
5589
  adoptDevice: async ({ haId, integrationId, type, name, applianceType }) => {
5521
5590
  const devices = this.ctx.kernel.devices;
5522
5591
  if (!devices) throw new Error("home-connect adopt: devices unavailable");
5523
- if (type !== require_dist.DeviceType.Container) throw new Error(`home-connect adopt: expected Container, got ${type}`);
5592
+ if (type !== require_bosch_instances.DeviceType.Container) throw new Error(`home-connect adopt: expected Container, got ${type}`);
5524
5593
  const config = {
5525
5594
  haId,
5526
5595
  brokerId: integrationId,
@@ -5531,7 +5600,7 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5531
5600
  };
5532
5601
  const stableId = this.generateStableId(type, config);
5533
5602
  const device = await devices.create(stableId, HomeConnectApplianceDevice, config, null, {
5534
- type: require_dist.DeviceType.Container,
5603
+ type: require_bosch_instances.DeviceType.Container,
5535
5604
  name,
5536
5605
  integrationId
5537
5606
  });
@@ -5596,9 +5665,6 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5596
5665
  logger: this.ctx.logger
5597
5666
  }, trigger);
5598
5667
  }
5599
- globalSettingsSchema() {
5600
- return buildHomeConnectFormSchema();
5601
- }
5602
5668
  async supportsManualCreation() {
5603
5669
  return false;
5604
5670
  }
@@ -5608,6 +5674,10 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5608
5674
  async onCreateDevice(_type, _config) {
5609
5675
  throw new Error("Home Connect devices are adopted from the gateway");
5610
5676
  }
5677
+ requireInstances() {
5678
+ if (!this.instances) throw new Error("Home Connect provider not initialised");
5679
+ return this.instances;
5680
+ }
5611
5681
  setIntegrationDevicesOnline(integrationId, online) {
5612
5682
  const reg = this.ctx.kernel.deviceRegistry;
5613
5683
  if (!reg) return;