@camstack/addon-provider-bosch 0.1.35 → 0.1.37
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/CHANGELOG.md +12 -0
- package/dist/{account-integration-offline-De_H_EsP.js → account-integration-offline-VItxeiJg.js} +2 -2
- package/dist/{account-integration-offline-Bt3N9Zdk.mjs → account-integration-offline-nChgZUlC.mjs} +1 -1
- package/dist/{dist-CyZFf49n.js → bosch-instances-BQiyzlPt.mjs} +33936 -31385
- package/dist/{dist-CkMPcvma.mjs → bosch-instances-CO8yIFzJ.js} +34261 -31124
- package/dist/home-connect/addon.js +349 -278
- package/dist/home-connect/addon.mjs +175 -104
- package/dist/homecom/addon.js +247 -117
- package/dist/homecom/addon.mjs +165 -35
- package/dist/shc/addon.js +217 -93
- package/dist/shc/addon.mjs +130 -6
- package/package.json +14 -2
package/dist/homecom/addon.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_bosch_instances = require("../bosch-instances-CO8yIFzJ.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-VItxeiJg.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 =
|
|
7
|
+
var HomeComBrandSchema = require_bosch_instances._enum(HOMECOM_BRANDS);
|
|
8
8
|
var HOMECOM_REGIONS = ["eu", "us"];
|
|
9
|
-
var HomeComRegionSchema =
|
|
10
|
-
var homeComConfigSchema =
|
|
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:
|
|
13
|
-
token:
|
|
14
|
-
refresh:
|
|
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:
|
|
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:
|
|
23
|
+
accountLabel: require_bosch_instances.string().optional(),
|
|
24
24
|
/** How many gateways the last sign-in listed. */
|
|
25
|
-
gatewayCount:
|
|
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 =
|
|
191
|
-
value:
|
|
192
|
-
label:
|
|
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 =
|
|
197
|
-
beginSignIn:
|
|
198
|
-
attemptId:
|
|
199
|
-
authorizeUrl:
|
|
200
|
-
summary:
|
|
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:
|
|
206
|
-
attemptId:
|
|
207
|
-
callback:
|
|
208
|
-
}),
|
|
209
|
-
token:
|
|
210
|
-
refresh:
|
|
211
|
-
username:
|
|
212
|
-
accountLabel:
|
|
213
|
-
gatewayCount:
|
|
214
|
-
summary:
|
|
215
|
-
gatewayId:
|
|
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:
|
|
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:
|
|
229
|
-
pending:
|
|
230
|
-
token:
|
|
231
|
-
refresh:
|
|
232
|
-
username:
|
|
233
|
-
accountLabel:
|
|
234
|
-
gatewayCount:
|
|
235
|
-
summary:
|
|
236
|
-
gatewayId:
|
|
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:
|
|
234
|
+
choices: require_bosch_instances.array(gatewayChoice).optional()
|
|
240
235
|
}), {
|
|
241
236
|
kind: "mutation",
|
|
242
237
|
auth: "admin"
|
|
243
238
|
}),
|
|
244
|
-
signOut:
|
|
245
|
-
signedOut:
|
|
246
|
-
summary:
|
|
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
|
-
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
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.
|
|
1281
|
-
|
|
1282
|
-
if (locked
|
|
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.
|
|
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:
|
|
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" ?
|
|
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:
|
|
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:
|
|
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:
|
|
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" :
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
1882
|
-
nativeId:
|
|
1883
|
-
brokerId:
|
|
1884
|
-
circuitId:
|
|
1885
|
-
system:
|
|
1886
|
-
integrationId:
|
|
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
|
|
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(
|
|
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 =
|
|
1993
|
-
nativeId:
|
|
1994
|
-
brokerId:
|
|
1995
|
-
system:
|
|
1996
|
-
integrationId:
|
|
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
|
|
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(
|
|
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
|
|
2175
|
+
var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDeviceProvider {
|
|
2067
2176
|
addonId = "bosch-homecom";
|
|
2068
2177
|
providerName = "Bosch HomeCom";
|
|
2069
2178
|
deviceClasses = {
|
|
2070
|
-
[
|
|
2071
|
-
[
|
|
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,24 @@ 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
|
+
secrets: this.ctx.secrets ?? null,
|
|
2197
|
+
records,
|
|
2198
|
+
warn: (message) => this.ctx.logger.warn(message)
|
|
2199
|
+
})));
|
|
2200
|
+
const built = buildHomeComInstances(records, {
|
|
2201
|
+
onChanged: () => this.reconcileIntegrations(),
|
|
2202
|
+
tester: this.buildConnectionTestProvider()
|
|
2203
|
+
});
|
|
2204
|
+
this.instances = built;
|
|
2081
2205
|
await this.serveLoginProxy();
|
|
2082
2206
|
const persistDeps = {
|
|
2083
|
-
|
|
2084
|
-
|
|
2207
|
+
read: (id) => homeComStoredOf(built.instances, id),
|
|
2208
|
+
patch: (id, patch) => built.handle.patch(id, patch),
|
|
2085
2209
|
logger: this.ctx.logger
|
|
2086
2210
|
};
|
|
2087
2211
|
const persistTokens = buildHomeComTokenPersister(persistDeps);
|
|
@@ -2102,12 +2226,16 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2102
2226
|
providers: [
|
|
2103
2227
|
...regs,
|
|
2104
2228
|
{
|
|
2105
|
-
capability:
|
|
2229
|
+
capability: require_bosch_instances.deviceAdoptionCapability,
|
|
2106
2230
|
provider: this.buildAdoptionProvider()
|
|
2107
2231
|
},
|
|
2108
2232
|
{
|
|
2109
|
-
capability:
|
|
2233
|
+
capability: require_bosch_instances.connectionTestCapability,
|
|
2110
2234
|
provider: this.buildConnectionTestProvider()
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
capability: require_bosch_instances.integrationInstancesCapability,
|
|
2238
|
+
provider: built.provider
|
|
2111
2239
|
}
|
|
2112
2240
|
],
|
|
2113
2241
|
customActions: homeComActions,
|
|
@@ -2140,7 +2268,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2140
2268
|
}
|
|
2141
2269
|
/** The hub's HTTPS face for the vendor's login pages (D955): admin session only. */
|
|
2142
2270
|
async serveLoginProxy() {
|
|
2143
|
-
const proxy = new
|
|
2271
|
+
const proxy = new require_bosch_instances.VendorLoginProxy({
|
|
2144
2272
|
addonId: this.ctx.id,
|
|
2145
2273
|
logger: this.ctx.logger
|
|
2146
2274
|
});
|
|
@@ -2152,7 +2280,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2152
2280
|
}) ?? null;
|
|
2153
2281
|
if (this.loginPlane !== null) this.loginProxy = proxy;
|
|
2154
2282
|
} catch (err) {
|
|
2155
|
-
this.ctx.logger.warn("HomeCom login proxy failed to serve — sign-in falls back to paste", { meta: { error:
|
|
2283
|
+
this.ctx.logger.warn("HomeCom login proxy failed to serve — sign-in falls back to paste", { meta: { error: require_bosch_instances.errMsg(err) } });
|
|
2156
2284
|
}
|
|
2157
2285
|
}
|
|
2158
2286
|
async onShutdown() {
|
|
@@ -2162,9 +2290,10 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2162
2290
|
try {
|
|
2163
2291
|
await this.clients?.shutdown();
|
|
2164
2292
|
} catch (err) {
|
|
2165
|
-
this.ctx.logger.warn("HomeCom shutdown error", { meta: { error:
|
|
2293
|
+
this.ctx.logger.warn("HomeCom shutdown error", { meta: { error: require_bosch_instances.errMsg(err) } });
|
|
2166
2294
|
}
|
|
2167
2295
|
this.clients = null;
|
|
2296
|
+
this.instances = null;
|
|
2168
2297
|
await super.onShutdown();
|
|
2169
2298
|
}
|
|
2170
2299
|
requireClients() {
|
|
@@ -2184,14 +2313,14 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2184
2313
|
const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id && i.enabled);
|
|
2185
2314
|
const surviving = /* @__PURE__ */ new Set();
|
|
2186
2315
|
for (const integration of mine) try {
|
|
2187
|
-
const connection =
|
|
2316
|
+
const connection = await homeComConnectionOf(this.requireInstances().instances, integration.id);
|
|
2188
2317
|
if (!connection) continue;
|
|
2189
2318
|
await reg.upsert(integration.id, integration.name, connection);
|
|
2190
2319
|
surviving.add(integration.id);
|
|
2191
2320
|
} catch (err) {
|
|
2192
2321
|
this.ctx.logger.warn("HomeCom reconcile failed for integration", { meta: {
|
|
2193
2322
|
integrationId: integration.id,
|
|
2194
|
-
error:
|
|
2323
|
+
error: require_bosch_instances.errMsg(err)
|
|
2195
2324
|
} });
|
|
2196
2325
|
}
|
|
2197
2326
|
const vanished = reg.list().filter((id) => !surviving.has(id));
|
|
@@ -2207,7 +2336,7 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2207
2336
|
logger: this.ctx.logger
|
|
2208
2337
|
});
|
|
2209
2338
|
} catch (err) {
|
|
2210
|
-
this.ctx.logger.warn("HomeCom integration reconcile failed", { meta: { error:
|
|
2339
|
+
this.ctx.logger.warn("HomeCom integration reconcile failed", { meta: { error: require_bosch_instances.errMsg(err) } });
|
|
2211
2340
|
}
|
|
2212
2341
|
}
|
|
2213
2342
|
subscribeIntegrationLifecycle() {
|
|
@@ -2216,9 +2345,9 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2216
2345
|
if (typeof addonId === "string" && addonId !== this.ctx.id) return;
|
|
2217
2346
|
this.reconcileIntegrations();
|
|
2218
2347
|
};
|
|
2219
|
-
this.ctx.eventBus.subscribe({ category:
|
|
2220
|
-
this.ctx.eventBus.subscribe({ category:
|
|
2221
|
-
this.ctx.eventBus.subscribe({ category:
|
|
2348
|
+
this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationEnabled }, handler);
|
|
2349
|
+
this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDisabled }, handler);
|
|
2350
|
+
this.ctx.eventBus.subscribe({ category: require_bosch_instances.EventCategory.IntegrationDeleted }, handler);
|
|
2222
2351
|
}
|
|
2223
2352
|
buildConnectionTestProvider() {
|
|
2224
2353
|
return buildHomeComConnectionTestProvider({ logger: this.ctx.logger });
|
|
@@ -2273,9 +2402,6 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2273
2402
|
logger: this.ctx.logger
|
|
2274
2403
|
});
|
|
2275
2404
|
}
|
|
2276
|
-
globalSettingsSchema() {
|
|
2277
|
-
return buildHomeComFormSchema();
|
|
2278
|
-
}
|
|
2279
2405
|
async supportsManualCreation() {
|
|
2280
2406
|
return false;
|
|
2281
2407
|
}
|
|
@@ -2285,6 +2411,10 @@ var BoschHomeComProviderAddon = class extends require_dist.BaseDeviceProvider {
|
|
|
2285
2411
|
async onCreateDevice(_type, _config) {
|
|
2286
2412
|
throw new Error("HomeCom devices are adopted from the cloud");
|
|
2287
2413
|
}
|
|
2414
|
+
requireInstances() {
|
|
2415
|
+
if (!this.instances) throw new Error("HomeCom provider not initialised");
|
|
2416
|
+
return this.instances;
|
|
2417
|
+
}
|
|
2288
2418
|
setIntegrationDevicesOnline(integrationId, online) {
|
|
2289
2419
|
const reg = this.ctx.kernel.deviceRegistry;
|
|
2290
2420
|
if (!reg) return;
|