@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.
package/dist/shc/addon.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region \0rolldown/runtime.js
3
3
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
4
4
  //#endregion
5
- const require_dist = require("../dist-DOr0p9V1.js");
5
+ const require_bosch_instances = require("../bosch-instances-CXmuRkef.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");
@@ -11,27 +11,27 @@ let node_os = require("node:os");
11
11
  let node_path = require("node:path");
12
12
  let node_net = require("node:net");
13
13
  //#region src/shc/custom-actions.ts
14
- var boschShcActions = require_dist.defineCustomActions({
15
- discoverController: require_dist.customAction(require_dist.object({}), require_dist.object({
16
- hosts: require_dist.array(require_dist.object({
17
- host: require_dist.string(),
18
- name: require_dist.string(),
19
- id: require_dist.string()
14
+ var boschShcActions = require_bosch_instances.defineCustomActions({
15
+ discoverController: require_bosch_instances.customAction(require_bosch_instances.object({}), require_bosch_instances.object({
16
+ hosts: require_bosch_instances.array(require_bosch_instances.object({
17
+ host: require_bosch_instances.string(),
18
+ name: require_bosch_instances.string(),
19
+ id: require_bosch_instances.string()
20
20
  })),
21
- summary: require_dist.string()
21
+ summary: require_bosch_instances.string()
22
22
  }), {
23
23
  kind: "mutation",
24
24
  auth: "admin"
25
25
  }),
26
- registerClient: require_dist.customAction(require_dist.object({
27
- host: require_dist.string().optional(),
28
- hostManual: require_dist.string().optional(),
29
- systemPassword: require_dist.string().min(1)
30
- }), require_dist.object({
31
- sslCertificate: require_dist.string().min(1).meta({ secret: true }),
32
- sslKey: require_dist.string().min(1).meta({ secret: true }),
33
- token: require_dist.string().min(1).meta({ secret: true }),
34
- summary: require_dist.string()
26
+ registerClient: require_bosch_instances.customAction(require_bosch_instances.object({
27
+ host: require_bosch_instances.string().optional(),
28
+ hostManual: require_bosch_instances.string().optional(),
29
+ systemPassword: require_bosch_instances.string().min(1)
30
+ }), require_bosch_instances.object({
31
+ sslCertificate: require_bosch_instances.string().min(1).meta({ secret: true }),
32
+ sslKey: require_bosch_instances.string().min(1).meta({ secret: true }),
33
+ token: require_bosch_instances.string().min(1).meta({ secret: true }),
34
+ summary: require_bosch_instances.string()
35
35
  }), {
36
36
  kind: "mutation",
37
37
  auth: "admin"
@@ -40,11 +40,11 @@ var boschShcActions = require_dist.defineCustomActions({
40
40
  //#endregion
41
41
  //#region src/shc/config.ts
42
42
  /** Operator settings for one SHC integration (local mTLS + optional token). */
43
- var shcConfigSchema = require_dist.object({
44
- host: require_dist.string().min(1).describe("SHC hostname or IP"),
45
- sslCertificate: require_dist.string().min(1).describe("Client certificate PEM").meta({ secret: true }),
46
- sslKey: require_dist.string().min(1).describe("Client private key PEM").meta({ secret: true }),
47
- token: require_dist.string().optional().describe("Optional API token from the Bosch app").meta({ secret: true })
43
+ var shcConfigSchema = require_bosch_instances.object({
44
+ host: require_bosch_instances.string().min(1).describe("SHC hostname or IP"),
45
+ sslCertificate: require_bosch_instances.string().min(1).describe("Client certificate PEM").meta({ secret: true }),
46
+ sslKey: require_bosch_instances.string().min(1).describe("Client private key PEM").meta({ secret: true }),
47
+ token: require_bosch_instances.string().optional().describe("Optional API token from the Bosch app").meta({ secret: true })
48
48
  });
49
49
  function connectionFromSettings(settings) {
50
50
  const parsed = shcConfigSchema.safeParse(settings);
@@ -197,6 +197,109 @@ function buildConnectionFormSchema() {
197
197
  }] };
198
198
  }
199
199
  //#endregion
200
+ //#region src/shc/shc-instances.ts
201
+ /**
202
+ * Bosch Smart Home Controller integrations as `integration-instances` (planning#416, D985,
203
+ * D1007): one `connections` record per controller under the `integrations` registry id. The body
204
+ * IS the connection (host, the client certificate and key and the optional token, all three in
205
+ * the keychain), so the form the instances page edits is the stored shape.
206
+ */
207
+ var shcConnectionsEntryKind = require_bosch_instances.defineEntryKind("connections", {
208
+ title: "Smart Home Controllers",
209
+ schema: require_bosch_instances.entryBody({
210
+ host: require_bosch_instances.string().optional(),
211
+ sslCertificate: require_bosch_instances.string().optional().meta({ secret: true }),
212
+ sslKey: require_bosch_instances.string().optional().meta({ secret: true }),
213
+ token: require_bosch_instances.string().optional().meta({ secret: true })
214
+ }),
215
+ writeTrigger: "an operator pairs, edits or removes a Smart Home Controller"
216
+ });
217
+ /** Every kind this addon declares, keyed by its name. */
218
+ var shcRecordKinds = { connections: shcConnectionsEntryKind };
219
+ var LEGACY_KEYS = [
220
+ "host",
221
+ "sslCertificate",
222
+ "sslKey",
223
+ "token"
224
+ ];
225
+ var SECRET_KEYS = [
226
+ "sslCertificate",
227
+ "sslKey",
228
+ "token"
229
+ ];
230
+ function text(value) {
231
+ return typeof value === "string" && value.length > 0 ? value : void 0;
232
+ }
233
+ /** The record body of one controller, from its legacy rows (secrets resolved). */
234
+ function shcBodyFromRows(values, log, integration) {
235
+ const dropped = Object.keys(values).filter((key) => !LEGACY_KEYS.includes(key));
236
+ if (dropped.length > 0) log.warn(`integration '${integration.id}': legacy settings nothing reads any more are dropped: ${dropped.join(", ")}`);
237
+ const host = text(values["host"]);
238
+ const sslCertificate = text(values["sslCertificate"]);
239
+ const sslKey = text(values["sslKey"]);
240
+ const token = text(values["token"]);
241
+ return {
242
+ name: integration.name,
243
+ ...host !== void 0 ? { host } : {},
244
+ ...sslCertificate !== void 0 ? { sslCertificate } : {},
245
+ ...sslKey !== void 0 ? { sslKey } : {},
246
+ ...token !== void 0 ? { token } : {}
247
+ };
248
+ }
249
+ /** The whole `bosch-shc` catalogue (D987): offered to the engine at `onInitialize`. */
250
+ var SHC_MIGRATIONS = [require_bosch_instances.boschRowsMigration({
251
+ addonId: "bosch-shc",
252
+ id: "bosch-shc/2026-11-05-integration-rows-to-record",
253
+ description: "Move every Smart Home Controller connection into a typed instance record keyed by its registry id, then clear the legacy integration settings rows and their keychain values",
254
+ fixtureMark: "a legacy setting key the migration does not know",
255
+ kind: shcConnectionsEntryKind,
256
+ bodyFrom: shcBodyFromRows
257
+ })];
258
+ function shcRowsPorts(deps) {
259
+ return require_bosch_instances.boschRowsPorts({
260
+ ...deps,
261
+ kind: shcConnectionsEntryKind
262
+ });
263
+ }
264
+ /**
265
+ * The live connection of one controller, read from its record. null while the connection is
266
+ * incomplete; a locked keychain throws so the caller keeps the client it has instead of
267
+ * reconfiguring it without its certificate (D49).
268
+ */
269
+ async function shcConnectionOf(instances, id) {
270
+ const read = await instances.readResolved(id);
271
+ if (read === null) return null;
272
+ if (read.secrets === "unavailable") throw new Error("the keychain is locked, the saved controller credentials cannot be read");
273
+ return connectionFromSettings(read.body);
274
+ }
275
+ function buildShcInstances(records, deps) {
276
+ const handle = records.kind(shcConnectionsEntryKind);
277
+ const instances = new require_bosch_instances.RecordIntegrationInstances(records, shcConnectionsEntryKind, {
278
+ description: {
279
+ role: "devices",
280
+ instanceMode: "multiple",
281
+ kind: "controller",
282
+ canTest: true
283
+ },
284
+ formSchema: () => buildConnectionFormSchema(),
285
+ initialBody: (name) => ({ name }),
286
+ configured: (body) => connectionFromSettings(body) !== null,
287
+ onChanged: async (_id, change) => {
288
+ if (change !== "deleted") await deps.onChanged();
289
+ },
290
+ test: (input) => require_bosch_instances.testBoschInstance({
291
+ ...input,
292
+ tester: deps.tester,
293
+ handle,
294
+ secretKeys: SECRET_KEYS
295
+ })
296
+ });
297
+ return {
298
+ instances,
299
+ provider: require_bosch_instances.keepBodyKeys(instances.toProvider(), new Set(Object.keys(shcConnectionsEntryKind.schema.shape)))
300
+ };
301
+ }
302
+ //#endregion
200
303
  //#region src/shc/shc-self-signed.ts
201
304
  /**
202
305
  * RSA-2048 self-signed certificate. The controller stores this certificate;
@@ -388,7 +491,7 @@ function proposeShcControllers(found, existingHosts) {
388
491
  function shcDiscoveryCandidates(proposals) {
389
492
  return proposals.map((found) => ({
390
493
  stableId: `bosch-shc:${found.id}`,
391
- type: require_dist.DeviceType.Gateway,
494
+ type: require_bosch_instances.DeviceType.Gateway,
392
495
  suggestedName: found.name,
393
496
  prefilledConfig: { host: found.host },
394
497
  setupIntegration: true
@@ -439,15 +542,15 @@ var ShcConnectionResolver = class {
439
542
  var shcConnections = new ShcConnectionResolver();
440
543
  //#endregion
441
544
  //#region src/shc/devices/shc-device-base.ts
442
- var shcDeviceSchema = require_dist.object({
443
- shcDeviceId: require_dist.string().min(1).describe("Bosch SHC device id"),
444
- brokerId: require_dist.string().min(1).describe("Integration id"),
445
- deviceModel: require_dist.string().optional(),
446
- system: require_dist.literal("bosch-shc").optional(),
447
- integrationId: require_dist.string().optional(),
448
- tempStep: require_dist.number().positive().optional()
545
+ var shcDeviceSchema = require_bosch_instances.object({
546
+ shcDeviceId: require_bosch_instances.string().min(1).describe("Bosch SHC device id"),
547
+ brokerId: require_bosch_instances.string().min(1).describe("Integration id"),
548
+ deviceModel: require_bosch_instances.string().optional(),
549
+ system: require_bosch_instances.literal("bosch-shc").optional(),
550
+ integrationId: require_bosch_instances.string().optional(),
551
+ tempStep: require_bosch_instances.number().positive().optional()
449
552
  });
450
- var ShcBaseDevice = class extends require_dist.BaseDevice {
553
+ var ShcBaseDevice = class extends require_bosch_instances.BaseDevice {
451
554
  features = [];
452
555
  shcDeviceId;
453
556
  brokerId;
@@ -495,7 +598,7 @@ var ShcBaseDevice = class extends require_dist.BaseDevice {
495
598
  this.refreshFromController().catch((err) => {
496
599
  this.deviceLog("warn", "SHC refresh after controller event failed", {
497
600
  shcDeviceId: this.shcDeviceId,
498
- error: require_dist.errMsg(err)
601
+ error: require_bosch_instances.errMsg(err)
499
602
  });
500
603
  });
501
604
  };
@@ -526,11 +629,11 @@ var ShcBaseDevice = class extends require_dist.BaseDevice {
526
629
  * devices are NOT children of it; they are adopted as their own top-level
527
630
  * devices of the same integration.
528
631
  */
529
- var ShcGatewayDevice = class extends require_dist.BaseDevice {
632
+ var ShcGatewayDevice = class extends require_bosch_instances.BaseDevice {
530
633
  features = [];
531
634
  constructor(ctx) {
532
635
  const cfg = shcDeviceSchema.parse(ctx.persistedConfig ?? {});
533
- super(ctx, shcDeviceSchema, { type: require_dist.DeviceType.Gateway });
636
+ super(ctx, shcDeviceSchema, { type: require_bosch_instances.DeviceType.Gateway });
534
637
  this.online = shcConnections.has(cfg.brokerId);
535
638
  this.updateSourceInfo({
536
639
  id: cfg.shcDeviceId,
@@ -558,9 +661,9 @@ function shcKindForModel(deviceModel) {
558
661
  }
559
662
  function deviceTypeForShcKind(kind) {
560
663
  switch (kind) {
561
- case "room-climate": return require_dist.DeviceType.Container;
562
- case "trv": return require_dist.DeviceType.Thermostat;
563
- case "switch": return require_dist.DeviceType.Switch;
664
+ case "room-climate": return require_bosch_instances.DeviceType.Container;
665
+ case "trv": return require_bosch_instances.DeviceType.Thermostat;
666
+ case "switch": return require_bosch_instances.DeviceType.Switch;
564
667
  }
565
668
  }
566
669
  function capsForShcKind(kind) {
@@ -690,7 +793,7 @@ function trvCandidate(device) {
690
793
  return {
691
794
  childNativeId: device.id,
692
795
  name: device.name.length > 0 ? device.name : device.id,
693
- type: require_dist.DeviceType.Thermostat,
796
+ type: require_bosch_instances.DeviceType.Thermostat,
694
797
  status: "online",
695
798
  metadata: {
696
799
  serialNumber: device.id,
@@ -711,7 +814,7 @@ function roomClimateContainerCandidate(device, devices, adoptedId) {
711
814
  const climateChild = {
712
815
  childNativeId: `${device.id}#climate`,
713
816
  name: shcClimateEntityName(device.name.length > 0 ? device.name : device.id),
714
- type: require_dist.DeviceType.Climate,
817
+ type: require_bosch_instances.DeviceType.Climate,
715
818
  status: "online",
716
819
  metadata: {
717
820
  serialNumber: device.id,
@@ -730,7 +833,7 @@ function roomClimateContainerCandidate(device, devices, adoptedId) {
730
833
  return {
731
834
  childNativeId: device.id,
732
835
  name: device.name.length > 0 ? device.name : device.id,
733
- type: require_dist.DeviceType.Container,
836
+ type: require_bosch_instances.DeviceType.Container,
734
837
  status: "online",
735
838
  metadata: {
736
839
  serialNumber: device.id,
@@ -765,7 +868,7 @@ function buildShcCandidates(input) {
765
868
  const out = [{
766
869
  childNativeId: gatewayId,
767
870
  name: input.integrationName,
768
- type: require_dist.DeviceType.Gateway,
871
+ type: require_bosch_instances.DeviceType.Gateway,
769
872
  status: "online",
770
873
  metadata: {
771
874
  manufacturer: "Bosch",
@@ -886,7 +989,7 @@ var ShcRoomClimateDevice = class extends ShcBaseDevice {
886
989
  super(ctx);
887
990
  }
888
991
  registerCaps() {
889
- this.ctx.registerNativeCap(require_dist.climateControlCapability, {
992
+ this.ctx.registerNativeCap(require_bosch_instances.climateControlCapability, {
890
993
  getStatus: async () => this.runtimeState.getCapState(CLIMATE_CAP) ?? COLD_START,
891
994
  setMode: async ({ mode }) => {
892
995
  const client = this.requireClient();
@@ -986,9 +1089,9 @@ var ShcTrvDevice = class extends ShcBaseDevice {
986
1089
  super(ctx);
987
1090
  }
988
1091
  registerCaps() {
989
- this.ctx.registerNativeCap(require_dist.temperatureSensorCapability, { getStatus: async () => this.runtimeState.getCapState(TEMP_CAP) ?? TEMP_COLD });
1092
+ this.ctx.registerNativeCap(require_bosch_instances.temperatureSensorCapability, { getStatus: async () => this.runtimeState.getCapState(TEMP_CAP) ?? TEMP_COLD });
990
1093
  this.runtimeState.setCapState(TEMP_CAP, TEMP_COLD);
991
- this.ctx.registerNativeCap(require_dist.batteryCapability, {
1094
+ this.ctx.registerNativeCap(require_bosch_instances.batteryCapability, {
992
1095
  getStatus: async () => this.runtimeState.getCapState(BATTERY_CAP) ?? BATTERY_COLD,
993
1096
  wakeForStream: async () => ({
994
1097
  awoke: true,
@@ -996,7 +1099,7 @@ var ShcTrvDevice = class extends ShcBaseDevice {
996
1099
  })
997
1100
  });
998
1101
  this.runtimeState.setCapState(BATTERY_CAP, BATTERY_COLD);
999
- this.ctx.registerNativeCap(require_dist.heatingValveCapability, { getStatus: async () => this.runtimeState.getCapState(VALVE_CAP) ?? VALVE_COLD });
1102
+ this.ctx.registerNativeCap(require_bosch_instances.heatingValveCapability, { getStatus: async () => this.runtimeState.getCapState(VALVE_CAP) ?? VALVE_COLD });
1000
1103
  this.runtimeState.setCapState(VALVE_CAP, VALVE_COLD);
1001
1104
  }
1002
1105
  async refreshFromController() {
@@ -1043,21 +1146,21 @@ var ShcTrvDevice = class extends ShcBaseDevice {
1043
1146
  };
1044
1147
  //#endregion
1045
1148
  //#region src/shc/devices/shc-climate-room-device.ts
1046
- var shcClimateRoomChildSchema = require_dist.object({
1047
- shcDeviceId: require_dist.string().min(1),
1048
- name: require_dist.string(),
1049
- role: require_dist._enum(["climate", "trv"])
1149
+ var shcClimateRoomChildSchema = require_bosch_instances.object({
1150
+ shcDeviceId: require_bosch_instances.string().min(1),
1151
+ name: require_bosch_instances.string(),
1152
+ role: require_bosch_instances._enum(["climate", "trv"])
1050
1153
  });
1051
- var shcClimateRoomSchema = shcDeviceSchema.extend({ children: require_dist.array(shcClimateRoomChildSchema).min(1) });
1154
+ var shcClimateRoomSchema = shcDeviceSchema.extend({ children: require_bosch_instances.array(shcClimateRoomChildSchema).min(1) });
1052
1155
  /** One SHC room: climate setpoint child + linked TRV accessories. */
1053
- var ShcClimateRoomDevice = class extends require_dist.BaseDevice {
1156
+ var ShcClimateRoomDevice = class extends require_bosch_instances.BaseDevice {
1054
1157
  features = [];
1055
1158
  integrationId;
1056
1159
  brokerId;
1057
1160
  deviceModel;
1058
1161
  constructor(ctx) {
1059
1162
  const cfg = shcClimateRoomSchema.parse(ctx.persistedConfig ?? {});
1060
- super(ctx, shcClimateRoomSchema, { type: require_dist.DeviceType.Container });
1163
+ super(ctx, shcClimateRoomSchema, { type: require_bosch_instances.DeviceType.Container });
1061
1164
  this.brokerId = cfg.brokerId;
1062
1165
  this.integrationId = cfg.integrationId;
1063
1166
  this.deviceModel = cfg.deviceModel;
@@ -1082,7 +1185,7 @@ var ShcClimateRoomDevice = class extends require_dist.BaseDevice {
1082
1185
  return {
1083
1186
  stableIdSuffix: "climate",
1084
1187
  meta: {
1085
- type: require_dist.DeviceType.Climate,
1188
+ type: require_bosch_instances.DeviceType.Climate,
1086
1189
  name: shcClimateEntityName(containerName),
1087
1190
  linkDeviceId: this.id,
1088
1191
  ...this.integrationId !== void 0 ? { integrationId: this.integrationId } : {}
@@ -1101,7 +1204,7 @@ var ShcClimateRoomDevice = class extends require_dist.BaseDevice {
1101
1204
  return {
1102
1205
  stableIdSuffix: `trv-${shcStableIdSuffixFromDeviceId(child.shcDeviceId)}`,
1103
1206
  meta: {
1104
- type: require_dist.DeviceType.Thermostat,
1207
+ type: require_bosch_instances.DeviceType.Thermostat,
1105
1208
  name: child.name,
1106
1209
  linkDeviceId: this.id,
1107
1210
  ...this.integrationId !== void 0 ? { integrationId: this.integrationId } : {}
@@ -1125,7 +1228,7 @@ var ShcSwitchDevice = class extends ShcBaseDevice {
1125
1228
  super(ctx);
1126
1229
  }
1127
1230
  registerCaps() {
1128
- this.ctx.registerNativeCap(require_dist.switchCapability, {
1231
+ this.ctx.registerNativeCap(require_bosch_instances.switchCapability, {
1129
1232
  getStatus: async () => this.runtimeState.getCapState(SWITCH_CAP) ?? SWITCH_COLD,
1130
1233
  setState: async ({ on }) => {
1131
1234
  await this.requireClient().putServiceState(this.shcDeviceId, SERVICE, buildPowerSwitchPutBody(on));
@@ -1215,12 +1318,12 @@ function buildShcAdoptionProvider(deps) {
1215
1318
  lastError: null
1216
1319
  };
1217
1320
  } catch (err) {
1218
- logger.warn("bosch-shc adoption: getStatus failed", { meta: { error: require_dist.errMsg(err) } });
1321
+ logger.warn("bosch-shc adoption: getStatus failed", { meta: { error: require_bosch_instances.errMsg(err) } });
1219
1322
  return {
1220
1323
  lastDiscoveryAt: null,
1221
1324
  candidateCount: 0,
1222
1325
  adoptedCount: 0,
1223
- lastError: require_dist.errMsg(err)
1326
+ lastError: require_bosch_instances.errMsg(err)
1224
1327
  };
1225
1328
  }
1226
1329
  },
@@ -1245,7 +1348,7 @@ function buildShcAdoptionProvider(deps) {
1245
1348
  const { deviceId } = await adoptDevice({
1246
1349
  shcDeviceId,
1247
1350
  integrationId,
1248
- type: require_dist.DeviceType.Gateway,
1351
+ type: require_bosch_instances.DeviceType.Gateway,
1249
1352
  name,
1250
1353
  deviceModel: "Smart Home Controller"
1251
1354
  });
@@ -1283,7 +1386,7 @@ function buildShcAdoptionProvider(deps) {
1283
1386
  logger.warn("bosch-shc adopt: failed", { meta: {
1284
1387
  shcDeviceId,
1285
1388
  integrationId,
1286
- error: require_dist.errMsg(err)
1389
+ error: require_bosch_instances.errMsg(err)
1287
1390
  } });
1288
1391
  failures++;
1289
1392
  }
@@ -23465,7 +23568,7 @@ var ShcIntegrationManager = class {
23465
23568
  });
23466
23569
  } catch (err) {
23467
23570
  this.#status = "error";
23468
- this.#error = require_dist.errMsg(err);
23571
+ this.#error = require_bosch_instances.errMsg(err);
23469
23572
  this.#lastCheckedAt = Date.now();
23470
23573
  this.#surfaceSink.set(this.#id, null);
23471
23574
  client.close();
@@ -23489,7 +23592,7 @@ var ShcIntegrationManager = class {
23489
23592
  } catch (err) {
23490
23593
  this.#logger.warn("ShcIntegrationManager: client close failed", {
23491
23594
  tags: { integrationId: this.#id },
23492
- meta: { error: require_dist.errMsg(err) }
23595
+ meta: { error: require_bosch_instances.errMsg(err) }
23493
23596
  });
23494
23597
  }
23495
23598
  this.#onDisconnected(this.#id);
@@ -23548,7 +23651,7 @@ var ShcClientRegistry = class {
23548
23651
  } catch (err) {
23549
23652
  this.#logger.warn("ShcClientRegistry: applyConnection failed", {
23550
23653
  tags: { integrationId },
23551
- meta: { error: require_dist.errMsg(err) }
23654
+ meta: { error: require_bosch_instances.errMsg(err) }
23552
23655
  });
23553
23656
  }
23554
23657
  return;
@@ -23571,7 +23674,7 @@ var ShcClientRegistry = class {
23571
23674
  } catch (err) {
23572
23675
  this.#logger.warn("ShcClientRegistry: manager start failed", {
23573
23676
  tags: { integrationId },
23574
- meta: { error: require_dist.errMsg(err) }
23677
+ meta: { error: require_bosch_instances.errMsg(err) }
23575
23678
  });
23576
23679
  }
23577
23680
  }
@@ -23584,7 +23687,7 @@ var ShcClientRegistry = class {
23584
23687
  } catch (err) {
23585
23688
  this.#logger.warn("ShcClientRegistry: remove stop failed", {
23586
23689
  tags: { integrationId },
23587
- meta: { error: require_dist.errMsg(err) }
23690
+ meta: { error: require_bosch_instances.errMsg(err) }
23588
23691
  });
23589
23692
  }
23590
23693
  }
@@ -23600,7 +23703,7 @@ var ShcClientRegistry = class {
23600
23703
  } catch (err) {
23601
23704
  this.#logger.warn("ShcClientRegistry: shutdown stop failed", {
23602
23705
  tags: { integrationId: id },
23603
- meta: { error: require_dist.errMsg(err) }
23706
+ meta: { error: require_bosch_instances.errMsg(err) }
23604
23707
  });
23605
23708
  }
23606
23709
  }));
@@ -23695,7 +23798,7 @@ async function cascadeRemoveDevicesForIntegration(input) {
23695
23798
  tags: { deviceId: d.id },
23696
23799
  meta: {
23697
23800
  integrationId,
23698
- error: require_dist.errMsg(err)
23801
+ error: require_bosch_instances.errMsg(err)
23699
23802
  }
23700
23803
  });
23701
23804
  }
@@ -23720,22 +23823,36 @@ function setIntegrationDevicesOnline(devices, integrationId, online) {
23720
23823
  /**
23721
23824
  * Bosch Smart Home Controller — `mode: account`, broker-less multi-integration.
23722
23825
  */
23723
- var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23826
+ var BoschShcProviderAddon = class extends require_bosch_instances.BaseDeviceProvider {
23724
23827
  addonId = "bosch-shc";
23725
23828
  providerName = "Bosch SHC";
23726
23829
  deviceClasses = {
23727
- [require_dist.DeviceType.Gateway]: ShcGatewayDevice,
23728
- [require_dist.DeviceType.Container]: ShcClimateRoomDevice,
23729
- [require_dist.DeviceType.Climate]: ShcRoomClimateDevice,
23730
- [require_dist.DeviceType.Thermostat]: ShcTrvDevice,
23731
- [require_dist.DeviceType.Switch]: ShcSwitchDevice
23830
+ [require_bosch_instances.DeviceType.Gateway]: ShcGatewayDevice,
23831
+ [require_bosch_instances.DeviceType.Container]: ShcClimateRoomDevice,
23832
+ [require_bosch_instances.DeviceType.Climate]: ShcRoomClimateDevice,
23833
+ [require_bosch_instances.DeviceType.Thermostat]: ShcTrvDevice,
23834
+ [require_bosch_instances.DeviceType.Switch]: ShcSwitchDevice
23732
23835
  };
23733
23836
  clients = null;
23837
+ instances = null;
23734
23838
  constructor() {
23735
23839
  super({});
23736
23840
  }
23737
23841
  async onInitialize() {
23738
23842
  const regs = this.providerRegistrationsFromSuper(await super.onInitialize());
23843
+ const records = this.ctx.records;
23844
+ if (records === void 0) throw new Error("bosch-shc: ctx.records is required (hub-only addon)");
23845
+ await records.declare(shcRecordKinds);
23846
+ await this.runMigrations(require_bosch_instances.defineAddonMigrations(SHC_MIGRATIONS, shcRowsPorts({
23847
+ api: require_bosch_instances.defaultIntegrationApiOver(this.ctx.api),
23848
+ records,
23849
+ warn: (message) => this.ctx.logger.warn(message)
23850
+ })));
23851
+ const built = buildShcInstances(records, {
23852
+ onChanged: () => this.reconcileIntegrations(),
23853
+ tester: this.buildConnectionTestProvider()
23854
+ });
23855
+ this.instances = built.instances;
23739
23856
  this.clients = new ShcClientRegistry(this.ctx.logger);
23740
23857
  this.clients.setOnConnected((integrationId) => {
23741
23858
  this.setIntegrationDevicesOnline(integrationId, true);
@@ -23749,12 +23866,16 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23749
23866
  providers: [
23750
23867
  ...regs,
23751
23868
  {
23752
- capability: require_dist.deviceAdoptionCapability,
23869
+ capability: require_bosch_instances.deviceAdoptionCapability,
23753
23870
  provider: this.buildAdoptionProvider()
23754
23871
  },
23755
23872
  {
23756
- capability: require_dist.connectionTestCapability,
23873
+ capability: require_bosch_instances.connectionTestCapability,
23757
23874
  provider: this.buildConnectionTestProvider()
23875
+ },
23876
+ {
23877
+ capability: require_bosch_instances.integrationInstancesCapability,
23878
+ provider: built.provider
23758
23879
  }
23759
23880
  ],
23760
23881
  customActions: boschShcActions,
@@ -23793,14 +23914,12 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23793
23914
  try {
23794
23915
  await this.clients?.shutdown();
23795
23916
  } catch (err) {
23796
- this.ctx.logger.warn("Bosch SHC: shutdown error", { meta: { error: require_dist.errMsg(err) } });
23917
+ this.ctx.logger.warn("Bosch SHC: shutdown error", { meta: { error: require_bosch_instances.errMsg(err) } });
23797
23918
  }
23798
23919
  this.clients = null;
23920
+ this.instances = null;
23799
23921
  await super.onShutdown();
23800
23922
  }
23801
- globalSettingsSchema() {
23802
- return buildConnectionFormSchema();
23803
- }
23804
23923
  async supportsManualCreation() {
23805
23924
  return false;
23806
23925
  }
@@ -23843,21 +23962,25 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23843
23962
  for (const integration of all) {
23844
23963
  if (integration.addonId !== this.ctx.id) continue;
23845
23964
  try {
23846
- const connection = connectionFromSettings(await this.ctx.api.integrations.getSettings.query({ id: integration.id }));
23965
+ const connection = await shcConnectionOf(this.requireInstances(), integration.id);
23847
23966
  if (connection) hosts.push(connection.host);
23848
23967
  } catch (err) {
23849
23968
  this.ctx.logger.warn("SHC discovery: settings read failed", { meta: {
23850
23969
  integrationId: integration.id,
23851
- error: require_dist.errMsg(err)
23970
+ error: require_bosch_instances.errMsg(err)
23852
23971
  } });
23853
23972
  }
23854
23973
  }
23855
23974
  return hosts;
23856
23975
  } catch (err) {
23857
- this.ctx.logger.warn("SHC discovery: integration list failed", { meta: { error: require_dist.errMsg(err) } });
23976
+ this.ctx.logger.warn("SHC discovery: integration list failed", { meta: { error: require_bosch_instances.errMsg(err) } });
23858
23977
  return [];
23859
23978
  }
23860
23979
  }
23980
+ requireInstances() {
23981
+ if (!this.instances) throw new Error("Bosch SHC provider not initialised");
23982
+ return this.instances;
23983
+ }
23861
23984
  requireClients() {
23862
23985
  if (!this.clients) throw new Error("Bosch SHC provider not initialised");
23863
23986
  return this.clients;
@@ -23868,21 +23991,21 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23868
23991
  const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id && i.enabled);
23869
23992
  const surviving = /* @__PURE__ */ new Set();
23870
23993
  for (const integration of mine) try {
23871
- const connection = connectionFromSettings(await this.ctx.api.integrations.getSettings.query({ id: integration.id }));
23994
+ const connection = await shcConnectionOf(this.requireInstances(), integration.id);
23872
23995
  if (!connection) continue;
23873
23996
  await reg.upsert(integration.id, integration.name, connection);
23874
23997
  surviving.add(integration.id);
23875
23998
  } catch (err) {
23876
23999
  this.ctx.logger.warn("Bosch SHC reconcile: settings read failed", { meta: {
23877
24000
  integrationId: integration.id,
23878
- error: require_dist.errMsg(err)
24001
+ error: require_bosch_instances.errMsg(err)
23879
24002
  } });
23880
24003
  }
23881
24004
  const vanished = reg.list().filter((id) => !surviving.has(id));
23882
24005
  await reg.retain(surviving);
23883
24006
  for (const integrationId of vanished) await this.cascadeRemoveDevicesForIntegration(integrationId);
23884
24007
  } catch (err) {
23885
- this.ctx.logger.warn("Bosch SHC integration reconcile failed", { meta: { error: require_dist.errMsg(err) } });
24008
+ this.ctx.logger.warn("Bosch SHC integration reconcile failed", { meta: { error: require_bosch_instances.errMsg(err) } });
23886
24009
  }
23887
24010
  }
23888
24011
  subscribeIntegrationLifecycle() {
@@ -23891,9 +24014,9 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23891
24014
  if (typeof addonId === "string" && addonId !== this.ctx.id) return;
23892
24015
  this.reconcileIntegrations();
23893
24016
  };
23894
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationEnabled }, handler);
23895
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDisabled }, handler);
23896
- this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.IntegrationDeleted }, handler);
24017
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
24018
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
24019
+ this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
23897
24020
  }
23898
24021
  async cascadeRemoveDevicesForIntegration(integrationId) {
23899
24022
  const reg = this.ctx.kernel.deviceRegistry;
@@ -23936,9 +24059,9 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23936
24059
  const devices = this.ctx.kernel.devices;
23937
24060
  if (!devices) throw new Error("bosch-shc adopt: kernel.devices unavailable");
23938
24061
  const summary = shcConnections.devices(integrationId).find((d) => d.id === shcDeviceId);
23939
- const kind = type === require_dist.DeviceType.Gateway ? "gateway" : summary ? classifyShcDevice(summary) : "unsupported";
24062
+ const kind = type === require_bosch_instances.DeviceType.Gateway ? "gateway" : summary ? classifyShcDevice(summary) : "unsupported";
23940
24063
  if (kind === "unsupported") throw new Error(`bosch-shc adopt: unsupported device ${shcDeviceId}`);
23941
- if (type === require_dist.DeviceType.Gateway) {
24064
+ if (type === require_bosch_instances.DeviceType.Gateway) {
23942
24065
  const config = {
23943
24066
  shcDeviceId,
23944
24067
  brokerId: integrationId,
@@ -23947,9 +24070,9 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23947
24070
  integrationId,
23948
24071
  name
23949
24072
  };
23950
- const stableId = this.generateStableId(require_dist.DeviceType.Gateway, config);
24073
+ const stableId = this.generateStableId(require_bosch_instances.DeviceType.Gateway, config);
23951
24074
  const meta = {
23952
- type: require_dist.DeviceType.Gateway,
24075
+ type: require_bosch_instances.DeviceType.Gateway,
23953
24076
  name,
23954
24077
  integrationId
23955
24078
  };
@@ -23984,9 +24107,9 @@ var BoschShcProviderAddon = class extends require_dist.BaseDeviceProvider {
23984
24107
  ...baseConfig,
23985
24108
  children
23986
24109
  };
23987
- const stableId = this.generateStableId(require_dist.DeviceType.Container, config);
24110
+ const stableId = this.generateStableId(require_bosch_instances.DeviceType.Container, config);
23988
24111
  const meta = {
23989
- type: require_dist.DeviceType.Container,
24112
+ type: require_bosch_instances.DeviceType.Container,
23990
24113
  name,
23991
24114
  integrationId
23992
24115
  };