@camstack/addon-provider-homeassistant 1.2.173 → 1.2.602
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/addon.js +205 -147
- package/dist/addon.mjs +187 -147
- package/dist/{dist-CSIrSsu7.mjs → dist-Dcum8auE.mjs} +1452 -101
- package/dist/{dist-DTt9hwTQ.js → dist-xuu2eG_W.js} +1481 -100
- package/dist/ha-export/ha-export.addon.js +5 -1
- package/dist/ha-export/ha-export.addon.mjs +5 -1
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-xuu2eG_W.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_zlib = require("node:zlib");
|
|
5
5
|
//#region src/ha-admin-link.ts
|
|
@@ -6783,6 +6783,54 @@ function createHaIconRouteProvider() {
|
|
|
6783
6783
|
}]);
|
|
6784
6784
|
}
|
|
6785
6785
|
//#endregion
|
|
6786
|
+
//#region src/broker-record-kinds.ts
|
|
6787
|
+
/**
|
|
6788
|
+
* Broker entry kind (B2): credentials live in records; integrations keep brokerId.
|
|
6789
|
+
*/
|
|
6790
|
+
var HA_BROKERS_KIND = "brokers";
|
|
6791
|
+
var HA_BROKERS_OWNER = "provider-homeassistant";
|
|
6792
|
+
var HaBrokerBodySchema = require_dist.entryBody({
|
|
6793
|
+
auth: HaBrokerEntrySchema.shape.auth,
|
|
6794
|
+
integrationId: require_dist.string().optional()
|
|
6795
|
+
});
|
|
6796
|
+
var haBrokersEntryKind = require_dist.defineEntryKind(HA_BROKERS_KIND, {
|
|
6797
|
+
title: "Home Assistant brokers",
|
|
6798
|
+
schema: HaBrokerBodySchema,
|
|
6799
|
+
writeTrigger: "an operator adds, edits or removes a Home Assistant broker connection",
|
|
6800
|
+
adoptsFrom: require_dist.settingsBrokersAdoptsFrom(HA_BROKERS_OWNER)
|
|
6801
|
+
});
|
|
6802
|
+
//#endregion
|
|
6803
|
+
//#region src/record-kinds.ts
|
|
6804
|
+
/**
|
|
6805
|
+
* Body of one stored HA notification target. The record id IS the target id
|
|
6806
|
+
* and is not repeated in the body.
|
|
6807
|
+
* No `.meta({ secret: true })` fields: HA notify targets carry no standalone
|
|
6808
|
+
* credential — delivery reuses the broker WebSocket connection (the token
|
|
6809
|
+
* lives in the broker config, not in the target).
|
|
6810
|
+
*/
|
|
6811
|
+
var HaTargetBodySchema = require_dist.TargetSchema.omit({ id: true });
|
|
6812
|
+
var haRecordKinds = require_dist.defineRecordKinds({
|
|
6813
|
+
/**
|
|
6814
|
+
* One row per configured Home Assistant push target. Operator-managed via the
|
|
6815
|
+
* notification-output cap CRUD; no TTL.
|
|
6816
|
+
* The legacy collection name is `provider-homeassistant:ha-notification-targets`.
|
|
6817
|
+
*/
|
|
6818
|
+
"ha-notification-targets": {
|
|
6819
|
+
schema: HaTargetBodySchema,
|
|
6820
|
+
class: "config",
|
|
6821
|
+
writeTrigger: "an operator creates, updates, enables/disables or deletes a HA notification target",
|
|
6822
|
+
device: "none",
|
|
6823
|
+
at: "none",
|
|
6824
|
+
retention: { none: "a row is removed only on an explicit operator delete; bounded by the number of HA notify targets the operator configures" },
|
|
6825
|
+
adoptsFrom: "provider-homeassistant:ha-notification-targets",
|
|
6826
|
+
entry: { title: "Home Assistant notification targets" }
|
|
6827
|
+
} });
|
|
6828
|
+
/** All record kinds this addon declares (targets + B2 broker entries). */
|
|
6829
|
+
var haAllRecordKinds = {
|
|
6830
|
+
...haRecordKinds,
|
|
6831
|
+
[haBrokersEntryKind.name]: haBrokersEntryKind
|
|
6832
|
+
};
|
|
6833
|
+
//#endregion
|
|
6786
6834
|
//#region src/ha-notification-output.ts
|
|
6787
6835
|
/**
|
|
6788
6836
|
* `homeassistant` notification-output kind — hosted BY the HA provider addon.
|
|
@@ -6816,8 +6864,6 @@ function createHaIconRouteProvider() {
|
|
|
6816
6864
|
*/
|
|
6817
6865
|
/** The single kind this provider contributes to the shared catalog. */
|
|
6818
6866
|
var HA_NOTIFICATION_KIND = "homeassistant";
|
|
6819
|
-
/** addonId-namespaced settings-store collection holding HA notify targets. */
|
|
6820
|
-
var HA_TARGETS_COLLECTION = "provider-homeassistant:ha-notification-targets";
|
|
6821
6867
|
function haConfigSchema() {
|
|
6822
6868
|
return { sections: [{
|
|
6823
6869
|
id: "connection",
|
|
@@ -6997,71 +7043,59 @@ function parseNotifyServices(result, brokerId) {
|
|
|
6997
7043
|
}
|
|
6998
7044
|
}));
|
|
6999
7045
|
}
|
|
7000
|
-
/**
|
|
7001
|
-
*
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
return parsed.success ? parsed.data : null;
|
|
7013
|
-
}
|
|
7014
|
-
function targetToData(target) {
|
|
7015
|
-
return {
|
|
7016
|
-
name: target.name,
|
|
7017
|
-
kind: target.kind,
|
|
7018
|
-
addonId: target.addonId,
|
|
7019
|
-
enabled: target.enabled,
|
|
7020
|
-
config: target.config
|
|
7021
|
-
};
|
|
7022
|
-
}
|
|
7023
|
-
/** CRUD over one settings-store collection of `homeassistant` notify targets. */
|
|
7024
|
-
var HaTargetStore = class {
|
|
7025
|
-
store;
|
|
7026
|
-
collection;
|
|
7027
|
-
constructor(store, collection = HA_TARGETS_COLLECTION) {
|
|
7028
|
-
this.store = store;
|
|
7029
|
-
this.collection = collection;
|
|
7046
|
+
/**
|
|
7047
|
+
* CRUD over the `ha-notification-targets` record kind.
|
|
7048
|
+
*
|
|
7049
|
+
* `HaTargetStore.of(records)` is the production factory; the test helper
|
|
7050
|
+
* (`makeFakeHaRecords`) supplies a fake transport so nothing hits SQLite.
|
|
7051
|
+
* No `init()` method: kinds are declared at addon boot via
|
|
7052
|
+
* `ctx.records.declare(haRecordKinds)`.
|
|
7053
|
+
*/
|
|
7054
|
+
var HaTargetStore = class HaTargetStore {
|
|
7055
|
+
kind;
|
|
7056
|
+
constructor(kind) {
|
|
7057
|
+
this.kind = kind;
|
|
7030
7058
|
}
|
|
7031
|
-
/**
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
async init() {
|
|
7035
|
-
await this.store.declareCollection(this.collection, KV_BLOB_COLUMNS);
|
|
7059
|
+
/** Factory: build from a declared `RecordsAccess` (after `ctx.records.declare`). */
|
|
7060
|
+
static of(records) {
|
|
7061
|
+
return new HaTargetStore(records.kind(haRecordKinds["ha-notification-targets"]));
|
|
7036
7062
|
}
|
|
7037
7063
|
async list() {
|
|
7038
|
-
const
|
|
7064
|
+
const page = await this.kind.query({ limit: 1e3 });
|
|
7039
7065
|
const out = [];
|
|
7040
|
-
for (const
|
|
7041
|
-
const
|
|
7042
|
-
|
|
7066
|
+
for (const record of page.records) {
|
|
7067
|
+
const parsed = require_dist.TargetSchema.safeParse({
|
|
7068
|
+
id: record.id,
|
|
7069
|
+
...record.data
|
|
7070
|
+
});
|
|
7071
|
+
if (parsed.success) out.push(parsed.data);
|
|
7043
7072
|
}
|
|
7044
7073
|
return out;
|
|
7045
7074
|
}
|
|
7046
7075
|
async getById(id) {
|
|
7047
|
-
const row =
|
|
7048
|
-
|
|
7076
|
+
const row = await this.kind.get(id);
|
|
7077
|
+
if (row === null) return null;
|
|
7078
|
+
const parsed = require_dist.TargetSchema.safeParse({
|
|
7079
|
+
id: row.id,
|
|
7080
|
+
...row.data
|
|
7081
|
+
});
|
|
7082
|
+
return parsed.success ? parsed.data : null;
|
|
7049
7083
|
}
|
|
7050
7084
|
async upsert(target) {
|
|
7051
|
-
const
|
|
7052
|
-
const
|
|
7053
|
-
if (
|
|
7054
|
-
|
|
7055
|
-
id
|
|
7056
|
-
data
|
|
7085
|
+
const { id, ...rest } = target;
|
|
7086
|
+
const parsed = haRecordKinds["ha-notification-targets"].schema.safeParse(rest);
|
|
7087
|
+
if (!parsed.success) throw new Error(`invalid HA target '${id}': ${parsed.error.message}`);
|
|
7088
|
+
await this.kind.put({
|
|
7089
|
+
id,
|
|
7090
|
+
data: parsed.data
|
|
7057
7091
|
});
|
|
7058
7092
|
}
|
|
7059
7093
|
async delete(id) {
|
|
7060
|
-
await this.
|
|
7094
|
+
await this.kind.delete(id);
|
|
7061
7095
|
}
|
|
7062
7096
|
async setEnabled(id, enabled) {
|
|
7063
7097
|
const target = await this.getById(id);
|
|
7064
|
-
if (
|
|
7098
|
+
if (target === null) return null;
|
|
7065
7099
|
const next = {
|
|
7066
7100
|
...target,
|
|
7067
7101
|
enabled
|
|
@@ -7070,78 +7104,6 @@ var HaTargetStore = class {
|
|
|
7070
7104
|
return next;
|
|
7071
7105
|
}
|
|
7072
7106
|
};
|
|
7073
|
-
/** Adapt the tRPC-shaped `settings-store` cap client to the narrow port. */
|
|
7074
|
-
function createApiHaSettingsStorePort(api) {
|
|
7075
|
-
return {
|
|
7076
|
-
query: async (collection) => {
|
|
7077
|
-
return (await api.settingsStore.query.query({ collection })).map((r) => ({
|
|
7078
|
-
id: r.id,
|
|
7079
|
-
data: r.data
|
|
7080
|
-
}));
|
|
7081
|
-
},
|
|
7082
|
-
insert: async (collection, record) => {
|
|
7083
|
-
await api.settingsStore.insert.mutate({
|
|
7084
|
-
collection,
|
|
7085
|
-
record: {
|
|
7086
|
-
id: record.id,
|
|
7087
|
-
data: { ...record.data }
|
|
7088
|
-
}
|
|
7089
|
-
});
|
|
7090
|
-
},
|
|
7091
|
-
update: async (collection, id, data) => {
|
|
7092
|
-
await api.settingsStore.update.mutate({
|
|
7093
|
-
collection,
|
|
7094
|
-
id,
|
|
7095
|
-
data
|
|
7096
|
-
});
|
|
7097
|
-
},
|
|
7098
|
-
remove: async (collection, id) => {
|
|
7099
|
-
await api.settingsStore.delete.mutate({
|
|
7100
|
-
collection,
|
|
7101
|
-
key: id
|
|
7102
|
-
});
|
|
7103
|
-
},
|
|
7104
|
-
declareCollection: async (collection, columns) => {
|
|
7105
|
-
await api.settingsStore.declareCollection.mutate({
|
|
7106
|
-
collection,
|
|
7107
|
-
columns: columns.map((c) => ({ ...c }))
|
|
7108
|
-
});
|
|
7109
|
-
}
|
|
7110
|
-
};
|
|
7111
|
-
}
|
|
7112
|
-
/** In-memory port — a resilient fallback when no `api` is wired. */
|
|
7113
|
-
function createMemoryHaSettingsStorePort() {
|
|
7114
|
-
const collections = /* @__PURE__ */ new Map();
|
|
7115
|
-
const bucket = (collection) => {
|
|
7116
|
-
let map = collections.get(collection);
|
|
7117
|
-
if (!map) {
|
|
7118
|
-
map = /* @__PURE__ */ new Map();
|
|
7119
|
-
collections.set(collection, map);
|
|
7120
|
-
}
|
|
7121
|
-
return map;
|
|
7122
|
-
};
|
|
7123
|
-
return {
|
|
7124
|
-
query: async (collection) => [...bucket(collection).values()],
|
|
7125
|
-
insert: async (collection, record) => {
|
|
7126
|
-
bucket(collection).set(record.id, {
|
|
7127
|
-
id: record.id,
|
|
7128
|
-
data: { ...record.data }
|
|
7129
|
-
});
|
|
7130
|
-
},
|
|
7131
|
-
update: async (collection, id, data) => {
|
|
7132
|
-
bucket(collection).set(id, {
|
|
7133
|
-
id,
|
|
7134
|
-
data: { ...data }
|
|
7135
|
-
});
|
|
7136
|
-
},
|
|
7137
|
-
remove: async (collection, id) => {
|
|
7138
|
-
bucket(collection).delete(id);
|
|
7139
|
-
},
|
|
7140
|
-
declareCollection: async (collection) => {
|
|
7141
|
-
bucket(collection);
|
|
7142
|
-
}
|
|
7143
|
-
};
|
|
7144
|
-
}
|
|
7145
7107
|
/** The canned notification `testTarget` sends when the caller omits a sample. */
|
|
7146
7108
|
function cannedNotification() {
|
|
7147
7109
|
return {
|
|
@@ -7291,6 +7253,78 @@ function createHaNotificationOutputProvider(deps) {
|
|
|
7291
7253
|
};
|
|
7292
7254
|
}
|
|
7293
7255
|
//#endregion
|
|
7256
|
+
//#region src/ha-broker-store.ts
|
|
7257
|
+
/**
|
|
7258
|
+
* CRUD for HA brokers over the `brokers` entry record kind (B2).
|
|
7259
|
+
*/
|
|
7260
|
+
function rowToEntry(id, data) {
|
|
7261
|
+
const parsed = HaBrokerEntrySchema.safeParse({
|
|
7262
|
+
id,
|
|
7263
|
+
name: data.name,
|
|
7264
|
+
auth: data.auth,
|
|
7265
|
+
integrationId: data.integrationId
|
|
7266
|
+
});
|
|
7267
|
+
return parsed.success ? parsed.data : null;
|
|
7268
|
+
}
|
|
7269
|
+
var HaBrokerStore = class HaBrokerStore {
|
|
7270
|
+
kind;
|
|
7271
|
+
constructor(kind) {
|
|
7272
|
+
this.kind = kind;
|
|
7273
|
+
}
|
|
7274
|
+
static of(records) {
|
|
7275
|
+
return new HaBrokerStore(records.kind(haBrokersEntryKind));
|
|
7276
|
+
}
|
|
7277
|
+
async listResolved() {
|
|
7278
|
+
const page = await this.kind.query({ limit: 1e3 });
|
|
7279
|
+
const out = [];
|
|
7280
|
+
for (const record of page.records) {
|
|
7281
|
+
let data = record.data;
|
|
7282
|
+
try {
|
|
7283
|
+
const resolved = await this.kind.getResolved(record.id);
|
|
7284
|
+
if (resolved !== null) data = resolved.data;
|
|
7285
|
+
} catch (err) {
|
|
7286
|
+
if (!(err instanceof require_dist.RecordSecretUnavailableError)) throw err;
|
|
7287
|
+
}
|
|
7288
|
+
const entry = rowToEntry(record.id, data);
|
|
7289
|
+
if (entry !== null) out.push(entry);
|
|
7290
|
+
}
|
|
7291
|
+
return out;
|
|
7292
|
+
}
|
|
7293
|
+
async getById(id) {
|
|
7294
|
+
try {
|
|
7295
|
+
const row = await this.kind.getResolved(id);
|
|
7296
|
+
if (row === null) return null;
|
|
7297
|
+
return rowToEntry(row.id, row.data);
|
|
7298
|
+
} catch (err) {
|
|
7299
|
+
if (err instanceof require_dist.RecordSecretUnavailableError) return null;
|
|
7300
|
+
throw err;
|
|
7301
|
+
}
|
|
7302
|
+
}
|
|
7303
|
+
async upsert(entry) {
|
|
7304
|
+
const { id, name, auth, integrationId } = entry;
|
|
7305
|
+
const body = {
|
|
7306
|
+
name,
|
|
7307
|
+
auth,
|
|
7308
|
+
...integrationId === void 0 ? {} : { integrationId }
|
|
7309
|
+
};
|
|
7310
|
+
const parsed = haBrokersEntryKind.schema.safeParse(body);
|
|
7311
|
+
if (!parsed.success) throw new Error(`invalid HA broker '${id}': ${parsed.error.message}`);
|
|
7312
|
+
await this.kind.put({
|
|
7313
|
+
id,
|
|
7314
|
+
data: parsed.data
|
|
7315
|
+
});
|
|
7316
|
+
}
|
|
7317
|
+
async delete(id) {
|
|
7318
|
+
await this.kind.delete(id);
|
|
7319
|
+
}
|
|
7320
|
+
async replaceAll(entries) {
|
|
7321
|
+
const page = await this.kind.query({ limit: 1e3 });
|
|
7322
|
+
const nextIds = new Set(entries.map((e) => e.id));
|
|
7323
|
+
for (const row of page.records) if (!nextIds.has(row.id)) await this.kind.delete(row.id);
|
|
7324
|
+
for (const entry of entries) await this.upsert(entry);
|
|
7325
|
+
}
|
|
7326
|
+
};
|
|
7327
|
+
//#endregion
|
|
7294
7328
|
//#region src/ha-calendar-source.ts
|
|
7295
7329
|
function isCalendarEntity(entityId) {
|
|
7296
7330
|
return entityId.startsWith("calendar.");
|
|
@@ -7951,6 +7985,9 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
7951
7985
|
return `ha:${String(config?.["brokerId"] ?? "unknown")}:dev:${String(config?.["haDeviceId"] ?? Date.now())}`;
|
|
7952
7986
|
}
|
|
7953
7987
|
registry = null;
|
|
7988
|
+
brokerStore = null;
|
|
7989
|
+
/** Runtime broker rows (records when B2 is live, else settings). */
|
|
7990
|
+
activeBrokers = [];
|
|
7954
7991
|
/** Periodic re-sync sweep handle (cleared on shutdown). */
|
|
7955
7992
|
resyncTimer = null;
|
|
7956
7993
|
/** `brokerId → aggregator deviceId` cache for the per-broker generic
|
|
@@ -7964,6 +8001,11 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
7964
8001
|
super({ ...DEFAULT_CONFIG });
|
|
7965
8002
|
}
|
|
7966
8003
|
async onInitialize() {
|
|
8004
|
+
const records = this.ctx.records;
|
|
8005
|
+
if (records === void 0) throw new Error("provider-homeassistant: ctx.records is required (hub-only addon)");
|
|
8006
|
+
await records.declare(haAllRecordKinds);
|
|
8007
|
+
this.brokerStore = HaBrokerStore.of(records);
|
|
8008
|
+
this.activeBrokers = await this.loadPersistedBrokers();
|
|
7967
8009
|
this.registry = new HaBrokerRegistry(this.ctx.logger, this.ctx.eventBus);
|
|
7968
8010
|
this.registry.setOnBrokerConnected((brokerId) => {
|
|
7969
8011
|
this.reconcileBroker(brokerId);
|
|
@@ -7974,11 +8016,11 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
7974
8016
|
this.registry.setOnBusEvent((brokerId, ev) => {
|
|
7975
8017
|
this.routeBusEvent(brokerId, ev);
|
|
7976
8018
|
});
|
|
7977
|
-
await this.registry.restore(this.
|
|
8019
|
+
await this.registry.restore(this.activeBrokers);
|
|
7978
8020
|
this.resyncTimer = setInterval(() => {
|
|
7979
8021
|
this.reconcileAllConnectedBrokers();
|
|
7980
8022
|
}, HaProviderAddon.RESYNC_INTERVAL_MS);
|
|
7981
|
-
this.ctx.logger.info("ha provider initialised", { meta: { brokerCount: this.
|
|
8023
|
+
this.ctx.logger.info("ha provider initialised", { meta: { brokerCount: this.activeBrokers.length } });
|
|
7982
8024
|
await this.reconcileIntegrationsToBrokers();
|
|
7983
8025
|
this.subscribeIntegrationLifecycle();
|
|
7984
8026
|
return [
|
|
@@ -8009,11 +8051,9 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8009
8051
|
];
|
|
8010
8052
|
}
|
|
8011
8053
|
async buildNotificationOutputProvider() {
|
|
8012
|
-
const
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
const store = new HaTargetStore(port);
|
|
8016
|
-
await store.init();
|
|
8054
|
+
const records = this.ctx.records;
|
|
8055
|
+
if (records === void 0) throw new Error("ha notification-output: ctx.records is required (hub-only addon)");
|
|
8056
|
+
const store = HaTargetStore.of(records);
|
|
8017
8057
|
return createHaNotificationOutputProvider({
|
|
8018
8058
|
addonId: this.ctx.id,
|
|
8019
8059
|
iconUrl: HA_NOTIFICATION_ICON_URL,
|
|
@@ -8030,7 +8070,7 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8030
8070
|
if (!manager) throw new Error(`ha-broker '${brokerId}' not found`);
|
|
8031
8071
|
return manager.sendMessage({ type: "get_services" });
|
|
8032
8072
|
},
|
|
8033
|
-
listBrokerIds: () => this.
|
|
8073
|
+
listBrokerIds: () => this.activeBrokers.map((b) => b.id),
|
|
8034
8074
|
logger: this.ctx.logger.child("notification-output")
|
|
8035
8075
|
});
|
|
8036
8076
|
}
|
|
@@ -8091,7 +8131,7 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8091
8131
|
const settings = await api.integrations.getSettings.query({ id: integration.id });
|
|
8092
8132
|
const brokerId = typeof settings["brokerId"] === "string" ? settings["brokerId"] : null;
|
|
8093
8133
|
if (!brokerId) continue;
|
|
8094
|
-
if (!this.
|
|
8134
|
+
if (!this.activeBrokers.find((b) => b.id === brokerId)) {
|
|
8095
8135
|
this.ctx.logger.warn("integration→broker: linked broker not found", { meta: {
|
|
8096
8136
|
integrationId: integration.id,
|
|
8097
8137
|
brokerId
|
|
@@ -8104,11 +8144,11 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8104
8144
|
brokerId
|
|
8105
8145
|
});
|
|
8106
8146
|
}
|
|
8107
|
-
const linkedBrokers = linkBrokersToIntegrations(this.
|
|
8108
|
-
if (linkedBrokers.some((b, i) => b !== this.
|
|
8109
|
-
const orphans = computeBrokerCleanup(this.
|
|
8147
|
+
const linkedBrokers = linkBrokersToIntegrations(this.activeBrokers, integrationsWithBrokerId);
|
|
8148
|
+
if (linkedBrokers.some((b, i) => b !== this.activeBrokers[i])) await this.persistBrokerEntries(linkedBrokers);
|
|
8149
|
+
const orphans = computeBrokerCleanup(this.activeBrokers, survivingIntegrationIds);
|
|
8110
8150
|
this.ctx.logger.info("integration→broker reconcile", { meta: {
|
|
8111
|
-
brokerCount: this.
|
|
8151
|
+
brokerCount: this.activeBrokers.length,
|
|
8112
8152
|
integrationCount: haIntegrations.length,
|
|
8113
8153
|
orphans: orphans.length
|
|
8114
8154
|
} });
|
|
@@ -8205,7 +8245,8 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8205
8245
|
async onConfigChanged() {
|
|
8206
8246
|
const reg = this.registry;
|
|
8207
8247
|
if (!reg) return;
|
|
8208
|
-
|
|
8248
|
+
this.activeBrokers = await this.loadPersistedBrokers();
|
|
8249
|
+
const persisted = this.activeBrokers;
|
|
8209
8250
|
const liveIds = new Set(reg.list().map((b) => b.id));
|
|
8210
8251
|
const persistedIds = new Set(persisted.map((e) => e.id));
|
|
8211
8252
|
for (const liveId of liveIds) if (!persistedIds.has(liveId)) try {
|
|
@@ -8243,7 +8284,7 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8243
8284
|
...b,
|
|
8244
8285
|
id: created.id
|
|
8245
8286
|
} : b);
|
|
8246
|
-
await this.
|
|
8287
|
+
await this.persistBrokerEntries(next);
|
|
8247
8288
|
}
|
|
8248
8289
|
} catch (err) {
|
|
8249
8290
|
this.ctx.logger.warn("ha onConfigChanged: failed to start new broker", { meta: {
|
|
@@ -8253,9 +8294,26 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8253
8294
|
}
|
|
8254
8295
|
}
|
|
8255
8296
|
}
|
|
8297
|
+
async loadPersistedBrokers() {
|
|
8298
|
+
const store = this.brokerStore;
|
|
8299
|
+
if (store !== null) {
|
|
8300
|
+
const fromRecords = await store.listResolved();
|
|
8301
|
+
if (fromRecords.length > 0) return fromRecords;
|
|
8302
|
+
}
|
|
8303
|
+
return this.config.brokers;
|
|
8304
|
+
}
|
|
8305
|
+
async persistBrokerEntries(entries) {
|
|
8306
|
+
this.activeBrokers = [...entries];
|
|
8307
|
+
const store = this.brokerStore;
|
|
8308
|
+
if (store !== null) {
|
|
8309
|
+
await store.replaceAll(entries);
|
|
8310
|
+
return;
|
|
8311
|
+
}
|
|
8312
|
+
await this.updateGlobalSettings({ brokers: entries });
|
|
8313
|
+
}
|
|
8256
8314
|
buildBrokerProvider() {
|
|
8257
8315
|
const ownerAddonId = this.ctx.id;
|
|
8258
|
-
const owns = (id) => this.
|
|
8316
|
+
const owns = (id) => this.activeBrokers.some((b) => b.id === id);
|
|
8259
8317
|
return {
|
|
8260
8318
|
list: async ({ kind }) => {
|
|
8261
8319
|
if (kind && kind !== HA_KIND) return [];
|
|
@@ -8285,7 +8343,7 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8285
8343
|
brokerId: entry.id,
|
|
8286
8344
|
name
|
|
8287
8345
|
} });
|
|
8288
|
-
await this.
|
|
8346
|
+
await this.persistBrokerEntries([...this.activeBrokers, entry]);
|
|
8289
8347
|
return { id: entry.id };
|
|
8290
8348
|
},
|
|
8291
8349
|
remove: async ({ id }) => {
|
|
@@ -8300,8 +8358,8 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8300
8358
|
brokerId: id,
|
|
8301
8359
|
logger: this.ctx.logger
|
|
8302
8360
|
});
|
|
8303
|
-
const nextBrokers = this.
|
|
8304
|
-
await this.
|
|
8361
|
+
const nextBrokers = this.activeBrokers.filter((b) => b.id !== id);
|
|
8362
|
+
await this.persistBrokerEntries(nextBrokers);
|
|
8305
8363
|
},
|
|
8306
8364
|
testConnection: async ({ id }) => {
|
|
8307
8365
|
if (!owns(id)) return {
|
|
@@ -8323,18 +8381,18 @@ var HaProviderAddon = class HaProviderAddon extends require_dist.BaseDeviceProvi
|
|
|
8323
8381
|
};
|
|
8324
8382
|
},
|
|
8325
8383
|
getSettings: async ({ id }) => {
|
|
8326
|
-
const entry = this.
|
|
8384
|
+
const entry = this.activeBrokers.find((b) => b.id === id);
|
|
8327
8385
|
if (!entry) return null;
|
|
8328
8386
|
return authToSettings(entry.auth);
|
|
8329
8387
|
},
|
|
8330
8388
|
setSettings: async ({ id, settings }) => {
|
|
8331
8389
|
if (!owns(id)) return;
|
|
8332
8390
|
const entry = await this.requireRegistry().updateEntry(id, settings);
|
|
8333
|
-
const next = this.
|
|
8334
|
-
await this.
|
|
8391
|
+
const next = this.activeBrokers.map((b) => b.id === id ? entry : b);
|
|
8392
|
+
await this.persistBrokerEntries(next);
|
|
8335
8393
|
},
|
|
8336
8394
|
getBrokerConfig: async ({ id }) => {
|
|
8337
|
-
const entry = this.
|
|
8395
|
+
const entry = this.activeBrokers.find((b) => b.id === id);
|
|
8338
8396
|
if (!entry) return null;
|
|
8339
8397
|
return authToSettings(entry.auth);
|
|
8340
8398
|
},
|