@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,28 +1,28 @@
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
  //#region src/homecom/config.ts
6
6
  var HOMECOM_BRANDS = ["bosch", "buderus"];
7
- var HomeComBrandSchema = require_dist._enum(HOMECOM_BRANDS);
7
+ var HomeComBrandSchema = require_bosch_instances._enum(HOMECOM_BRANDS);
8
8
  var HOMECOM_REGIONS = ["eu", "us"];
9
- var HomeComRegionSchema = require_dist._enum(HOMECOM_REGIONS);
10
- var homeComConfigSchema = require_dist.object({
9
+ var HomeComRegionSchema = require_bosch_instances._enum(HOMECOM_REGIONS);
10
+ var homeComConfigSchema = require_bosch_instances.object({
11
11
  /** Account email; filled by the sign-in, informational only. */
12
- username: require_dist.string().optional().describe("HomeCom / PointT account email").meta({ secret: true }),
13
- token: require_dist.string().min(1).describe("OAuth access token").meta({ secret: true }),
14
- refresh: require_dist.string().min(1).describe("OAuth refresh token").meta({ secret: true }),
12
+ username: require_bosch_instances.string().optional().describe("HomeCom / PointT account email").meta({ secret: true }),
13
+ token: require_bosch_instances.string().min(1).describe("OAuth access token").meta({ secret: true }),
14
+ refresh: require_bosch_instances.string().min(1).describe("OAuth refresh token").meta({ secret: true }),
15
15
  brand: HomeComBrandSchema.default("bosch"),
16
16
  region: HomeComRegionSchema.default("eu"),
17
17
  /**
18
18
  * The gateway this integration controls. Chosen from the account list after
19
19
  * sign-in. A blank value is the same as absent: the id is not known yet.
20
20
  */
21
- gatewayId: require_dist.string().trim().optional().transform((value) => value === void 0 || value.length === 0 ? void 0 : value),
21
+ gatewayId: require_bosch_instances.string().trim().optional().transform((value) => value === void 0 || value.length === 0 ? void 0 : value),
22
22
  /** Shown on the sign-in field. Not a credential. */
23
- accountLabel: require_dist.string().optional(),
23
+ accountLabel: require_bosch_instances.string().optional(),
24
24
  /** How many gateways the last sign-in listed. */
25
- gatewayCount: require_dist.number().optional()
25
+ gatewayCount: require_bosch_instances.number().optional()
26
26
  });
27
27
  function connectionFromSettings(settings) {
28
28
  const parsed = homeComConfigSchema.safeParse(settings);
@@ -42,11 +42,6 @@ var HOMECOM_GATEWAYS_PATH = "/pointt-api/api/v1/gateways/";
42
42
  function homeComApiBase(_region) {
43
43
  return HOMECOM_POINTT_API_ORIGIN;
44
44
  }
45
- var HOMECOM_SECRET_KEYS = [
46
- "username",
47
- "token",
48
- "refresh"
49
- ];
50
45
  var HIDDEN_UNTIL_ADVANCED = {
51
46
  field: "__hidden__",
52
47
  equals: "yes"
@@ -187,35 +182,35 @@ function buildHomeComFormSchema() {
187
182
  }
188
183
  //#endregion
189
184
  //#region src/homecom/custom-actions.ts
190
- var gatewayChoice = require_dist.object({
191
- value: require_dist.string(),
192
- label: require_dist.string(),
185
+ var gatewayChoice = require_bosch_instances.object({
186
+ value: require_bosch_instances.string(),
187
+ label: require_bosch_instances.string(),
193
188
  brand: HomeComBrandSchema,
194
189
  region: HomeComRegionSchema
195
190
  });
196
- var homeComActions = require_dist.defineCustomActions({
197
- beginSignIn: require_dist.customAction(require_dist.object({}), require_dist.object({
198
- attemptId: require_dist.string().min(1),
199
- authorizeUrl: require_dist.string().min(1),
200
- summary: require_dist.string()
191
+ var homeComActions = require_bosch_instances.defineCustomActions({
192
+ beginSignIn: require_bosch_instances.customAction(require_bosch_instances.object({}), require_bosch_instances.object({
193
+ attemptId: require_bosch_instances.string().min(1),
194
+ authorizeUrl: require_bosch_instances.string().min(1),
195
+ summary: require_bosch_instances.string()
201
196
  }), {
202
197
  kind: "mutation",
203
198
  auth: "admin"
204
199
  }),
205
- finishSignIn: require_dist.customAction(require_dist.object({
206
- attemptId: require_dist.string().min(1),
207
- callback: require_dist.string().min(1)
208
- }), require_dist.object({
209
- token: require_dist.string().min(1).meta({ secret: true }),
210
- refresh: require_dist.string().min(1).meta({ secret: true }),
211
- username: require_dist.string().meta({ secret: true }),
212
- accountLabel: require_dist.string(),
213
- gatewayCount: require_dist.number(),
214
- summary: require_dist.string(),
215
- gatewayId: require_dist.string().optional(),
200
+ finishSignIn: require_bosch_instances.customAction(require_bosch_instances.object({
201
+ attemptId: require_bosch_instances.string().min(1),
202
+ callback: require_bosch_instances.string().min(1)
203
+ }), require_bosch_instances.object({
204
+ token: require_bosch_instances.string().min(1).meta({ secret: true }),
205
+ refresh: require_bosch_instances.string().min(1).meta({ secret: true }),
206
+ username: require_bosch_instances.string().meta({ secret: true }),
207
+ accountLabel: require_bosch_instances.string(),
208
+ gatewayCount: require_bosch_instances.number(),
209
+ summary: require_bosch_instances.string(),
210
+ gatewayId: require_bosch_instances.string().optional(),
216
211
  brand: HomeComBrandSchema.optional(),
217
212
  region: HomeComRegionSchema.optional(),
218
- choices: require_dist.array(gatewayChoice).optional()
213
+ choices: require_bosch_instances.array(gatewayChoice).optional()
219
214
  }), {
220
215
  kind: "mutation",
221
216
  auth: "admin"
@@ -225,25 +220,25 @@ var homeComActions = require_dist.defineCustomActions({
225
220
  * app-scheme redirect and finished the exchange, then the same fields `finishSignIn` returns.
226
221
  * Claimed once. A failed exchange answers with its operator-facing message as an error.
227
222
  */
228
- claimSignIn: require_dist.customAction(require_dist.object({ attemptId: require_dist.string().min(1) }), require_dist.object({
229
- pending: require_dist.boolean(),
230
- token: require_dist.string().optional().meta({ secret: true }),
231
- refresh: require_dist.string().optional().meta({ secret: true }),
232
- username: require_dist.string().optional().meta({ secret: true }),
233
- accountLabel: require_dist.string().optional(),
234
- gatewayCount: require_dist.number().optional(),
235
- summary: require_dist.string().optional(),
236
- gatewayId: require_dist.string().optional(),
223
+ claimSignIn: require_bosch_instances.customAction(require_bosch_instances.object({ attemptId: require_bosch_instances.string().min(1) }), require_bosch_instances.object({
224
+ pending: require_bosch_instances.boolean(),
225
+ token: require_bosch_instances.string().optional().meta({ secret: true }),
226
+ refresh: require_bosch_instances.string().optional().meta({ secret: true }),
227
+ username: require_bosch_instances.string().optional().meta({ secret: true }),
228
+ accountLabel: require_bosch_instances.string().optional(),
229
+ gatewayCount: require_bosch_instances.number().optional(),
230
+ summary: require_bosch_instances.string().optional(),
231
+ gatewayId: require_bosch_instances.string().optional(),
237
232
  brand: HomeComBrandSchema.optional(),
238
233
  region: HomeComRegionSchema.optional(),
239
- choices: require_dist.array(gatewayChoice).optional()
234
+ choices: require_bosch_instances.array(gatewayChoice).optional()
240
235
  }), {
241
236
  kind: "mutation",
242
237
  auth: "admin"
243
238
  }),
244
- signOut: require_dist.customAction(require_dist.object({}), require_dist.object({
245
- signedOut: require_dist.literal(true),
246
- summary: require_dist.string()
239
+ signOut: require_bosch_instances.customAction(require_bosch_instances.object({}), require_bosch_instances.object({
240
+ signedOut: require_bosch_instances.literal(true),
241
+ summary: require_bosch_instances.string()
247
242
  }), {
248
243
  kind: "mutation",
249
244
  auth: "admin"
@@ -1263,41 +1258,27 @@ function beginHomeComProxiedSignIn(deps) {
1263
1258
  }
1264
1259
  //#endregion
1265
1260
  //#region src/homecom/homecom-token-persist.ts
1266
- function unreadable(value) {
1267
- return require_dist.isSecretMarker(value) || require_dist.isSecretMarkerLike(value);
1268
- }
1269
1261
  /**
1270
- * Merge `patch` into the integration's stored settings in ONE `setSettings` write, one at a
1271
- * time per integration. Refuses (and says so, without values) when a secret the write
1272
- * touches cannot be read back from the keychain: the hub refuses an overwrite of a secret the
1273
- * addon could not read, so the write would only fail.
1262
+ * Patch the integration's record, one write at a time per integration. Refuses (and says so,
1263
+ * without values) when the record's secrets cannot be read right now: the write would replace a
1264
+ * secret the addon cannot see.
1274
1265
  */
1275
1266
  function buildSerialPatcher(deps) {
1276
1267
  const tails = /* @__PURE__ */ new Map();
1277
1268
  return (integrationId, patch) => {
1278
1269
  const run = async () => {
1279
1270
  try {
1280
- const stored = await deps.getSettings(integrationId);
1281
- const locked = HOMECOM_SECRET_KEYS.filter((key) => unreadable(stored[key]));
1282
- if (locked.length > 0) {
1283
- deps.logger.warn(`HomeCom not persisting ${deps.what} — stored secrets are locked`, {
1284
- tags: { integrationId },
1285
- meta: { locked }
1286
- });
1271
+ const stored = await deps.read(integrationId);
1272
+ if (stored === null) return;
1273
+ if (stored.locked) {
1274
+ deps.logger.warn(`HomeCom not persisting ${deps.what} — stored secrets are locked`, { tags: { integrationId } });
1287
1275
  return;
1288
1276
  }
1289
- await deps.setSettings({
1290
- id: integrationId,
1291
- settings: {
1292
- ...stored,
1293
- ...patch
1294
- },
1295
- secretKeys: [...HOMECOM_SECRET_KEYS]
1296
- });
1277
+ await deps.patch(integrationId, patch);
1297
1278
  } catch (err) {
1298
1279
  deps.logger.warn(`HomeCom failed to persist ${deps.what}`, {
1299
1280
  tags: { integrationId },
1300
- meta: { error: require_dist.errMsg(err) }
1281
+ meta: { error: require_bosch_instances.errMsg(err) }
1301
1282
  });
1302
1283
  }
1303
1284
  };
@@ -1330,7 +1311,7 @@ function buildHomeComGatewayPersister(deps) {
1330
1311
  function buildHomeComCandidates(input) {
1331
1312
  const out = [];
1332
1313
  for (const dev of input.devices) {
1333
- const type = dev.kind === "heating-circuit" ? require_dist.DeviceType.Climate : require_dist.DeviceType.WaterHeater;
1314
+ const type = dev.kind === "heating-circuit" ? require_bosch_instances.DeviceType.Climate : require_bosch_instances.DeviceType.WaterHeater;
1334
1315
  const caps = dev.kind === "heating-circuit" ? ["climate-control"] : ["water-heater"];
1335
1316
  const adoptedId = input.adopted.get(dev.nativeId) ?? null;
1336
1317
  out.push({
@@ -1401,7 +1382,7 @@ function buildHomeComAdoptionProvider(deps) {
1401
1382
  lastDiscoveryAt: null,
1402
1383
  candidateCount: 0,
1403
1384
  adoptedCount: 0,
1404
- lastError: require_dist.errMsg(err)
1385
+ lastError: require_bosch_instances.errMsg(err)
1405
1386
  };
1406
1387
  }
1407
1388
  },
@@ -1451,7 +1432,7 @@ function buildHomeComAdoptionProvider(deps) {
1451
1432
  logger.warn("homecom adopt failed", { meta: {
1452
1433
  nativeId,
1453
1434
  integrationId,
1454
- error: require_dist.errMsg(err)
1435
+ error: require_bosch_instances.errMsg(err)
1455
1436
  } });
1456
1437
  failures++;
1457
1438
  }
@@ -1574,7 +1555,7 @@ var HomeComIntegrationManager = class {
1574
1555
  } catch (err) {
1575
1556
  this.#logger.warn("HomeCom could not store the rotated tokens", {
1576
1557
  tags: { integrationId: this.#id },
1577
- meta: { error: require_dist.errMsg(err) }
1558
+ meta: { error: require_bosch_instances.errMsg(err) }
1578
1559
  });
1579
1560
  }
1580
1561
  };
@@ -1630,7 +1611,7 @@ var HomeComIntegrationManager = class {
1630
1611
  }, this.#pollIntervalMs);
1631
1612
  } catch (err) {
1632
1613
  this.#status = "error";
1633
- this.#error = err instanceof HomeComAuthError ? "authentication failed — sign in again" : require_dist.errMsg(err);
1614
+ this.#error = err instanceof HomeComAuthError ? "authentication failed — sign in again" : require_bosch_instances.errMsg(err);
1634
1615
  this.#client = null;
1635
1616
  this.#surfaceSink.set(this.#id, null);
1636
1617
  this.#onDisconnected(this.#id);
@@ -1664,7 +1645,7 @@ var HomeComIntegrationManager = class {
1664
1645
  } catch (err) {
1665
1646
  this.#logger.warn("HomeCom poll failed", { meta: {
1666
1647
  integrationId: this.#id,
1667
- error: require_dist.errMsg(err)
1648
+ error: require_bosch_instances.errMsg(err)
1668
1649
  } });
1669
1650
  }
1670
1651
  }
@@ -1739,7 +1720,7 @@ var HomeComClientRegistry = class {
1739
1720
  } catch (err) {
1740
1721
  this.#logger.warn("HomeComClientRegistry: applyConnection failed", { meta: {
1741
1722
  integrationId,
1742
- error: require_dist.errMsg(err)
1723
+ error: require_bosch_instances.errMsg(err)
1743
1724
  } });
1744
1725
  }
1745
1726
  return;
@@ -1763,7 +1744,7 @@ var HomeComClientRegistry = class {
1763
1744
  } catch (err) {
1764
1745
  this.#logger.warn("HomeComClientRegistry: manager start failed", { meta: {
1765
1746
  integrationId,
1766
- error: require_dist.errMsg(err)
1747
+ error: require_bosch_instances.errMsg(err)
1767
1748
  } });
1768
1749
  }
1769
1750
  }
@@ -1776,7 +1757,7 @@ var HomeComClientRegistry = class {
1776
1757
  } catch (err) {
1777
1758
  this.#logger.warn("HomeComClientRegistry: remove stop failed", { meta: {
1778
1759
  integrationId,
1779
- error: require_dist.errMsg(err)
1760
+ error: require_bosch_instances.errMsg(err)
1780
1761
  } });
1781
1762
  }
1782
1763
  }
@@ -1789,7 +1770,7 @@ var HomeComClientRegistry = class {
1789
1770
  } catch (err) {
1790
1771
  this.#logger.warn("HomeComClientRegistry: shutdown stop failed", { meta: {
1791
1772
  integrationId: id,
1792
- error: require_dist.errMsg(err)
1773
+ error: require_bosch_instances.errMsg(err)
1793
1774
  } });
1794
1775
  }
1795
1776
  this.#entries.clear();
@@ -1867,7 +1848,7 @@ function buildHomeComConnectionTestProvider(deps) {
1867
1848
  outcome: "rejected",
1868
1849
  error: "HomeCom refused the access token — sign in again to get a fresh one."
1869
1850
  };
1870
- logger.warn("HomeCom connection test inconclusive", { meta: { error: require_dist.errMsg(err) } });
1851
+ logger.warn("HomeCom connection test inconclusive", { meta: { error: require_bosch_instances.errMsg(err) } });
1871
1852
  return {
1872
1853
  outcome: "inconclusive",
1873
1854
  error: "Could not reach the HomeCom cloud API."
@@ -1877,13 +1858,141 @@ function buildHomeComConnectionTestProvider(deps) {
1877
1858
  };
1878
1859
  }
1879
1860
  //#endregion
1861
+ //#region src/homecom/homecom-instances.ts
1862
+ /**
1863
+ * HomeCom integrations as `integration-instances` (planning#416, D985, D1007): one `connections`
1864
+ * record per account under the `integrations` registry id. The body IS the account (the account
1865
+ * email and the OAuth tokens in the keychain; brand, region, the chosen gateway and the
1866
+ * signed-in label in the open), so the form the instances page edits is the stored shape.
1867
+ */
1868
+ var homeComConnectionsEntryKind = require_bosch_instances.defineEntryKind("connections", {
1869
+ title: "HomeCom accounts",
1870
+ schema: require_bosch_instances.entryBody({
1871
+ username: require_bosch_instances.string().optional().meta({ secret: true }),
1872
+ token: require_bosch_instances.string().optional().meta({ secret: true }),
1873
+ refresh: require_bosch_instances.string().optional().meta({ secret: true }),
1874
+ brand: HomeComBrandSchema.optional(),
1875
+ region: HomeComRegionSchema.optional(),
1876
+ gatewayId: require_bosch_instances.string().optional(),
1877
+ accountLabel: require_bosch_instances.string().optional(),
1878
+ gatewayCount: require_bosch_instances.number().optional()
1879
+ }),
1880
+ writeTrigger: "an operator signs in, edits or removes a HomeCom account, or a connection stores a rotated token or its gateway"
1881
+ });
1882
+ /** Every kind this addon declares, keyed by its name. */
1883
+ var homeComRecordKinds = { connections: homeComConnectionsEntryKind };
1884
+ var LEGACY_KEYS = [
1885
+ "username",
1886
+ "token",
1887
+ "refresh",
1888
+ "brand",
1889
+ "region",
1890
+ "gatewayId",
1891
+ "accountLabel",
1892
+ "gatewayCount"
1893
+ ];
1894
+ var SECRET_KEYS = [
1895
+ "username",
1896
+ "token",
1897
+ "refresh"
1898
+ ];
1899
+ function text(value) {
1900
+ return typeof value === "string" && value.length > 0 ? value : void 0;
1901
+ }
1902
+ /** The record body of one account, from its legacy rows (secrets resolved). */
1903
+ function homeComBodyFromRows(values, log, integration) {
1904
+ const dropped = Object.keys(values).filter((key) => !LEGACY_KEYS.includes(key));
1905
+ if (dropped.length > 0) log.warn(`integration '${integration.id}': legacy settings nothing reads any more are dropped: ${dropped.join(", ")}`);
1906
+ const username = text(values["username"]);
1907
+ const token = text(values["token"]);
1908
+ const refresh = text(values["refresh"]);
1909
+ const brand = HomeComBrandSchema.safeParse(values["brand"]);
1910
+ const region = HomeComRegionSchema.safeParse(values["region"]);
1911
+ const gatewayId = text(values["gatewayId"])?.trim();
1912
+ const accountLabel = text(values["accountLabel"]);
1913
+ const count = values["gatewayCount"];
1914
+ return {
1915
+ name: integration.name,
1916
+ ...username !== void 0 ? { username } : {},
1917
+ ...token !== void 0 ? { token } : {},
1918
+ ...refresh !== void 0 ? { refresh } : {},
1919
+ ...brand.success ? { brand: brand.data } : {},
1920
+ ...region.success ? { region: region.data } : {},
1921
+ ...gatewayId !== void 0 && gatewayId.length > 0 ? { gatewayId } : {},
1922
+ ...accountLabel !== void 0 ? { accountLabel } : {},
1923
+ ...typeof count === "number" && Number.isFinite(count) ? { gatewayCount: count } : {}
1924
+ };
1925
+ }
1926
+ /** The whole `bosch-homecom` catalogue (D987): offered to the engine at `onInitialize`. */
1927
+ var HOMECOM_MIGRATIONS = [require_bosch_instances.boschRowsMigration({
1928
+ addonId: "bosch-homecom",
1929
+ id: "bosch-homecom/2026-11-05-integration-rows-to-record",
1930
+ description: "Move every HomeCom account into a typed instance record keyed by its registry id, then clear the legacy integration settings rows and their keychain values",
1931
+ fixtureMark: "a legacy setting key the migration does not know",
1932
+ kind: homeComConnectionsEntryKind,
1933
+ bodyFrom: homeComBodyFromRows
1934
+ })];
1935
+ function homeComRowsPorts(deps) {
1936
+ return require_bosch_instances.boschRowsPorts({
1937
+ ...deps,
1938
+ kind: homeComConnectionsEntryKind
1939
+ });
1940
+ }
1941
+ async function homeComStoredOf(instances, id) {
1942
+ const read = await instances.readResolved(id);
1943
+ if (read === null) return null;
1944
+ return {
1945
+ settings: { ...read.body },
1946
+ locked: read.secrets === "unavailable"
1947
+ };
1948
+ }
1949
+ /**
1950
+ * The live account of one integration, read from its record. null while it is not signed in; a
1951
+ * locked keychain throws so the caller keeps the client it has instead of reconfiguring it
1952
+ * without its tokens (D49).
1953
+ */
1954
+ async function homeComConnectionOf(instances, id) {
1955
+ const stored = await homeComStoredOf(instances, id);
1956
+ if (stored === null) return null;
1957
+ if (stored.locked) throw new Error("the keychain is locked, the saved HomeCom tokens cannot be read");
1958
+ return connectionFromSettings(stored.settings);
1959
+ }
1960
+ function buildHomeComInstances(records, deps) {
1961
+ const handle = records.kind(homeComConnectionsEntryKind);
1962
+ const instances = new require_bosch_instances.RecordIntegrationInstances(records, homeComConnectionsEntryKind, {
1963
+ description: {
1964
+ role: "devices",
1965
+ instanceMode: "multiple",
1966
+ kind: "account",
1967
+ canTest: true
1968
+ },
1969
+ formSchema: () => buildHomeComFormSchema(),
1970
+ initialBody: (name) => ({ name }),
1971
+ configured: (body) => connectionFromSettings(body) !== null,
1972
+ onChanged: async (_id, change) => {
1973
+ if (change !== "deleted") await deps.onChanged();
1974
+ },
1975
+ test: (input) => require_bosch_instances.testBoschInstance({
1976
+ ...input,
1977
+ tester: deps.tester,
1978
+ handle,
1979
+ secretKeys: SECRET_KEYS
1980
+ })
1981
+ });
1982
+ return {
1983
+ instances,
1984
+ handle,
1985
+ provider: require_bosch_instances.keepBodyKeys(instances.toProvider(), new Set(Object.keys(homeComConnectionsEntryKind.schema.shape)))
1986
+ };
1987
+ }
1988
+ //#endregion
1880
1989
  //#region src/homecom/devices/homecom-climate-device.ts
1881
- var homeComClimateSchema = require_dist.object({
1882
- nativeId: require_dist.string().min(1),
1883
- brokerId: require_dist.string().min(1),
1884
- circuitId: require_dist.string().min(1),
1885
- system: require_dist.literal("homecom").optional(),
1886
- integrationId: require_dist.string().optional()
1990
+ var homeComClimateSchema = require_bosch_instances.object({
1991
+ nativeId: require_bosch_instances.string().min(1),
1992
+ brokerId: require_bosch_instances.string().min(1),
1993
+ circuitId: require_bosch_instances.string().min(1),
1994
+ system: require_bosch_instances.literal("homecom").optional(),
1995
+ integrationId: require_bosch_instances.string().optional()
1887
1996
  });
1888
1997
  var CLIMATE_CAP = "climate-control";
1889
1998
  var COLD_START$1 = {
@@ -1903,7 +2012,7 @@ var COLD_START$1 = {
1903
2012
  swingHorizontal: null,
1904
2013
  lastFetchedAt: 0
1905
2014
  };
1906
- var HomeComClimateDevice = class extends require_dist.BaseDevice {
2015
+ var HomeComClimateDevice = class extends require_bosch_instances.BaseDevice {
1907
2016
  features = [];
1908
2017
  #brokerId;
1909
2018
  #circuitId;
@@ -1941,7 +2050,7 @@ var HomeComClimateDevice = class extends require_dist.BaseDevice {
1941
2050
  return client;
1942
2051
  }
1943
2052
  registerClimateCap() {
1944
- this.ctx.registerNativeCap(require_dist.climateControlCapability, {
2053
+ this.ctx.registerNativeCap(require_bosch_instances.climateControlCapability, {
1945
2054
  getStatus: async () => {
1946
2055
  this.refreshFromSnapshot();
1947
2056
  return this.runtimeState.getCapState(CLIMATE_CAP) ?? COLD_START$1;
@@ -1989,11 +2098,11 @@ function hvacModeToHomeCom(mode) {
1989
2098
  }
1990
2099
  //#endregion
1991
2100
  //#region src/homecom/devices/homecom-water-heater-device.ts
1992
- var homeComWaterHeaterSchema = require_dist.object({
1993
- nativeId: require_dist.string().min(1),
1994
- brokerId: require_dist.string().min(1),
1995
- system: require_dist.literal("homecom").optional(),
1996
- integrationId: require_dist.string().optional()
2101
+ var homeComWaterHeaterSchema = require_bosch_instances.object({
2102
+ nativeId: require_bosch_instances.string().min(1),
2103
+ brokerId: require_bosch_instances.string().min(1),
2104
+ system: require_bosch_instances.literal("homecom").optional(),
2105
+ integrationId: require_bosch_instances.string().optional()
1997
2106
  });
1998
2107
  var WH_CAP = "water-heater";
1999
2108
  var COLD_START = {
@@ -2006,7 +2115,7 @@ var COLD_START = {
2006
2115
  maxTemp: null,
2007
2116
  lastChangedAt: 0
2008
2117
  };
2009
- var HomeComWaterHeaterDevice = class extends require_dist.BaseDevice {
2118
+ var HomeComWaterHeaterDevice = class extends require_bosch_instances.BaseDevice {
2010
2119
  features = [];
2011
2120
  #brokerId;
2012
2121
  constructor(ctx) {
@@ -2042,7 +2151,7 @@ var HomeComWaterHeaterDevice = class extends require_dist.BaseDevice {
2042
2151
  return client;
2043
2152
  }
2044
2153
  registerWaterHeaterCap() {
2045
- this.ctx.registerNativeCap(require_dist.waterHeaterCapability, {
2154
+ this.ctx.registerNativeCap(require_bosch_instances.waterHeaterCapability, {
2046
2155
  getStatus: async () => {
2047
2156
  this.refreshFromSnapshot();
2048
2157
  return this.runtimeState.getCapState(WH_CAP) ?? COLD_START;
@@ -2063,14 +2172,15 @@ var HomeComWaterHeaterDevice = class extends require_dist.BaseDevice {
2063
2172
  };
2064
2173
  //#endregion
2065
2174
  //#region src/homecom/addon.ts
2066
- var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2175
+ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDeviceProvider {
2067
2176
  addonId = "bosch-homecom";
2068
2177
  providerName = "Bosch HomeCom";
2069
2178
  deviceClasses = {
2070
- [require_dist.DeviceType.Climate]: HomeComClimateDevice,
2071
- [require_dist.DeviceType.WaterHeater]: HomeComWaterHeaterDevice
2179
+ [require_bosch_instances.DeviceType.Climate]: HomeComClimateDevice,
2180
+ [require_bosch_instances.DeviceType.WaterHeater]: HomeComWaterHeaterDevice
2072
2181
  };
2073
2182
  clients = null;
2183
+ instances = null;
2074
2184
  loginProxy = null;
2075
2185
  loginPlane = null;
2076
2186
  constructor() {
@@ -2078,10 +2188,23 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2078
2188
  }
2079
2189
  async onInitialize() {
2080
2190
  const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
2191
+ const records = this.ctx.records;
2192
+ if (records === void 0) throw new Error("bosch-homecom: ctx.records is required (hub-only addon)");
2193
+ await records.declare(homeComRecordKinds);
2194
+ await this.runMigrations(require_bosch_instances.defineAddonMigrations(HOMECOM_MIGRATIONS, homeComRowsPorts({
2195
+ api: require_bosch_instances.defaultIntegrationApiOver(this.ctx.api),
2196
+ records,
2197
+ warn: (message) => this.ctx.logger.warn(message)
2198
+ })));
2199
+ const built = buildHomeComInstances(records, {
2200
+ onChanged: () => this.reconcileIntegrations(),
2201
+ tester: this.buildConnectionTestProvider()
2202
+ });
2203
+ this.instances = built;
2081
2204
  await this.serveLoginProxy();
2082
2205
  const persistDeps = {
2083
- getSettings: (id) => this.ctx.api.integrations.getSettings.query({ id }),
2084
- setSettings: (input) => this.ctx.api.integrations.setSettings.mutate(input),
2206
+ read: (id) => homeComStoredOf(built.instances, id),
2207
+ patch: (id, patch) => built.handle.patch(id, patch),
2085
2208
  logger: this.ctx.logger
2086
2209
  };
2087
2210
  const persistTokens = buildHomeComTokenPersister(persistDeps);
@@ -2102,12 +2225,16 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2102
2225
  providers: [
2103
2226
  ...regs,
2104
2227
  {
2105
- capability: require_dist.deviceAdoptionCapability,
2228
+ capability: require_bosch_instances.deviceAdoptionCapability,
2106
2229
  provider: this.buildAdoptionProvider()
2107
2230
  },
2108
2231
  {
2109
- capability: require_dist.connectionTestCapability,
2232
+ capability: require_bosch_instances.connectionTestCapability,
2110
2233
  provider: this.buildConnectionTestProvider()
2234
+ },
2235
+ {
2236
+ capability: require_bosch_instances.integrationInstancesCapability,
2237
+ provider: built.provider
2111
2238
  }
2112
2239
  ],
2113
2240
  customActions: homeComActions,
@@ -2140,7 +2267,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2140
2267
  }
2141
2268
  /** The hub's HTTPS face for the vendor's login pages (D955): admin session only. */
2142
2269
  async serveLoginProxy() {
2143
- const proxy = new require_dist.VendorLoginProxy({
2270
+ const proxy = new require_bosch_instances.VendorLoginProxy({
2144
2271
  addonId: this.ctx.id,
2145
2272
  logger: this.ctx.logger
2146
2273
  });
@@ -2152,7 +2279,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2152
2279
  }) ?? null;
2153
2280
  if (this.loginPlane !== null) this.loginProxy = proxy;
2154
2281
  } catch (err) {
2155
- this.ctx.logger.warn("HomeCom login proxy failed to serve — sign-in falls back to paste", { meta: { error: require_dist.errMsg(err) } });
2282
+ this.ctx.logger.warn("HomeCom login proxy failed to serve — sign-in falls back to paste", { meta: { error: require_bosch_instances.errMsg(err) } });
2156
2283
  }
2157
2284
  }
2158
2285
  async onShutdown() {
@@ -2162,9 +2289,10 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2162
2289
  try {
2163
2290
  await this.clients?.shutdown();
2164
2291
  } catch (err) {
2165
- this.ctx.logger.warn("HomeCom shutdown error", { meta: { error: require_dist.errMsg(err) } });
2292
+ this.ctx.logger.warn("HomeCom shutdown error", { meta: { error: require_bosch_instances.errMsg(err) } });
2166
2293
  }
2167
2294
  this.clients = null;
2295
+ this.instances = null;
2168
2296
  await super.onShutdown();
2169
2297
  }
2170
2298
  requireClients() {
@@ -2184,14 +2312,14 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2184
2312
  const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id && i.enabled);
2185
2313
  const surviving = /* @__PURE__ */ new Set();
2186
2314
  for (const integration of mine) try {
2187
- const connection = connectionFromSettings(await this.ctx.api.integrations.getSettings.query({ id: integration.id }));
2315
+ const connection = await homeComConnectionOf(this.requireInstances().instances, integration.id);
2188
2316
  if (!connection) continue;
2189
2317
  await reg.upsert(integration.id, integration.name, connection);
2190
2318
  surviving.add(integration.id);
2191
2319
  } catch (err) {
2192
2320
  this.ctx.logger.warn("HomeCom reconcile failed for integration", { meta: {
2193
2321
  integrationId: integration.id,
2194
- error: require_dist.errMsg(err)
2322
+ error: require_bosch_instances.errMsg(err)
2195
2323
  } });
2196
2324
  }
2197
2325
  const vanished = reg.list().filter((id) => !surviving.has(id));
@@ -2207,7 +2335,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2207
2335
  logger: this.ctx.logger
2208
2336
  });
2209
2337
  } catch (err) {
2210
- this.ctx.logger.warn("HomeCom integration reconcile failed", { meta: { error: require_dist.errMsg(err) } });
2338
+ this.ctx.logger.warn("HomeCom integration reconcile failed", { meta: { error: require_bosch_instances.errMsg(err) } });
2211
2339
  }
2212
2340
  }
2213
2341
  subscribeIntegrationLifecycle() {
@@ -2216,9 +2344,9 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2216
2344
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
2217
2345
  this.reconcileIntegrations();
2218
2346
  };
2219
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationEnabled }, handler);
2220
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDisabled }, handler);
2221
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDeleted }, handler);
2347
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
2348
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
2349
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
2222
2350
  }
2223
2351
  buildConnectionTestProvider() {
2224
2352
  return buildHomeComConnectionTestProvider({ logger: this.ctx.logger });
@@ -2273,9 +2401,6 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2273
2401
  logger: this.ctx.logger
2274
2402
  });
2275
2403
  }
2276
- globalSettingsSchema() {
2277
- return buildHomeComFormSchema();
2278
- }
2279
2404
  async supportsManualCreation() {
2280
2405
  return false;
2281
2406
  }
@@ -2285,6 +2410,10 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
2285
2410
  async onCreateDevice(_type, _config) {
2286
2411
  throw new Error("HomeCom devices are adopted from the cloud");
2287
2412
  }
2413
+ requireInstances() {
2414
+ if (!this.instances) throw new Error("HomeCom provider not initialised");
2415
+ return this.instances;
2416
+ }
2288
2417
  setIntegrationDevicesOnline(integrationId, online) {
2289
2418
  const reg = this.ctx.kernel.deviceRegistry;
2290
2419
  if (!reg) return;