@camstack/addon-provider-bosch 0.1.54 → 0.1.55
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 +6 -0
- package/dist/{account-integration-offline-DK6CYsvB.js → account-integration-offline-DzGZkIwF.js} +1 -1
- package/dist/{account-integration-offline-C9glrBvy.mjs → account-integration-offline-xi6muNeM.mjs} +1 -1
- package/dist/{bosch-instances-DkTzZrlR.js → bosch-instances-DaWS-s0M.js} +15443 -3675
- package/dist/{bosch-instances-DMzZSMxW.mjs → bosch-instances-g54r3Dus.mjs} +15438 -3676
- package/dist/home-connect/addon.js +2 -2
- package/dist/home-connect/addon.mjs +2 -2
- package/dist/homecom/addon.js +69 -5
- package/dist/homecom/addon.mjs +69 -5
- package/dist/shc/addon.js +1 -1
- package/dist/shc/addon.mjs +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_bosch_instances = require("../bosch-instances-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_bosch_instances = require("../bosch-instances-DaWS-s0M.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-DzGZkIwF.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_tls = require("node:tls");
|
|
6
6
|
let node_zlib = require("node:zlib");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { a as loginFailureForAttempt, c as HOME_CONNECT_REDIRECT_URI, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { $ as union, A as runningFromDishwasherOperation, B as entryBody, C as ingestReading, D as powerMeterCapability, E as plainEventVocabulary, F as RecordIntegrationInstances, H as isSecretMarkerLike, I as createEvent, J as literal, K as array, L as customAction, O as quantityFromUnit, Q as string, R as defineCustomActions, T as numericSensorCapability, U as rowsDepsOver, V as isSecretMarker, W as _enum, X as object, Z as record, _ as enumSensorCapability, a as BaseDevice, c as RUNNING_STATE_COLD, d as binaryCapability, et as unknown, g as dishwasherCapability, h as deviceAdoptionCapability, i as testBoschInstance, it as EventCategory, j as runningStateCapability, n as boschRowsPorts, nt as DeviceType, o as BaseDeviceProvider, p as consumablesCapability, r as keepBodyKeys, rt as errMsg, s as DishwasherOperationStateSchema, t as boschRowsMigration, tt as DeviceRole, v as eventEmitterCapability, w as integrationInstancesCapability, z as defineEntryKind } from "../bosch-instances-g54r3Dus.mjs";
|
|
2
|
+
import { a as loginFailureForAttempt, c as HOME_CONNECT_REDIRECT_URI, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, t as setIntegrationDevicesOnline } from "../account-integration-offline-xi6muNeM.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { connect } from "node:tls";
|
|
5
5
|
import { inflateRawSync } from "node:zlib";
|
package/dist/homecom/addon.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_bosch_instances = require("../bosch-instances-
|
|
3
|
-
const require_account_integration_offline = require("../account-integration-offline-
|
|
2
|
+
const require_bosch_instances = require("../bosch-instances-DaWS-s0M.js");
|
|
3
|
+
const require_account_integration_offline = require("../account-integration-offline-DzGZkIwF.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_child_process = require("node:child_process");
|
|
6
6
|
let node_fs = require("node:fs");
|
|
@@ -526,6 +526,32 @@ var homeComActions = require_bosch_instances.defineCustomActions({
|
|
|
526
526
|
})
|
|
527
527
|
});
|
|
528
528
|
//#endregion
|
|
529
|
+
//#region src/homecom/homecom-session-alert.ts
|
|
530
|
+
/** The standard session-lost alert for HomeCom; "Sign in again" opens the integration page. */
|
|
531
|
+
function createHomeComSessionAlert(deps) {
|
|
532
|
+
const tracker = new require_bosch_instances.SessionHealthTracker({
|
|
533
|
+
kind: "homecom",
|
|
534
|
+
providerName: "Bosch HomeCom",
|
|
535
|
+
logger: deps.logger,
|
|
536
|
+
getAlerts: deps.getAlerts,
|
|
537
|
+
debounceMs: deps.debounceMs ?? 0
|
|
538
|
+
});
|
|
539
|
+
return {
|
|
540
|
+
authFailed: (integrationId) => tracker.lost(integrationId, {
|
|
541
|
+
integrationName: deps.nameOf(integrationId),
|
|
542
|
+
reason: "token-expired",
|
|
543
|
+
action: {
|
|
544
|
+
label: "Sign in again",
|
|
545
|
+
href: `/integrations/${encodeURIComponent(integrationId)}`,
|
|
546
|
+
navigation: "app"
|
|
547
|
+
}
|
|
548
|
+
}),
|
|
549
|
+
connected: (integrationId) => tracker.restored(integrationId),
|
|
550
|
+
removed: (integrationId) => tracker.forget(integrationId),
|
|
551
|
+
dispose: () => tracker.dispose()
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
//#endregion
|
|
529
555
|
//#region src/homecom/homecom-explore-action.ts
|
|
530
556
|
/** The action refused before it walked anything; `reason` says why. */
|
|
531
557
|
var HomeComExploreRefusedError = class extends Error {
|
|
@@ -1845,6 +1871,14 @@ function homeComResourceUrl(gatewayId, resourcePath) {
|
|
|
1845
1871
|
const path = resourcePath.startsWith("/") ? resourcePath : `/${resourcePath}`;
|
|
1846
1872
|
return `${HOMECOM_POINTT_API_ORIGIN}${HOMECOM_GATEWAYS_PATH}${encodeURIComponent(gatewayId)}/resource${path}`;
|
|
1847
1873
|
}
|
|
1874
|
+
async function isInvalidGrantBody(res) {
|
|
1875
|
+
try {
|
|
1876
|
+
const body = await res.json();
|
|
1877
|
+
return isRecord$1(body) && body["error"] === "invalid_grant";
|
|
1878
|
+
} catch {
|
|
1879
|
+
return false;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1848
1882
|
function createHomeComApiClient(config, gatewayId, deps = {}) {
|
|
1849
1883
|
const fetchFn = deps.fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
1850
1884
|
const refreshOnUnauthorized = deps.refreshOnUnauthorized ?? true;
|
|
@@ -1965,6 +1999,7 @@ function createHomeComApiClient(config, gatewayId, deps = {}) {
|
|
|
1965
1999
|
});
|
|
1966
2000
|
if (!res.ok) {
|
|
1967
2001
|
if (res.status === 401 || res.status === 403) throw new HomeComAuthError("refresh refused");
|
|
2002
|
+
if (res.status === 400 && await isInvalidGrantBody(res)) throw new HomeComAuthError("refresh refused");
|
|
1968
2003
|
throw new Error(`HomeCom token refresh failed: HTTP ${res.status}`);
|
|
1969
2004
|
}
|
|
1970
2005
|
const body = await res.json();
|
|
@@ -2384,7 +2419,10 @@ function buildSerialPatcher(deps) {
|
|
|
2384
2419
|
const run = async () => {
|
|
2385
2420
|
try {
|
|
2386
2421
|
const stored = await deps.read(integrationId);
|
|
2387
|
-
if (stored === null)
|
|
2422
|
+
if (stored === null) {
|
|
2423
|
+
deps.logger.warn(`HomeCom not persisting ${deps.what} — the integration record is gone`, { tags: { integrationId } });
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
2388
2426
|
if (stored.locked) {
|
|
2389
2427
|
deps.logger.warn(`HomeCom not persisting ${deps.what} — stored secrets are locked`, { tags: { integrationId } });
|
|
2390
2428
|
return;
|
|
@@ -2798,6 +2836,7 @@ var HomeComIntegrationManager = class {
|
|
|
2798
2836
|
#makeClient;
|
|
2799
2837
|
#pollIntervalMs;
|
|
2800
2838
|
#onGatewayChosen;
|
|
2839
|
+
#onAuthFailed;
|
|
2801
2840
|
#gateways = [];
|
|
2802
2841
|
#client = null;
|
|
2803
2842
|
#gatewayId = null;
|
|
@@ -2816,6 +2855,7 @@ var HomeComIntegrationManager = class {
|
|
|
2816
2855
|
const fetchFn = options.fetchFn;
|
|
2817
2856
|
const bridge = options.bridge;
|
|
2818
2857
|
this.#onGatewayChosen = options.onGatewayChosen ?? (() => void 0);
|
|
2858
|
+
this.#onAuthFailed = options.onAuthFailed ?? (() => void 0);
|
|
2819
2859
|
const onTokensRotated = async (tokens) => {
|
|
2820
2860
|
this.#connection = {
|
|
2821
2861
|
...this.#connection,
|
|
@@ -2884,7 +2924,9 @@ var HomeComIntegrationManager = class {
|
|
|
2884
2924
|
}, this.#pollIntervalMs);
|
|
2885
2925
|
} catch (err) {
|
|
2886
2926
|
this.#status = "error";
|
|
2887
|
-
|
|
2927
|
+
const authFailed = err instanceof HomeComAuthError;
|
|
2928
|
+
this.#error = authFailed ? "authentication failed — sign in again" : require_bosch_instances.errMsg(err);
|
|
2929
|
+
if (authFailed) this.#onAuthFailed(this.#id);
|
|
2888
2930
|
this.#client = null;
|
|
2889
2931
|
this.#surfaceSink.set(this.#id, null);
|
|
2890
2932
|
this.#onDisconnected(this.#id);
|
|
@@ -2916,6 +2958,7 @@ var HomeComIntegrationManager = class {
|
|
|
2916
2958
|
this.#surfaceSink.updateSnapshot(this.#id, snapshot);
|
|
2917
2959
|
this.#lastCheckedAt = Date.now();
|
|
2918
2960
|
} catch (err) {
|
|
2961
|
+
if (err instanceof HomeComAuthError) this.#onAuthFailed(this.#id);
|
|
2919
2962
|
this.#logger.warn("HomeCom poll failed", { meta: {
|
|
2920
2963
|
integrationId: this.#id,
|
|
2921
2964
|
error: require_bosch_instances.errMsg(err)
|
|
@@ -2950,6 +2993,7 @@ var HomeComClientRegistry = class {
|
|
|
2950
2993
|
#makeManager;
|
|
2951
2994
|
#onTokensRotated;
|
|
2952
2995
|
#onGatewayChosen;
|
|
2996
|
+
#onAuthFailed;
|
|
2953
2997
|
#entries = /* @__PURE__ */ new Map();
|
|
2954
2998
|
constructor(logger, deps = {}) {
|
|
2955
2999
|
this.#logger = logger;
|
|
@@ -2957,6 +3001,7 @@ var HomeComClientRegistry = class {
|
|
|
2957
3001
|
this.#onDisconnected = deps.onDisconnected ?? (() => void 0);
|
|
2958
3002
|
this.#onTokensRotated = deps.onTokensRotated ?? (async () => void 0);
|
|
2959
3003
|
this.#onGatewayChosen = deps.onGatewayChosen ?? (() => void 0);
|
|
3004
|
+
this.#onAuthFailed = deps.onAuthFailed ?? (() => void 0);
|
|
2960
3005
|
const fetchFn = deps.fetchFn;
|
|
2961
3006
|
const makeClient = deps.makeClient;
|
|
2962
3007
|
const bridge = deps.bridge;
|
|
@@ -2969,6 +3014,7 @@ var HomeComClientRegistry = class {
|
|
|
2969
3014
|
onDisconnected: opts.onDisconnected,
|
|
2970
3015
|
onTokensRotated: opts.onTokensRotated,
|
|
2971
3016
|
onGatewayChosen: opts.onGatewayChosen,
|
|
3017
|
+
onAuthFailed: opts.onAuthFailed,
|
|
2972
3018
|
surfaceSink: homeComConnections,
|
|
2973
3019
|
fetchFn,
|
|
2974
3020
|
makeClient,
|
|
@@ -3008,7 +3054,8 @@ var HomeComClientRegistry = class {
|
|
|
3008
3054
|
onConnected: (id) => this.#onConnected(id),
|
|
3009
3055
|
onDisconnected: (id) => this.#onDisconnected(id),
|
|
3010
3056
|
onTokensRotated: (tokens) => this.#onTokensRotated(integrationId, tokens),
|
|
3011
|
-
onGatewayChosen: (gatewayId) => this.#onGatewayChosen(integrationId, gatewayId)
|
|
3057
|
+
onGatewayChosen: (gatewayId) => this.#onGatewayChosen(integrationId, gatewayId),
|
|
3058
|
+
onAuthFailed: (id) => this.#onAuthFailed(id)
|
|
3012
3059
|
});
|
|
3013
3060
|
this.#entries.set(integrationId, {
|
|
3014
3061
|
manager,
|
|
@@ -3660,6 +3707,8 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
|
|
|
3660
3707
|
};
|
|
3661
3708
|
clients = null;
|
|
3662
3709
|
instances = null;
|
|
3710
|
+
sessionAlert = null;
|
|
3711
|
+
integrationNames = /* @__PURE__ */ new Map();
|
|
3663
3712
|
constructor() {
|
|
3664
3713
|
super({});
|
|
3665
3714
|
}
|
|
@@ -3686,12 +3735,20 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
|
|
|
3686
3735
|
const persistTokens = buildHomeComTokenPersister(persistDeps);
|
|
3687
3736
|
const persistGateway = buildHomeComGatewayPersister(persistDeps);
|
|
3688
3737
|
const bridge = await this.createBridge();
|
|
3738
|
+
const sessionAlert = createHomeComSessionAlert({
|
|
3739
|
+
logger: this.ctx.logger,
|
|
3740
|
+
getAlerts: () => this.ctx.api.alerts,
|
|
3741
|
+
nameOf: (id) => this.integrationNames.get(id) ?? id
|
|
3742
|
+
});
|
|
3743
|
+
this.sessionAlert = sessionAlert;
|
|
3689
3744
|
this.clients = new HomeComClientRegistry(this.ctx.logger, {
|
|
3745
|
+
onAuthFailed: (integrationId) => sessionAlert.authFailed(integrationId),
|
|
3690
3746
|
...bridge !== null ? { bridge } : {},
|
|
3691
3747
|
onTokensRotated: (integrationId, tokens) => persistTokens(integrationId, tokens),
|
|
3692
3748
|
onGatewayChosen: (integrationId, gatewayId) => void persistGateway(integrationId, gatewayId)
|
|
3693
3749
|
});
|
|
3694
3750
|
this.clients.setOnConnected((integrationId) => {
|
|
3751
|
+
sessionAlert.connected(integrationId);
|
|
3695
3752
|
this.setIntegrationDevicesOnline(integrationId, true);
|
|
3696
3753
|
});
|
|
3697
3754
|
this.clients.setOnDisconnected((integrationId) => {
|
|
@@ -3743,6 +3800,8 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
|
|
|
3743
3800
|
}
|
|
3744
3801
|
this.clients = null;
|
|
3745
3802
|
this.instances = null;
|
|
3803
|
+
this.sessionAlert?.dispose();
|
|
3804
|
+
this.sessionAlert = null;
|
|
3746
3805
|
await super.onShutdown();
|
|
3747
3806
|
}
|
|
3748
3807
|
/** The `homecom_alt` bridge on the embedded Python; null leaves k40/k30/icom on plain reads. */
|
|
@@ -3781,6 +3840,7 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
|
|
|
3781
3840
|
for (const integration of mine) try {
|
|
3782
3841
|
const connection = await homeComConnectionOf(this.requireInstances().instances, integration.id);
|
|
3783
3842
|
if (!connection) continue;
|
|
3843
|
+
this.integrationNames.set(integration.id, integration.name);
|
|
3784
3844
|
await reg.upsert(integration.id, integration.name, connection);
|
|
3785
3845
|
surviving.add(integration.id);
|
|
3786
3846
|
} catch (err) {
|
|
@@ -3791,6 +3851,10 @@ var BoschHomeComProviderAddon = class extends require_bosch_instances.BaseDevice
|
|
|
3791
3851
|
}
|
|
3792
3852
|
const vanished = reg.list().filter((id) => !surviving.has(id));
|
|
3793
3853
|
await reg.retain(surviving);
|
|
3854
|
+
for (const integrationId of vanished) {
|
|
3855
|
+
this.integrationNames.delete(integrationId);
|
|
3856
|
+
this.sessionAlert?.removed(integrationId);
|
|
3857
|
+
}
|
|
3794
3858
|
const deviceReg = this.ctx.kernel.deviceRegistry;
|
|
3795
3859
|
const deviceApi = this.ctx.kernel.devices;
|
|
3796
3860
|
if (deviceReg && deviceApi) for (const integrationId of vanished) await require_account_integration_offline.cascadeRemoveDevicesForIntegration({
|
package/dist/homecom/addon.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as loginFailureForAttempt, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, s as HOMECOM_REDIRECT_URI, t as setIntegrationDevicesOnline } from "../account-integration-offline-
|
|
1
|
+
import { $ as union, B as entryBody, F as RecordIntegrationInstances, G as _null, J as literal, K as array, L as customAction, P as waterHeaterCapability, Q as string, R as defineCustomActions, U as rowsDepsOver, W as _enum, X as object, Y as number, Z as record, a as BaseDevice, b as heatPumpControlCapability, f as climateControlCapability, h as deviceAdoptionCapability, i as testBoschInstance, it as EventCategory, k as registerPowerSwitch, l as SessionHealthTracker, n as boschRowsPorts, nt as DeviceType, o as BaseDeviceProvider, q as boolean, r as keepBodyKeys, rt as errMsg, t as boschRowsMigration, tt as DeviceRole, w as integrationInstancesCapability, x as heatPumpStatusCapability, y as gatewayDeviceName, z as defineEntryKind } from "../bosch-instances-g54r3Dus.mjs";
|
|
2
|
+
import { a as loginFailureForAttempt, i as createSignInAttemptStore, n as cascadeRemoveDevicesForIntegration, o as parseOAuthCallback, r as buildSignInGuideFields, s as HOMECOM_REDIRECT_URI, t as setIntegrationDevicesOnline } from "../account-integration-offline-xi6muNeM.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
@@ -525,6 +525,32 @@ var homeComActions = defineCustomActions({
|
|
|
525
525
|
})
|
|
526
526
|
});
|
|
527
527
|
//#endregion
|
|
528
|
+
//#region src/homecom/homecom-session-alert.ts
|
|
529
|
+
/** The standard session-lost alert for HomeCom; "Sign in again" opens the integration page. */
|
|
530
|
+
function createHomeComSessionAlert(deps) {
|
|
531
|
+
const tracker = new SessionHealthTracker({
|
|
532
|
+
kind: "homecom",
|
|
533
|
+
providerName: "Bosch HomeCom",
|
|
534
|
+
logger: deps.logger,
|
|
535
|
+
getAlerts: deps.getAlerts,
|
|
536
|
+
debounceMs: deps.debounceMs ?? 0
|
|
537
|
+
});
|
|
538
|
+
return {
|
|
539
|
+
authFailed: (integrationId) => tracker.lost(integrationId, {
|
|
540
|
+
integrationName: deps.nameOf(integrationId),
|
|
541
|
+
reason: "token-expired",
|
|
542
|
+
action: {
|
|
543
|
+
label: "Sign in again",
|
|
544
|
+
href: `/integrations/${encodeURIComponent(integrationId)}`,
|
|
545
|
+
navigation: "app"
|
|
546
|
+
}
|
|
547
|
+
}),
|
|
548
|
+
connected: (integrationId) => tracker.restored(integrationId),
|
|
549
|
+
removed: (integrationId) => tracker.forget(integrationId),
|
|
550
|
+
dispose: () => tracker.dispose()
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
//#endregion
|
|
528
554
|
//#region src/homecom/homecom-explore-action.ts
|
|
529
555
|
/** The action refused before it walked anything; `reason` says why. */
|
|
530
556
|
var HomeComExploreRefusedError = class extends Error {
|
|
@@ -1844,6 +1870,14 @@ function homeComResourceUrl(gatewayId, resourcePath) {
|
|
|
1844
1870
|
const path = resourcePath.startsWith("/") ? resourcePath : `/${resourcePath}`;
|
|
1845
1871
|
return `${HOMECOM_POINTT_API_ORIGIN}${HOMECOM_GATEWAYS_PATH}${encodeURIComponent(gatewayId)}/resource${path}`;
|
|
1846
1872
|
}
|
|
1873
|
+
async function isInvalidGrantBody(res) {
|
|
1874
|
+
try {
|
|
1875
|
+
const body = await res.json();
|
|
1876
|
+
return isRecord$1(body) && body["error"] === "invalid_grant";
|
|
1877
|
+
} catch {
|
|
1878
|
+
return false;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1847
1881
|
function createHomeComApiClient(config, gatewayId, deps = {}) {
|
|
1848
1882
|
const fetchFn = deps.fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
1849
1883
|
const refreshOnUnauthorized = deps.refreshOnUnauthorized ?? true;
|
|
@@ -1964,6 +1998,7 @@ function createHomeComApiClient(config, gatewayId, deps = {}) {
|
|
|
1964
1998
|
});
|
|
1965
1999
|
if (!res.ok) {
|
|
1966
2000
|
if (res.status === 401 || res.status === 403) throw new HomeComAuthError("refresh refused");
|
|
2001
|
+
if (res.status === 400 && await isInvalidGrantBody(res)) throw new HomeComAuthError("refresh refused");
|
|
1967
2002
|
throw new Error(`HomeCom token refresh failed: HTTP ${res.status}`);
|
|
1968
2003
|
}
|
|
1969
2004
|
const body = await res.json();
|
|
@@ -2383,7 +2418,10 @@ function buildSerialPatcher(deps) {
|
|
|
2383
2418
|
const run = async () => {
|
|
2384
2419
|
try {
|
|
2385
2420
|
const stored = await deps.read(integrationId);
|
|
2386
|
-
if (stored === null)
|
|
2421
|
+
if (stored === null) {
|
|
2422
|
+
deps.logger.warn(`HomeCom not persisting ${deps.what} — the integration record is gone`, { tags: { integrationId } });
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2387
2425
|
if (stored.locked) {
|
|
2388
2426
|
deps.logger.warn(`HomeCom not persisting ${deps.what} — stored secrets are locked`, { tags: { integrationId } });
|
|
2389
2427
|
return;
|
|
@@ -2797,6 +2835,7 @@ var HomeComIntegrationManager = class {
|
|
|
2797
2835
|
#makeClient;
|
|
2798
2836
|
#pollIntervalMs;
|
|
2799
2837
|
#onGatewayChosen;
|
|
2838
|
+
#onAuthFailed;
|
|
2800
2839
|
#gateways = [];
|
|
2801
2840
|
#client = null;
|
|
2802
2841
|
#gatewayId = null;
|
|
@@ -2815,6 +2854,7 @@ var HomeComIntegrationManager = class {
|
|
|
2815
2854
|
const fetchFn = options.fetchFn;
|
|
2816
2855
|
const bridge = options.bridge;
|
|
2817
2856
|
this.#onGatewayChosen = options.onGatewayChosen ?? (() => void 0);
|
|
2857
|
+
this.#onAuthFailed = options.onAuthFailed ?? (() => void 0);
|
|
2818
2858
|
const onTokensRotated = async (tokens) => {
|
|
2819
2859
|
this.#connection = {
|
|
2820
2860
|
...this.#connection,
|
|
@@ -2883,7 +2923,9 @@ var HomeComIntegrationManager = class {
|
|
|
2883
2923
|
}, this.#pollIntervalMs);
|
|
2884
2924
|
} catch (err) {
|
|
2885
2925
|
this.#status = "error";
|
|
2886
|
-
|
|
2926
|
+
const authFailed = err instanceof HomeComAuthError;
|
|
2927
|
+
this.#error = authFailed ? "authentication failed — sign in again" : errMsg(err);
|
|
2928
|
+
if (authFailed) this.#onAuthFailed(this.#id);
|
|
2887
2929
|
this.#client = null;
|
|
2888
2930
|
this.#surfaceSink.set(this.#id, null);
|
|
2889
2931
|
this.#onDisconnected(this.#id);
|
|
@@ -2915,6 +2957,7 @@ var HomeComIntegrationManager = class {
|
|
|
2915
2957
|
this.#surfaceSink.updateSnapshot(this.#id, snapshot);
|
|
2916
2958
|
this.#lastCheckedAt = Date.now();
|
|
2917
2959
|
} catch (err) {
|
|
2960
|
+
if (err instanceof HomeComAuthError) this.#onAuthFailed(this.#id);
|
|
2918
2961
|
this.#logger.warn("HomeCom poll failed", { meta: {
|
|
2919
2962
|
integrationId: this.#id,
|
|
2920
2963
|
error: errMsg(err)
|
|
@@ -2949,6 +2992,7 @@ var HomeComClientRegistry = class {
|
|
|
2949
2992
|
#makeManager;
|
|
2950
2993
|
#onTokensRotated;
|
|
2951
2994
|
#onGatewayChosen;
|
|
2995
|
+
#onAuthFailed;
|
|
2952
2996
|
#entries = /* @__PURE__ */ new Map();
|
|
2953
2997
|
constructor(logger, deps = {}) {
|
|
2954
2998
|
this.#logger = logger;
|
|
@@ -2956,6 +3000,7 @@ var HomeComClientRegistry = class {
|
|
|
2956
3000
|
this.#onDisconnected = deps.onDisconnected ?? (() => void 0);
|
|
2957
3001
|
this.#onTokensRotated = deps.onTokensRotated ?? (async () => void 0);
|
|
2958
3002
|
this.#onGatewayChosen = deps.onGatewayChosen ?? (() => void 0);
|
|
3003
|
+
this.#onAuthFailed = deps.onAuthFailed ?? (() => void 0);
|
|
2959
3004
|
const fetchFn = deps.fetchFn;
|
|
2960
3005
|
const makeClient = deps.makeClient;
|
|
2961
3006
|
const bridge = deps.bridge;
|
|
@@ -2968,6 +3013,7 @@ var HomeComClientRegistry = class {
|
|
|
2968
3013
|
onDisconnected: opts.onDisconnected,
|
|
2969
3014
|
onTokensRotated: opts.onTokensRotated,
|
|
2970
3015
|
onGatewayChosen: opts.onGatewayChosen,
|
|
3016
|
+
onAuthFailed: opts.onAuthFailed,
|
|
2971
3017
|
surfaceSink: homeComConnections,
|
|
2972
3018
|
fetchFn,
|
|
2973
3019
|
makeClient,
|
|
@@ -3007,7 +3053,8 @@ var HomeComClientRegistry = class {
|
|
|
3007
3053
|
onConnected: (id) => this.#onConnected(id),
|
|
3008
3054
|
onDisconnected: (id) => this.#onDisconnected(id),
|
|
3009
3055
|
onTokensRotated: (tokens) => this.#onTokensRotated(integrationId, tokens),
|
|
3010
|
-
onGatewayChosen: (gatewayId) => this.#onGatewayChosen(integrationId, gatewayId)
|
|
3056
|
+
onGatewayChosen: (gatewayId) => this.#onGatewayChosen(integrationId, gatewayId),
|
|
3057
|
+
onAuthFailed: (id) => this.#onAuthFailed(id)
|
|
3011
3058
|
});
|
|
3012
3059
|
this.#entries.set(integrationId, {
|
|
3013
3060
|
manager,
|
|
@@ -3659,6 +3706,8 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
|
|
|
3659
3706
|
};
|
|
3660
3707
|
clients = null;
|
|
3661
3708
|
instances = null;
|
|
3709
|
+
sessionAlert = null;
|
|
3710
|
+
integrationNames = /* @__PURE__ */ new Map();
|
|
3662
3711
|
constructor() {
|
|
3663
3712
|
super({});
|
|
3664
3713
|
}
|
|
@@ -3685,12 +3734,20 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
|
|
|
3685
3734
|
const persistTokens = buildHomeComTokenPersister(persistDeps);
|
|
3686
3735
|
const persistGateway = buildHomeComGatewayPersister(persistDeps);
|
|
3687
3736
|
const bridge = await this.createBridge();
|
|
3737
|
+
const sessionAlert = createHomeComSessionAlert({
|
|
3738
|
+
logger: this.ctx.logger,
|
|
3739
|
+
getAlerts: () => this.ctx.api.alerts,
|
|
3740
|
+
nameOf: (id) => this.integrationNames.get(id) ?? id
|
|
3741
|
+
});
|
|
3742
|
+
this.sessionAlert = sessionAlert;
|
|
3688
3743
|
this.clients = new HomeComClientRegistry(this.ctx.logger, {
|
|
3744
|
+
onAuthFailed: (integrationId) => sessionAlert.authFailed(integrationId),
|
|
3689
3745
|
...bridge !== null ? { bridge } : {},
|
|
3690
3746
|
onTokensRotated: (integrationId, tokens) => persistTokens(integrationId, tokens),
|
|
3691
3747
|
onGatewayChosen: (integrationId, gatewayId) => void persistGateway(integrationId, gatewayId)
|
|
3692
3748
|
});
|
|
3693
3749
|
this.clients.setOnConnected((integrationId) => {
|
|
3750
|
+
sessionAlert.connected(integrationId);
|
|
3694
3751
|
this.setIntegrationDevicesOnline(integrationId, true);
|
|
3695
3752
|
});
|
|
3696
3753
|
this.clients.setOnDisconnected((integrationId) => {
|
|
@@ -3742,6 +3799,8 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
|
|
|
3742
3799
|
}
|
|
3743
3800
|
this.clients = null;
|
|
3744
3801
|
this.instances = null;
|
|
3802
|
+
this.sessionAlert?.dispose();
|
|
3803
|
+
this.sessionAlert = null;
|
|
3745
3804
|
await super.onShutdown();
|
|
3746
3805
|
}
|
|
3747
3806
|
/** The `homecom_alt` bridge on the embedded Python; null leaves k40/k30/icom on plain reads. */
|
|
@@ -3780,6 +3839,7 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
|
|
|
3780
3839
|
for (const integration of mine) try {
|
|
3781
3840
|
const connection = await homeComConnectionOf(this.requireInstances().instances, integration.id);
|
|
3782
3841
|
if (!connection) continue;
|
|
3842
|
+
this.integrationNames.set(integration.id, integration.name);
|
|
3783
3843
|
await reg.upsert(integration.id, integration.name, connection);
|
|
3784
3844
|
surviving.add(integration.id);
|
|
3785
3845
|
} catch (err) {
|
|
@@ -3790,6 +3850,10 @@ var BoschHomeComProviderAddon = class extends BaseDeviceProvider {
|
|
|
3790
3850
|
}
|
|
3791
3851
|
const vanished = reg.list().filter((id) => !surviving.has(id));
|
|
3792
3852
|
await reg.retain(surviving);
|
|
3853
|
+
for (const integrationId of vanished) {
|
|
3854
|
+
this.integrationNames.delete(integrationId);
|
|
3855
|
+
this.sessionAlert?.removed(integrationId);
|
|
3856
|
+
}
|
|
3793
3857
|
const deviceReg = this.ctx.kernel.deviceRegistry;
|
|
3794
3858
|
const deviceApi = this.ctx.kernel.devices;
|
|
3795
3859
|
if (deviceReg && deviceApi) for (const integrationId of vanished) await cascadeRemoveDevicesForIntegration({
|
package/dist/shc/addon.js
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
//#region \0rolldown/runtime.js
|
|
3
3
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
4
4
|
//#endregion
|
|
5
|
-
const require_bosch_instances = require("../bosch-instances-
|
|
5
|
+
const require_bosch_instances = require("../bosch-instances-DaWS-s0M.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");
|
package/dist/shc/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as entryBody, F as RecordIntegrationInstances, J as literal, K as array, L as customAction, M as switchCapability, N as temperatureSensorCapability, Q as string, R as defineCustomActions, S as heatingValveCapability, U as rowsDepsOver, W as _enum, X as object, Y as number, a as BaseDevice, f as climateControlCapability, h as deviceAdoptionCapability, i as testBoschInstance, it as EventCategory, k as registerPowerSwitch, m as defaultIntegrationName, n as boschRowsPorts, nt as DeviceType, o as BaseDeviceProvider, r as keepBodyKeys, rt as errMsg, t as boschRowsMigration, tt as DeviceRole, u as batteryCapability, w as integrationInstancesCapability, y as gatewayDeviceName, z as defineEntryKind } from "../bosch-instances-g54r3Dus.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { request } from "node:https";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-bosch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.55",
|
|
4
4
|
"description": "Bosch smart-home device-provider addons for CamStack — SHC, Home Connect, and HomeCom cloud integrations (scaffold)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
}
|
|
143
143
|
],
|
|
144
144
|
"requires": {
|
|
145
|
-
"server": ">=1.2.
|
|
145
|
+
"server": ">=1.2.879"
|
|
146
146
|
}
|
|
147
147
|
},
|
|
148
148
|
"files": [
|