@camstack/addon-provider-bosch 0.1.39 → 0.1.41

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,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_bosch_instances = require("../bosch-instances-WlrW2PAy.js");
3
- const require_account_integration_offline = require("../account-integration-offline-CG1-xGSm.js");
2
+ const require_bosch_instances = require("../bosch-instances-CNLo570R.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-bVxt6lq-.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");
@@ -3619,48 +3619,44 @@ var HomeConnectClientRegistry = class {
3619
3619
  };
3620
3620
  //#endregion
3621
3621
  //#region src/home-connect/home-connect-connection-test.ts
3622
- var TEST_LABEL = "Checks the Home Connect account token and lists appliances";
3623
3622
  function buildHomeConnectConnectionTestProvider(deps) {
3624
3623
  const { logger } = deps;
3625
- return {
3626
- describeTest: async () => ({ label: TEST_LABEL }),
3627
- testSettings: async ({ settings }) => {
3628
- const parsed = connectionFromSettings(typeof settings === "object" && settings !== null ? Object.fromEntries(Object.entries(settings)) : {});
3629
- if (parsed === null) return {
3624
+ return { testSettings: async ({ settings }) => {
3625
+ const parsed = connectionFromSettings(typeof settings === "object" && settings !== null ? Object.fromEntries(Object.entries(settings)) : {});
3626
+ if (parsed === null) return {
3627
+ outcome: "rejected",
3628
+ error: "Home Connect settings incomplete: sign in to read the account token."
3629
+ };
3630
+ const saved = parsed.appliances ?? [];
3631
+ if (saved.length > 0) {
3632
+ const names = saved.map((app) => app.name).join(", ");
3633
+ return {
3634
+ outcome: "validated",
3635
+ latencyMs: 0,
3636
+ detail: names.length > 0 ? names : `${String(saved.length)} appliance(s) on this account`
3637
+ };
3638
+ }
3639
+ const startedAt = Date.now();
3640
+ try {
3641
+ const account = await fetchHomeConnectAccount(parsed, deps.fetchImpl);
3642
+ return {
3643
+ outcome: "validated",
3644
+ latencyMs: Date.now() - startedAt,
3645
+ detail: account.summary
3646
+ };
3647
+ } catch (err) {
3648
+ const message = require_bosch_instances.errMsg(err);
3649
+ if (message.includes("rejected")) return {
3630
3650
  outcome: "rejected",
3631
- error: "Home Connect settings incomplete: sign in to read the account token."
3651
+ error: "Home Connect refused this account token. Sign in again."
3652
+ };
3653
+ logger.warn("Home Connect account test inconclusive", { meta: { error: message } });
3654
+ return {
3655
+ outcome: "inconclusive",
3656
+ error: "Could not reach Home Connect to read this account."
3632
3657
  };
3633
- const saved = parsed.appliances ?? [];
3634
- if (saved.length > 0) {
3635
- const names = saved.map((app) => app.name).join(", ");
3636
- return {
3637
- outcome: "validated",
3638
- latencyMs: 0,
3639
- detail: names.length > 0 ? names : `${String(saved.length)} appliance(s) on this account`
3640
- };
3641
- }
3642
- const startedAt = Date.now();
3643
- try {
3644
- const account = await fetchHomeConnectAccount(parsed, deps.fetchImpl);
3645
- return {
3646
- outcome: "validated",
3647
- latencyMs: Date.now() - startedAt,
3648
- detail: account.summary
3649
- };
3650
- } catch (err) {
3651
- const message = require_bosch_instances.errMsg(err);
3652
- if (message.includes("rejected")) return {
3653
- outcome: "rejected",
3654
- error: "Home Connect refused this account token. Sign in again."
3655
- };
3656
- logger.warn("Home Connect account test inconclusive", { meta: { error: message } });
3657
- return {
3658
- outcome: "inconclusive",
3659
- error: "Could not reach Home Connect to read this account."
3660
- };
3661
- }
3662
3658
  }
3663
- };
3659
+ } };
3664
3660
  }
3665
3661
  //#endregion
3666
3662
  //#region src/home-connect/home-connect-connection-persist.ts
@@ -5386,6 +5382,10 @@ var BoschHomeConnectProviderAddon = class extends require_bosch_instances.BaseDe
5386
5382
  const records = this.ctx.records;
5387
5383
  if (records === void 0) throw new Error("bosch-home-connect: ctx.records is required (hub-only addon)");
5388
5384
  await records.declare(homeConnectRecordKinds);
5385
+ this.declareRegistrySwitch({
5386
+ kind: homeConnectConnectionsEntryKind,
5387
+ initialBody: (name) => ({ name })
5388
+ });
5389
5389
  await this.runMigrations(HOME_CONNECT_MIGRATIONS, (api) => homeConnectRowsPorts({ ...require_bosch_instances.rowsDepsOver(api) }));
5390
5390
  const built = buildHomeConnectInstances(records, {
5391
5391
  onChanged: () => this.reconcileIntegrations(),
@@ -5414,10 +5414,6 @@ var BoschHomeConnectProviderAddon = class extends require_bosch_instances.BaseDe
5414
5414
  capability: require_bosch_instances.deviceAdoptionCapability,
5415
5415
  provider: this.buildAdoptionProvider()
5416
5416
  },
5417
- {
5418
- capability: require_bosch_instances.connectionTestCapability,
5419
- provider: this.buildConnectionTestProvider()
5420
- },
5421
5417
  {
5422
5418
  capability: require_bosch_instances.integrationInstancesCapability,
5423
5419
  provider: built.provider
@@ -5561,8 +5557,9 @@ var BoschHomeConnectProviderAddon = class extends require_bosch_instances.BaseDe
5561
5557
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
5562
5558
  this.reconcileIntegrations();
5563
5559
  };
5564
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
5565
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
5560
+ this.requireInstances().instances.onSwitched(() => {
5561
+ this.reconcileIntegrations();
5562
+ });
5566
5563
  this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
5567
5564
  }
5568
5565
  buildConnectionTestProvider() {
@@ -1,5 +1,5 @@
1
- import { $ as EventCategory, B as _enum, C as integrationInstancesCapability, D as rowsDepsOver, E as quantityFromUnit, F as defineCustomActions, G as object, H as boolean, I as defineEntryKind, J as union, K as record, L as entryBody, N as createEvent, O as runningFromDishwasherOperation, P as customAction, Q as errMsg, R as isSecretMarker, S as ingestReading, T as powerMeterCapability, U as literal, V as array, X as DeviceRole, Y as unknown, Z as DeviceType, _ as deviceAdoptionCapability, a as BaseDevice, b as eventEmitterCapability, c as RUNNING_STATE_COLD, d as VendorLoginProxy, g as consumablesCapability, h as connectionTestCapability, i as testBoschInstance, k as runningStateCapability, l as RecordIntegrationInstances, n as boschRowsPorts, o as BaseDeviceProvider, p as binaryCapability, q as string, r as keepBodyKeys, s as DishwasherOperationStateSchema, t as boschRowsMigration, v as dishwasherCapability, w as numericSensorCapability, y as enumSensorCapability, z as isSecretMarkerLike } from "../bosch-instances-GrNuqDFv.mjs";
2
- import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-etjkhGaj.mjs";
1
+ import { A as RecordIntegrationInstances, B as array, C as powerMeterCapability, E as runningStateCapability, F as entryBody, G as record, H as literal, I as isSecretMarker, J as unknown, K as string, L as isSecretMarkerLike, M as customAction, N as defineCustomActions, P as defineEntryKind, Q as EventCategory, R as rowsDepsOver, S as numericSensorCapability, T as runningFromDishwasherOperation, V as boolean, W as object, X as DeviceType, Y as DeviceRole, Z as errMsg, _ as enumSensorCapability, a as BaseDevice, b as ingestReading, c as RUNNING_STATE_COLD, f as binaryCapability, g as dishwasherCapability, h as deviceAdoptionCapability, i as testBoschInstance, j as createEvent, m as consumablesCapability, n as boschRowsPorts, o as BaseDeviceProvider, q as union, r as keepBodyKeys, s as DishwasherOperationStateSchema, t as boschRowsMigration, u as VendorLoginProxy, v as eventEmitterCapability, w as quantityFromUnit, x as integrationInstancesCapability, z as _enum } from "../bosch-instances-C1zZd1KP.mjs";
2
+ import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-B0GiHxM5.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { connect } from "node:tls";
5
5
  import { inflateRawSync } from "node:zlib";
@@ -3618,48 +3618,44 @@ var HomeConnectClientRegistry = class {
3618
3618
  };
3619
3619
  //#endregion
3620
3620
  //#region src/home-connect/home-connect-connection-test.ts
3621
- var TEST_LABEL = "Checks the Home Connect account token and lists appliances";
3622
3621
  function buildHomeConnectConnectionTestProvider(deps) {
3623
3622
  const { logger } = deps;
3624
- return {
3625
- describeTest: async () => ({ label: TEST_LABEL }),
3626
- testSettings: async ({ settings }) => {
3627
- const parsed = connectionFromSettings(typeof settings === "object" && settings !== null ? Object.fromEntries(Object.entries(settings)) : {});
3628
- if (parsed === null) return {
3623
+ return { testSettings: async ({ settings }) => {
3624
+ const parsed = connectionFromSettings(typeof settings === "object" && settings !== null ? Object.fromEntries(Object.entries(settings)) : {});
3625
+ if (parsed === null) return {
3626
+ outcome: "rejected",
3627
+ error: "Home Connect settings incomplete: sign in to read the account token."
3628
+ };
3629
+ const saved = parsed.appliances ?? [];
3630
+ if (saved.length > 0) {
3631
+ const names = saved.map((app) => app.name).join(", ");
3632
+ return {
3633
+ outcome: "validated",
3634
+ latencyMs: 0,
3635
+ detail: names.length > 0 ? names : `${String(saved.length)} appliance(s) on this account`
3636
+ };
3637
+ }
3638
+ const startedAt = Date.now();
3639
+ try {
3640
+ const account = await fetchHomeConnectAccount(parsed, deps.fetchImpl);
3641
+ return {
3642
+ outcome: "validated",
3643
+ latencyMs: Date.now() - startedAt,
3644
+ detail: account.summary
3645
+ };
3646
+ } catch (err) {
3647
+ const message = errMsg(err);
3648
+ if (message.includes("rejected")) return {
3629
3649
  outcome: "rejected",
3630
- error: "Home Connect settings incomplete: sign in to read the account token."
3650
+ error: "Home Connect refused this account token. Sign in again."
3651
+ };
3652
+ logger.warn("Home Connect account test inconclusive", { meta: { error: message } });
3653
+ return {
3654
+ outcome: "inconclusive",
3655
+ error: "Could not reach Home Connect to read this account."
3631
3656
  };
3632
- const saved = parsed.appliances ?? [];
3633
- if (saved.length > 0) {
3634
- const names = saved.map((app) => app.name).join(", ");
3635
- return {
3636
- outcome: "validated",
3637
- latencyMs: 0,
3638
- detail: names.length > 0 ? names : `${String(saved.length)} appliance(s) on this account`
3639
- };
3640
- }
3641
- const startedAt = Date.now();
3642
- try {
3643
- const account = await fetchHomeConnectAccount(parsed, deps.fetchImpl);
3644
- return {
3645
- outcome: "validated",
3646
- latencyMs: Date.now() - startedAt,
3647
- detail: account.summary
3648
- };
3649
- } catch (err) {
3650
- const message = errMsg(err);
3651
- if (message.includes("rejected")) return {
3652
- outcome: "rejected",
3653
- error: "Home Connect refused this account token. Sign in again."
3654
- };
3655
- logger.warn("Home Connect account test inconclusive", { meta: { error: message } });
3656
- return {
3657
- outcome: "inconclusive",
3658
- error: "Could not reach Home Connect to read this account."
3659
- };
3660
- }
3661
3657
  }
3662
- };
3658
+ } };
3663
3659
  }
3664
3660
  //#endregion
3665
3661
  //#region src/home-connect/home-connect-connection-persist.ts
@@ -5385,6 +5381,10 @@ var BoschHomeConnectProviderAddon = class extends BaseDeviceProvider {
5385
5381
  const records = this.ctx.records;
5386
5382
  if (records === void 0) throw new Error("bosch-home-connect: ctx.records is required (hub-only addon)");
5387
5383
  await records.declare(homeConnectRecordKinds);
5384
+ this.declareRegistrySwitch({
5385
+ kind: homeConnectConnectionsEntryKind,
5386
+ initialBody: (name) => ({ name })
5387
+ });
5388
5388
  await this.runMigrations(HOME_CONNECT_MIGRATIONS, (api) => homeConnectRowsPorts({ ...rowsDepsOver(api) }));
5389
5389
  const built = buildHomeConnectInstances(records, {
5390
5390
  onChanged: () => this.reconcileIntegrations(),
@@ -5413,10 +5413,6 @@ var BoschHomeConnectProviderAddon = class extends BaseDeviceProvider {
5413
5413
  capability: deviceAdoptionCapability,
5414
5414
  provider: this.buildAdoptionProvider()
5415
5415
  },
5416
- {
5417
- capability: connectionTestCapability,
5418
- provider: this.buildConnectionTestProvider()
5419
- },
5420
5416
  {
5421
5417
  capability: integrationInstancesCapability,
5422
5418
  provider: built.provider
@@ -5560,8 +5556,9 @@ var BoschHomeConnectProviderAddon = class extends BaseDeviceProvider {
5560
5556
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
5561
5557
  this.reconcileIntegrations();
5562
5558
  };
5563
- this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationEnabled }, handler);
5564
- this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationDisabled }, handler);
5559
+ this.requireInstances().instances.onSwitched(() => {
5560
+ this.reconcileIntegrations();
5561
+ });
5565
5562
  this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationDeleted }, handler);
5566
5563
  }
5567
5564
  buildConnectionTestProvider() {
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_bosch_instances = require("../bosch-instances-WlrW2PAy.js");
3
- const require_account_integration_offline = require("../account-integration-offline-CG1-xGSm.js");
2
+ const require_bosch_instances = require("../bosch-instances-CNLo570R.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-bVxt6lq-.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  //#region src/homecom/config.ts
6
6
  var HOMECOM_BRANDS = ["bosch", "buderus"];
@@ -1796,7 +1796,6 @@ var HomeComClientRegistry = class {
1796
1796
  };
1797
1797
  //#endregion
1798
1798
  //#region src/homecom/homecom-connection-test.ts
1799
- var TEST_LABEL = "Lists the account gateways and reads the gateway clock";
1800
1799
  var NO_GATEWAY = "This Bosch account has no HomeCom gateway.";
1801
1800
  function signInIncomplete(paths) {
1802
1801
  if (paths.includes("token") || paths.includes("refresh")) return "Sign in first. Bosch has not issued an access token yet.";
@@ -1811,56 +1810,53 @@ function listFailureMessage(err) {
1811
1810
  function buildHomeComConnectionTestProvider(deps) {
1812
1811
  const { logger } = deps;
1813
1812
  const makeClient = deps.makeClient ?? ((config, gatewayId) => createHomeComApiClient(config, gatewayId, { refreshOnUnauthorized: false }));
1814
- return {
1815
- describeTest: async () => ({ label: TEST_LABEL }),
1816
- testSettings: async ({ settings }) => {
1817
- const parsed = homeComConfigSchema.safeParse(settings);
1818
- if (!parsed.success) return {
1813
+ return { testSettings: async ({ settings }) => {
1814
+ const parsed = homeComConfigSchema.safeParse(settings);
1815
+ if (!parsed.success) return {
1816
+ outcome: "rejected",
1817
+ error: signInIncomplete(parsed.error.issues.map((issue) => issue.path.join(".") || "(root)"))
1818
+ };
1819
+ const startedAt = Date.now();
1820
+ try {
1821
+ const gateways = await makeClient(parsed.data, "").listGateways();
1822
+ const gatewayId = parsed.data.gatewayId ?? gateways[0]?.gatewayId;
1823
+ if (gatewayId === void 0) return {
1819
1824
  outcome: "rejected",
1820
- error: signInIncomplete(parsed.error.issues.map((issue) => issue.path.join(".") || "(root)"))
1825
+ error: NO_GATEWAY
1826
+ };
1827
+ if (!gateways.some((g) => g.gatewayId === gatewayId)) return {
1828
+ outcome: "rejected",
1829
+ error: `Gateway ${gatewayId} is not on this account.`
1830
+ };
1831
+ const listed = gateways.find((gateway) => gateway.gatewayId === gatewayId);
1832
+ const probe = await makeClient(parsed.data, gatewayId).probeGateway();
1833
+ const refusal = unsupportedDeviceTypeMessage(listed?.deviceType);
1834
+ if (refusal !== null) return {
1835
+ outcome: "rejected",
1836
+ error: refusal
1837
+ };
1838
+ return {
1839
+ outcome: "validated",
1840
+ latencyMs: Date.now() - startedAt,
1841
+ detail: `Gateway ${gatewayId} (${listed?.deviceType}) answered ${probe.resource}.`
1842
+ };
1843
+ } catch (err) {
1844
+ const listed = listFailureMessage(err);
1845
+ if (listed !== null) return {
1846
+ outcome: "rejected",
1847
+ error: listed
1848
+ };
1849
+ if (err instanceof HomeComAuthError) return {
1850
+ outcome: "rejected",
1851
+ error: "HomeCom refused the access token — sign in again to get a fresh one."
1852
+ };
1853
+ logger.warn("HomeCom connection test inconclusive", { meta: { error: require_bosch_instances.errMsg(err) } });
1854
+ return {
1855
+ outcome: "inconclusive",
1856
+ error: "Could not reach the HomeCom cloud API."
1821
1857
  };
1822
- const startedAt = Date.now();
1823
- try {
1824
- const gateways = await makeClient(parsed.data, "").listGateways();
1825
- const gatewayId = parsed.data.gatewayId ?? gateways[0]?.gatewayId;
1826
- if (gatewayId === void 0) return {
1827
- outcome: "rejected",
1828
- error: NO_GATEWAY
1829
- };
1830
- if (!gateways.some((g) => g.gatewayId === gatewayId)) return {
1831
- outcome: "rejected",
1832
- error: `Gateway ${gatewayId} is not on this account.`
1833
- };
1834
- const listed = gateways.find((gateway) => gateway.gatewayId === gatewayId);
1835
- const probe = await makeClient(parsed.data, gatewayId).probeGateway();
1836
- const refusal = unsupportedDeviceTypeMessage(listed?.deviceType);
1837
- if (refusal !== null) return {
1838
- outcome: "rejected",
1839
- error: refusal
1840
- };
1841
- return {
1842
- outcome: "validated",
1843
- latencyMs: Date.now() - startedAt,
1844
- detail: `Gateway ${gatewayId} (${listed?.deviceType}) answered ${probe.resource}.`
1845
- };
1846
- } catch (err) {
1847
- const listed = listFailureMessage(err);
1848
- if (listed !== null) return {
1849
- outcome: "rejected",
1850
- error: listed
1851
- };
1852
- if (err instanceof HomeComAuthError) return {
1853
- outcome: "rejected",
1854
- error: "HomeCom refused the access token — sign in again to get a fresh one."
1855
- };
1856
- logger.warn("HomeCom connection test inconclusive", { meta: { error: require_bosch_instances.errMsg(err) } });
1857
- return {
1858
- outcome: "inconclusive",
1859
- error: "Could not reach the HomeCom cloud API."
1860
- };
1861
- }
1862
1858
  }
1863
- };
1859
+ } };
1864
1860
  }
1865
1861
  //#endregion
1866
1862
  //#region src/homecom/homecom-instances.ts
@@ -2196,6 +2192,10 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
2196
2192
  const records = this.ctx.records;
2197
2193
  if (records === void 0) throw new Error("bosch-homecom: ctx.records is required (hub-only addon)");
2198
2194
  await records.declare(homeComRecordKinds);
2195
+ this.declareRegistrySwitch({
2196
+ kind: homeComConnectionsEntryKind,
2197
+ initialBody: (name) => ({ name })
2198
+ });
2199
2199
  await this.runMigrations(HOMECOM_MIGRATIONS, (api) => homeComRowsPorts({ ...require_bosch_instances.rowsDepsOver(api) }));
2200
2200
  const built = buildHomeComInstances(records, {
2201
2201
  onChanged: () => this.reconcileIntegrations(),
@@ -2229,10 +2229,6 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
2229
2229
  capability: require_bosch_instances.deviceAdoptionCapability,
2230
2230
  provider: this.buildAdoptionProvider()
2231
2231
  },
2232
- {
2233
- capability: require_bosch_instances.connectionTestCapability,
2234
- provider: this.buildConnectionTestProvider()
2235
- },
2236
2232
  {
2237
2233
  capability: require_bosch_instances.integrationInstancesCapability,
2238
2234
  provider: built.provider
@@ -2345,8 +2341,9 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
2345
2341
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
2346
2342
  this.reconcileIntegrations();
2347
2343
  };
2348
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
2349
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
2344
+ this.requireInstances().instances.onSwitched(() => {
2345
+ this.reconcileIntegrations();
2346
+ });
2350
2347
  this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
2351
2348
  }
2352
2349
  buildConnectionTestProvider() {
@@ -1,5 +1,5 @@
1
- import { $ as EventCategory, B as _enum, C as integrationInstancesCapability, D as rowsDepsOver, F as defineCustomActions, G as object, H as boolean, I as defineEntryKind, L as entryBody, M as waterHeaterCapability, P as customAction, Q as errMsg, U as literal, V as array, W as number, Z as DeviceType, _ as deviceAdoptionCapability, a as BaseDevice, d as VendorLoginProxy, h as connectionTestCapability, i as testBoschInstance, l as RecordIntegrationInstances, m as climateControlCapability, n as boschRowsPorts, o as BaseDeviceProvider, q as string, r as keepBodyKeys, t as boschRowsMigration } from "../bosch-instances-GrNuqDFv.mjs";
2
- import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-etjkhGaj.mjs";
1
+ import { A as RecordIntegrationInstances, B as array, F as entryBody, H as literal, K as string, M as customAction, N as defineCustomActions, P as defineEntryKind, Q as EventCategory, R as rowsDepsOver, U as number, V as boolean, W as object, X as DeviceType, Z as errMsg, a as BaseDevice, h as deviceAdoptionCapability, i as testBoschInstance, k as waterHeaterCapability, n as boschRowsPorts, o as BaseDeviceProvider, p as climateControlCapability, r as keepBodyKeys, t as boschRowsMigration, u as VendorLoginProxy, x as integrationInstancesCapability, z as _enum } from "../bosch-instances-C1zZd1KP.mjs";
2
+ import { a as createSignInAttemptStore, i as openSignInProxy, n as cascadeRemoveDevicesForIntegration, o as loginFailureForAttempt, r as createSignInClaims, s as parseOAuthCallback, t as setIntegrationDevicesOnline } from "../account-integration-offline-B0GiHxM5.mjs";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  //#region src/homecom/config.ts
5
5
  var HOMECOM_BRANDS = ["bosch", "buderus"];
@@ -1795,7 +1795,6 @@ var HomeComClientRegistry = class {
1795
1795
  };
1796
1796
  //#endregion
1797
1797
  //#region src/homecom/homecom-connection-test.ts
1798
- var TEST_LABEL = "Lists the account gateways and reads the gateway clock";
1799
1798
  var NO_GATEWAY = "This Bosch account has no HomeCom gateway.";
1800
1799
  function signInIncomplete(paths) {
1801
1800
  if (paths.includes("token") || paths.includes("refresh")) return "Sign in first. Bosch has not issued an access token yet.";
@@ -1810,56 +1809,53 @@ function listFailureMessage(err) {
1810
1809
  function buildHomeComConnectionTestProvider(deps) {
1811
1810
  const { logger } = deps;
1812
1811
  const makeClient = deps.makeClient ?? ((config, gatewayId) => createHomeComApiClient(config, gatewayId, { refreshOnUnauthorized: false }));
1813
- return {
1814
- describeTest: async () => ({ label: TEST_LABEL }),
1815
- testSettings: async ({ settings }) => {
1816
- const parsed = homeComConfigSchema.safeParse(settings);
1817
- if (!parsed.success) return {
1812
+ return { testSettings: async ({ settings }) => {
1813
+ const parsed = homeComConfigSchema.safeParse(settings);
1814
+ if (!parsed.success) return {
1815
+ outcome: "rejected",
1816
+ error: signInIncomplete(parsed.error.issues.map((issue) => issue.path.join(".") || "(root)"))
1817
+ };
1818
+ const startedAt = Date.now();
1819
+ try {
1820
+ const gateways = await makeClient(parsed.data, "").listGateways();
1821
+ const gatewayId = parsed.data.gatewayId ?? gateways[0]?.gatewayId;
1822
+ if (gatewayId === void 0) return {
1818
1823
  outcome: "rejected",
1819
- error: signInIncomplete(parsed.error.issues.map((issue) => issue.path.join(".") || "(root)"))
1824
+ error: NO_GATEWAY
1825
+ };
1826
+ if (!gateways.some((g) => g.gatewayId === gatewayId)) return {
1827
+ outcome: "rejected",
1828
+ error: `Gateway ${gatewayId} is not on this account.`
1829
+ };
1830
+ const listed = gateways.find((gateway) => gateway.gatewayId === gatewayId);
1831
+ const probe = await makeClient(parsed.data, gatewayId).probeGateway();
1832
+ const refusal = unsupportedDeviceTypeMessage(listed?.deviceType);
1833
+ if (refusal !== null) return {
1834
+ outcome: "rejected",
1835
+ error: refusal
1836
+ };
1837
+ return {
1838
+ outcome: "validated",
1839
+ latencyMs: Date.now() - startedAt,
1840
+ detail: `Gateway ${gatewayId} (${listed?.deviceType}) answered ${probe.resource}.`
1841
+ };
1842
+ } catch (err) {
1843
+ const listed = listFailureMessage(err);
1844
+ if (listed !== null) return {
1845
+ outcome: "rejected",
1846
+ error: listed
1847
+ };
1848
+ if (err instanceof HomeComAuthError) return {
1849
+ outcome: "rejected",
1850
+ error: "HomeCom refused the access token — sign in again to get a fresh one."
1851
+ };
1852
+ logger.warn("HomeCom connection test inconclusive", { meta: { error: errMsg(err) } });
1853
+ return {
1854
+ outcome: "inconclusive",
1855
+ error: "Could not reach the HomeCom cloud API."
1820
1856
  };
1821
- const startedAt = Date.now();
1822
- try {
1823
- const gateways = await makeClient(parsed.data, "").listGateways();
1824
- const gatewayId = parsed.data.gatewayId ?? gateways[0]?.gatewayId;
1825
- if (gatewayId === void 0) return {
1826
- outcome: "rejected",
1827
- error: NO_GATEWAY
1828
- };
1829
- if (!gateways.some((g) => g.gatewayId === gatewayId)) return {
1830
- outcome: "rejected",
1831
- error: `Gateway ${gatewayId} is not on this account.`
1832
- };
1833
- const listed = gateways.find((gateway) => gateway.gatewayId === gatewayId);
1834
- const probe = await makeClient(parsed.data, gatewayId).probeGateway();
1835
- const refusal = unsupportedDeviceTypeMessage(listed?.deviceType);
1836
- if (refusal !== null) return {
1837
- outcome: "rejected",
1838
- error: refusal
1839
- };
1840
- return {
1841
- outcome: "validated",
1842
- latencyMs: Date.now() - startedAt,
1843
- detail: `Gateway ${gatewayId} (${listed?.deviceType}) answered ${probe.resource}.`
1844
- };
1845
- } catch (err) {
1846
- const listed = listFailureMessage(err);
1847
- if (listed !== null) return {
1848
- outcome: "rejected",
1849
- error: listed
1850
- };
1851
- if (err instanceof HomeComAuthError) return {
1852
- outcome: "rejected",
1853
- error: "HomeCom refused the access token — sign in again to get a fresh one."
1854
- };
1855
- logger.warn("HomeCom connection test inconclusive", { meta: { error: errMsg(err) } });
1856
- return {
1857
- outcome: "inconclusive",
1858
- error: "Could not reach the HomeCom cloud API."
1859
- };
1860
- }
1861
1857
  }
1862
- };
1858
+ } };
1863
1859
  }
1864
1860
  //#endregion
1865
1861
  //#region src/homecom/homecom-instances.ts
@@ -2195,6 +2191,10 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
2195
2191
  const records = this.ctx.records;
2196
2192
  if (records === void 0) throw new Error("bosch-homecom: ctx.records is required (hub-only addon)");
2197
2193
  await records.declare(homeComRecordKinds);
2194
+ this.declareRegistrySwitch({
2195
+ kind: homeComConnectionsEntryKind,
2196
+ initialBody: (name) => ({ name })
2197
+ });
2198
2198
  await this.runMigrations(HOMECOM_MIGRATIONS, (api) => homeComRowsPorts({ ...rowsDepsOver(api) }));
2199
2199
  const built = buildHomeComInstances(records, {
2200
2200
  onChanged: () => this.reconcileIntegrations(),
@@ -2228,10 +2228,6 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
2228
2228
  capability: deviceAdoptionCapability,
2229
2229
  provider: this.buildAdoptionProvider()
2230
2230
  },
2231
- {
2232
- capability: connectionTestCapability,
2233
- provider: this.buildConnectionTestProvider()
2234
- },
2235
2231
  {
2236
2232
  capability: integrationInstancesCapability,
2237
2233
  provider: built.provider
@@ -2344,8 +2340,9 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
2344
2340
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
2345
2341
  this.reconcileIntegrations();
2346
2342
  };
2347
- this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationEnabled }, handler);
2348
- this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationDisabled }, handler);
2343
+ this.requireInstances().instances.onSwitched(() => {
2344
+ this.reconcileIntegrations();
2345
+ });
2349
2346
  this.ctx.eventBus.subscribe({ category: EventCategory.IntegrationDeleted }, handler);
2350
2347
  }
2351
2348
  buildConnectionTestProvider() {
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_bosch_instances = require("../bosch-instances-WlrW2PAy.js");
5
+ const require_bosch_instances = require("../bosch-instances-CNLo570R.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");
@@ -23730,34 +23730,30 @@ var ShcClientRegistry = class {
23730
23730
  //#region src/shc/shc-connection-test.ts
23731
23731
  /** REST port of a Smart Home Controller. A connect here means the address answers. */
23732
23732
  var SHC_REACHABILITY_PORT = 8444;
23733
- var TEST_LABEL = "Checks that the controller address answers on the local network";
23734
23733
  function buildShcConnectionTestProvider(deps) {
23735
23734
  const { logger, probe = probeTcp } = deps;
23736
- return {
23737
- describeTest: async () => ({ label: TEST_LABEL }),
23738
- testSettings: async ({ settings }) => {
23739
- const host = readHost(settings);
23740
- if (host === null) return {
23741
- outcome: "rejected",
23742
- error: "Enter the controller host or IP address."
23743
- };
23744
- const startedAt = Date.now();
23745
- if (!await probe(host, 8444)) {
23746
- logger.warn("Bosch SHC connection test: host unreachable", { meta: {
23747
- host,
23748
- port: SHC_REACHABILITY_PORT
23749
- } });
23750
- return {
23751
- outcome: "rejected",
23752
- error: `Could not reach ${host} on port ${SHC_REACHABILITY_PORT}.`
23753
- };
23754
- }
23735
+ return { testSettings: async ({ settings }) => {
23736
+ const host = readHost(settings);
23737
+ if (host === null) return {
23738
+ outcome: "rejected",
23739
+ error: "Enter the controller host or IP address."
23740
+ };
23741
+ const startedAt = Date.now();
23742
+ if (!await probe(host, 8444)) {
23743
+ logger.warn("Bosch SHC connection test: host unreachable", { meta: {
23744
+ host,
23745
+ port: SHC_REACHABILITY_PORT
23746
+ } });
23755
23747
  return {
23756
- outcome: "validated",
23757
- latencyMs: Date.now() - startedAt
23748
+ outcome: "rejected",
23749
+ error: `Could not reach ${host} on port ${SHC_REACHABILITY_PORT}.`
23758
23750
  };
23759
23751
  }
23760
- };
23752
+ return {
23753
+ outcome: "validated",
23754
+ latencyMs: Date.now() - startedAt
23755
+ };
23756
+ } };
23761
23757
  }
23762
23758
  function readHost(settings) {
23763
23759
  if (settings === null || typeof settings !== "object") return null;
@@ -23843,6 +23839,10 @@ var BoschShcProviderAddon = class extends require_bosch_instances.BaseDeviceProv
23843
23839
  const records = this.ctx.records;
23844
23840
  if (records === void 0) throw new Error("bosch-shc: ctx.records is required (hub-only addon)");
23845
23841
  await records.declare(shcRecordKinds);
23842
+ this.declareRegistrySwitch({
23843
+ kind: shcConnectionsEntryKind,
23844
+ initialBody: (name) => ({ name })
23845
+ });
23846
23846
  await this.runMigrations(SHC_MIGRATIONS, (api) => shcRowsPorts({ ...require_bosch_instances.rowsDepsOver(api) }));
23847
23847
  const built = buildShcInstances(records, {
23848
23848
  onChanged: () => this.reconcileIntegrations(),
@@ -23865,10 +23865,6 @@ var BoschShcProviderAddon = class extends require_bosch_instances.BaseDeviceProv
23865
23865
  capability: require_bosch_instances.deviceAdoptionCapability,
23866
23866
  provider: this.buildAdoptionProvider()
23867
23867
  },
23868
- {
23869
- capability: require_bosch_instances.connectionTestCapability,
23870
- provider: this.buildConnectionTestProvider()
23871
- },
23872
23868
  {
23873
23869
  capability: require_bosch_instances.integrationInstancesCapability,
23874
23870
  provider: built.provider
@@ -24010,8 +24006,9 @@ var BoschShcProviderAddon = class extends require_bosch_instances.BaseDeviceProv
24010
24006
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
24011
24007
  this.reconcileIntegrations();
24012
24008
  };
24013
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
24014
- this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
24009
+ this.requireInstances().onSwitched(() => {
24010
+ this.reconcileIntegrations();
24011
+ });
24015
24012
  this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
24016
24013
  }
24017
24014
  async cascadeRemoveDevicesForIntegration(integrationId) {