@camstack/addon-provider-homeassistant 1.2.173 → 1.2.601

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as connectivityCapability, At as record, B as floodCapability, C as buildAddonRouteProvider, Ct as _enum, D as carbonMonoxideCapability, Dt as literal, E as calendarSourceCapability, Et as discriminatedUnion, F as deviceAdoptionCapability, Ft as EventCategory, G as lawnMowerControlCapability, H as humidifierCapability, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, M as controlCapability, Mt as union, N as coverCapability, Nt as unknown, O as climateControlCapability, Ot as number, P as deviceAdminLinkCapability, Pt as url, Q as numericSensorCapability, R as eventEmitterCapability, S as brokerCapability, T as buttonCapability, Tt as boolean, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as string, k as colorCapability, kt as object, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as array, x as brightnessCapability, xt as createEvent, y as bestLocationMatch, yt as errMsg, z as fanControlCapability } from "./dist-CSIrSsu7.mjs";
1
+ import { A as connectivityCapability, At as boolean, B as floodCapability, Bt as EventCategory, C as buildAddonRouteProvider, Ct as defineEntryKind, D as carbonMonoxideCapability, Dt as settingsBrokersAdoptsFrom, E as calendarSourceCapability, F as deviceAdoptionCapability, Ft as record, G as lawnMowerControlCapability, H as humidifierCapability, It as string, J as motionCapability, K as lockControlCapability, L as enumSensorCapability, Lt as union, M as controlCapability, Mt as literal, N as coverCapability, Nt as number, O as climateControlCapability, Ot as _enum, P as deviceAdminLinkCapability, Pt as object, Q as numericSensorCapability, R as eventEmitterCapability, Rt as unknown, S as brokerCapability, St as createEvent, T as buttonCapability, Tt as entryBody, U as humiditySensorCapability, V as gasCapability, W as imageCapability, X as notificationOutputCapability, Y as normalizeUnit, Z as notifierCapability, _ as automationControlCapability, _t as DeviceRole, at as scriptRunnerCapability, b as binaryCapability, ct as tamperCapability, d as TargetSchema, dt as vacuumControlCapability, et as parseAdminBase, f as accessoriesCapability, ft as valveCapability, g as ambientLightSensorCapability, gt as DeviceFeature, h as alarmPanelCapability, ht as weatherCapability, it as pressureSensorCapability, j as contactCapability, jt as discriminatedUnion, k as colorCapability, kt as array, lt as temperatureSensorCapability, m as airQualitySensorCapability, mt as waterHeaterCapability, n as BaseDevice, nt as prepareNotification, ot as smokeCapability, p as addonRoutesCapability, pt as vibrationCapability, q as mediaPlayerCapability, r as BaseDeviceProvider, rt as presenceCapability, s as EnumSensorDateTimeFormatSchema, st as switchCapability, tt as powerMeterCapability, ut as updateCapability, v as batteryCapability, vt as DeviceType, w as buildDeviceAdminUrl, wt as defineRecordKinds, x as brightnessCapability, xt as RecordSecretUnavailableError, y as bestLocationMatch, yt as errMsg, z as fanControlCapability, zt as url } from "./dist-BQLjEZxA.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { brotliCompressSync, deflateSync, gzipSync } from "node:zlib";
4
4
  //#region src/ha-admin-link.ts
@@ -6781,6 +6781,36 @@ function createHaIconRouteProvider() {
6781
6781
  }
6782
6782
  }]);
6783
6783
  }
6784
+ var haBrokersEntryKind = defineEntryKind("brokers", {
6785
+ title: "Home Assistant brokers",
6786
+ schema: entryBody({
6787
+ auth: HaBrokerEntrySchema.shape.auth,
6788
+ integrationId: string().optional()
6789
+ }),
6790
+ writeTrigger: "an operator adds, edits or removes a Home Assistant broker connection",
6791
+ adoptsFrom: settingsBrokersAdoptsFrom("provider-homeassistant")
6792
+ });
6793
+ var haRecordKinds = defineRecordKinds({
6794
+ /**
6795
+ * One row per configured Home Assistant push target. Operator-managed via the
6796
+ * notification-output cap CRUD; no TTL.
6797
+ * The legacy collection name is `provider-homeassistant:ha-notification-targets`.
6798
+ */
6799
+ "ha-notification-targets": {
6800
+ schema: TargetSchema.omit({ id: true }),
6801
+ class: "config",
6802
+ writeTrigger: "an operator creates, updates, enables/disables or deletes a HA notification target",
6803
+ device: "none",
6804
+ at: "none",
6805
+ retention: { none: "a row is removed only on an explicit operator delete; bounded by the number of HA notify targets the operator configures" },
6806
+ adoptsFrom: "provider-homeassistant:ha-notification-targets",
6807
+ entry: { title: "Home Assistant notification targets" }
6808
+ } });
6809
+ /** All record kinds this addon declares (targets + B2 broker entries). */
6810
+ var haAllRecordKinds = {
6811
+ ...haRecordKinds,
6812
+ [haBrokersEntryKind.name]: haBrokersEntryKind
6813
+ };
6784
6814
  //#endregion
6785
6815
  //#region src/ha-notification-output.ts
6786
6816
  /**
@@ -6815,8 +6845,6 @@ function createHaIconRouteProvider() {
6815
6845
  */
6816
6846
  /** The single kind this provider contributes to the shared catalog. */
6817
6847
  var HA_NOTIFICATION_KIND = "homeassistant";
6818
- /** addonId-namespaced settings-store collection holding HA notify targets. */
6819
- var HA_TARGETS_COLLECTION = "provider-homeassistant:ha-notification-targets";
6820
6848
  function haConfigSchema() {
6821
6849
  return { sections: [{
6822
6850
  id: "connection",
@@ -6996,71 +7024,59 @@ function parseNotifyServices(result, brokerId) {
6996
7024
  }
6997
7025
  }));
6998
7026
  }
6999
- /** KV JSON-blob shape — a single `data` column routes the row through the
7000
- * settings backend's canonical key/value path (id TEXT PK, data TEXT). */
7001
- var KV_BLOB_COLUMNS = [{
7002
- name: "data",
7003
- type: "TEXT",
7004
- notNull: true
7005
- }];
7006
- function rowToTarget(row) {
7007
- const parsed = TargetSchema.safeParse({
7008
- id: row.id,
7009
- ...row.data
7010
- });
7011
- return parsed.success ? parsed.data : null;
7012
- }
7013
- function targetToData(target) {
7014
- return {
7015
- name: target.name,
7016
- kind: target.kind,
7017
- addonId: target.addonId,
7018
- enabled: target.enabled,
7019
- config: target.config
7020
- };
7021
- }
7022
- /** CRUD over one settings-store collection of `homeassistant` notify targets. */
7023
- var HaTargetStore = class {
7024
- store;
7025
- collection;
7026
- constructor(store, collection = HA_TARGETS_COLLECTION) {
7027
- this.store = store;
7028
- this.collection = collection;
7027
+ /**
7028
+ * CRUD over the `ha-notification-targets` record kind.
7029
+ *
7030
+ * `HaTargetStore.of(records)` is the production factory; the test helper
7031
+ * (`makeFakeHaRecords`) supplies a fake transport so nothing hits SQLite.
7032
+ * No `init()` method: kinds are declared at addon boot via
7033
+ * `ctx.records.declare(haRecordKinds)`.
7034
+ */
7035
+ var HaTargetStore = class HaTargetStore {
7036
+ kind;
7037
+ constructor(kind) {
7038
+ this.kind = kind;
7029
7039
  }
7030
- /** Declare the backing collection before any read/write. The SQLite settings
7031
- * backend rejects undeclared collections (fail-fast), so this MUST run before
7032
- * `list`/`getById`/`upsert`/`delete` — mirrors addon-ai's ProfileStore.init. */
7033
- async init() {
7034
- await this.store.declareCollection(this.collection, KV_BLOB_COLUMNS);
7040
+ /** Factory: build from a declared `RecordsAccess` (after `ctx.records.declare`). */
7041
+ static of(records) {
7042
+ return new HaTargetStore(records.kind(haRecordKinds["ha-notification-targets"]));
7035
7043
  }
7036
7044
  async list() {
7037
- const rows = await this.store.query(this.collection);
7045
+ const page = await this.kind.query({ limit: 1e3 });
7038
7046
  const out = [];
7039
- for (const row of rows) {
7040
- const target = rowToTarget(row);
7041
- if (target) out.push(target);
7047
+ for (const record of page.records) {
7048
+ const parsed = TargetSchema.safeParse({
7049
+ id: record.id,
7050
+ ...record.data
7051
+ });
7052
+ if (parsed.success) out.push(parsed.data);
7042
7053
  }
7043
7054
  return out;
7044
7055
  }
7045
7056
  async getById(id) {
7046
- const row = (await this.store.query(this.collection)).find((r) => r.id === id);
7047
- return row ? rowToTarget(row) : null;
7057
+ const row = await this.kind.get(id);
7058
+ if (row === null) return null;
7059
+ const parsed = TargetSchema.safeParse({
7060
+ id: row.id,
7061
+ ...row.data
7062
+ });
7063
+ return parsed.success ? parsed.data : null;
7048
7064
  }
7049
7065
  async upsert(target) {
7050
- const exists = (await this.store.query(this.collection)).some((r) => r.id === target.id);
7051
- const data = targetToData(target);
7052
- if (exists) await this.store.update(this.collection, target.id, data);
7053
- else await this.store.insert(this.collection, {
7054
- id: target.id,
7055
- data
7066
+ const { id, ...rest } = target;
7067
+ const parsed = haRecordKinds["ha-notification-targets"].schema.safeParse(rest);
7068
+ if (!parsed.success) throw new Error(`invalid HA target '${id}': ${parsed.error.message}`);
7069
+ await this.kind.put({
7070
+ id,
7071
+ data: parsed.data
7056
7072
  });
7057
7073
  }
7058
7074
  async delete(id) {
7059
- await this.store.remove(this.collection, id);
7075
+ await this.kind.delete(id);
7060
7076
  }
7061
7077
  async setEnabled(id, enabled) {
7062
7078
  const target = await this.getById(id);
7063
- if (!target) return null;
7079
+ if (target === null) return null;
7064
7080
  const next = {
7065
7081
  ...target,
7066
7082
  enabled
@@ -7069,78 +7085,6 @@ var HaTargetStore = class {
7069
7085
  return next;
7070
7086
  }
7071
7087
  };
7072
- /** Adapt the tRPC-shaped `settings-store` cap client to the narrow port. */
7073
- function createApiHaSettingsStorePort(api) {
7074
- return {
7075
- query: async (collection) => {
7076
- return (await api.settingsStore.query.query({ collection })).map((r) => ({
7077
- id: r.id,
7078
- data: r.data
7079
- }));
7080
- },
7081
- insert: async (collection, record) => {
7082
- await api.settingsStore.insert.mutate({
7083
- collection,
7084
- record: {
7085
- id: record.id,
7086
- data: { ...record.data }
7087
- }
7088
- });
7089
- },
7090
- update: async (collection, id, data) => {
7091
- await api.settingsStore.update.mutate({
7092
- collection,
7093
- id,
7094
- data
7095
- });
7096
- },
7097
- remove: async (collection, id) => {
7098
- await api.settingsStore.delete.mutate({
7099
- collection,
7100
- key: id
7101
- });
7102
- },
7103
- declareCollection: async (collection, columns) => {
7104
- await api.settingsStore.declareCollection.mutate({
7105
- collection,
7106
- columns: columns.map((c) => ({ ...c }))
7107
- });
7108
- }
7109
- };
7110
- }
7111
- /** In-memory port — a resilient fallback when no `api` is wired. */
7112
- function createMemoryHaSettingsStorePort() {
7113
- const collections = /* @__PURE__ */ new Map();
7114
- const bucket = (collection) => {
7115
- let map = collections.get(collection);
7116
- if (!map) {
7117
- map = /* @__PURE__ */ new Map();
7118
- collections.set(collection, map);
7119
- }
7120
- return map;
7121
- };
7122
- return {
7123
- query: async (collection) => [...bucket(collection).values()],
7124
- insert: async (collection, record) => {
7125
- bucket(collection).set(record.id, {
7126
- id: record.id,
7127
- data: { ...record.data }
7128
- });
7129
- },
7130
- update: async (collection, id, data) => {
7131
- bucket(collection).set(id, {
7132
- id,
7133
- data: { ...data }
7134
- });
7135
- },
7136
- remove: async (collection, id) => {
7137
- bucket(collection).delete(id);
7138
- },
7139
- declareCollection: async (collection) => {
7140
- bucket(collection);
7141
- }
7142
- };
7143
- }
7144
7088
  /** The canned notification `testTarget` sends when the caller omits a sample. */
7145
7089
  function cannedNotification() {
7146
7090
  return {
@@ -7290,6 +7234,78 @@ function createHaNotificationOutputProvider(deps) {
7290
7234
  };
7291
7235
  }
7292
7236
  //#endregion
7237
+ //#region src/ha-broker-store.ts
7238
+ /**
7239
+ * CRUD for HA brokers over the `brokers` entry record kind (B2).
7240
+ */
7241
+ function rowToEntry(id, data) {
7242
+ const parsed = HaBrokerEntrySchema.safeParse({
7243
+ id,
7244
+ name: data.name,
7245
+ auth: data.auth,
7246
+ integrationId: data.integrationId
7247
+ });
7248
+ return parsed.success ? parsed.data : null;
7249
+ }
7250
+ var HaBrokerStore = class HaBrokerStore {
7251
+ kind;
7252
+ constructor(kind) {
7253
+ this.kind = kind;
7254
+ }
7255
+ static of(records) {
7256
+ return new HaBrokerStore(records.kind(haBrokersEntryKind));
7257
+ }
7258
+ async listResolved() {
7259
+ const page = await this.kind.query({ limit: 1e3 });
7260
+ const out = [];
7261
+ for (const record of page.records) {
7262
+ let data = record.data;
7263
+ try {
7264
+ const resolved = await this.kind.getResolved(record.id);
7265
+ if (resolved !== null) data = resolved.data;
7266
+ } catch (err) {
7267
+ if (!(err instanceof RecordSecretUnavailableError)) throw err;
7268
+ }
7269
+ const entry = rowToEntry(record.id, data);
7270
+ if (entry !== null) out.push(entry);
7271
+ }
7272
+ return out;
7273
+ }
7274
+ async getById(id) {
7275
+ try {
7276
+ const row = await this.kind.getResolved(id);
7277
+ if (row === null) return null;
7278
+ return rowToEntry(row.id, row.data);
7279
+ } catch (err) {
7280
+ if (err instanceof RecordSecretUnavailableError) return null;
7281
+ throw err;
7282
+ }
7283
+ }
7284
+ async upsert(entry) {
7285
+ const { id, name, auth, integrationId } = entry;
7286
+ const body = {
7287
+ name,
7288
+ auth,
7289
+ ...integrationId === void 0 ? {} : { integrationId }
7290
+ };
7291
+ const parsed = haBrokersEntryKind.schema.safeParse(body);
7292
+ if (!parsed.success) throw new Error(`invalid HA broker '${id}': ${parsed.error.message}`);
7293
+ await this.kind.put({
7294
+ id,
7295
+ data: parsed.data
7296
+ });
7297
+ }
7298
+ async delete(id) {
7299
+ await this.kind.delete(id);
7300
+ }
7301
+ async replaceAll(entries) {
7302
+ const page = await this.kind.query({ limit: 1e3 });
7303
+ const nextIds = new Set(entries.map((e) => e.id));
7304
+ for (const row of page.records) if (!nextIds.has(row.id)) await this.kind.delete(row.id);
7305
+ for (const entry of entries) await this.upsert(entry);
7306
+ }
7307
+ };
7308
+ //#endregion
7293
7309
  //#region src/ha-calendar-source.ts
7294
7310
  function isCalendarEntity(entityId) {
7295
7311
  return entityId.startsWith("calendar.");
@@ -7950,6 +7966,9 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
7950
7966
  return `ha:${String(config?.["brokerId"] ?? "unknown")}:dev:${String(config?.["haDeviceId"] ?? Date.now())}`;
7951
7967
  }
7952
7968
  registry = null;
7969
+ brokerStore = null;
7970
+ /** Runtime broker rows (records when B2 is live, else settings). */
7971
+ activeBrokers = [];
7953
7972
  /** Periodic re-sync sweep handle (cleared on shutdown). */
7954
7973
  resyncTimer = null;
7955
7974
  /** `brokerId → aggregator deviceId` cache for the per-broker generic
@@ -7963,6 +7982,11 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
7963
7982
  super({ ...DEFAULT_CONFIG });
7964
7983
  }
7965
7984
  async onInitialize() {
7985
+ const records = this.ctx.records;
7986
+ if (records === void 0) throw new Error("provider-homeassistant: ctx.records is required (hub-only addon)");
7987
+ await records.declare(haAllRecordKinds);
7988
+ this.brokerStore = HaBrokerStore.of(records);
7989
+ this.activeBrokers = await this.loadPersistedBrokers();
7966
7990
  this.registry = new HaBrokerRegistry(this.ctx.logger, this.ctx.eventBus);
7967
7991
  this.registry.setOnBrokerConnected((brokerId) => {
7968
7992
  this.reconcileBroker(brokerId);
@@ -7973,11 +7997,11 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
7973
7997
  this.registry.setOnBusEvent((brokerId, ev) => {
7974
7998
  this.routeBusEvent(brokerId, ev);
7975
7999
  });
7976
- await this.registry.restore(this.config.brokers);
8000
+ await this.registry.restore(this.activeBrokers);
7977
8001
  this.resyncTimer = setInterval(() => {
7978
8002
  this.reconcileAllConnectedBrokers();
7979
8003
  }, HaProviderAddon.RESYNC_INTERVAL_MS);
7980
- this.ctx.logger.info("ha provider initialised", { meta: { brokerCount: this.config.brokers.length } });
8004
+ this.ctx.logger.info("ha provider initialised", { meta: { brokerCount: this.activeBrokers.length } });
7981
8005
  await this.reconcileIntegrationsToBrokers();
7982
8006
  this.subscribeIntegrationLifecycle();
7983
8007
  return [
@@ -8008,11 +8032,9 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8008
8032
  ];
8009
8033
  }
8010
8034
  async buildNotificationOutputProvider() {
8011
- const api = this.ctx.api;
8012
- const port = api ? createApiHaSettingsStorePort(api) : createMemoryHaSettingsStorePort();
8013
- if (!api) this.ctx.logger.warn("ha notification-output: no ctx.api — targets persist in-memory only");
8014
- const store = new HaTargetStore(port);
8015
- await store.init();
8035
+ const records = this.ctx.records;
8036
+ if (records === void 0) throw new Error("ha notification-output: ctx.records is required (hub-only addon)");
8037
+ const store = HaTargetStore.of(records);
8016
8038
  return createHaNotificationOutputProvider({
8017
8039
  addonId: this.ctx.id,
8018
8040
  iconUrl: HA_NOTIFICATION_ICON_URL,
@@ -8029,7 +8051,7 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8029
8051
  if (!manager) throw new Error(`ha-broker '${brokerId}' not found`);
8030
8052
  return manager.sendMessage({ type: "get_services" });
8031
8053
  },
8032
- listBrokerIds: () => this.config.brokers.map((b) => b.id),
8054
+ listBrokerIds: () => this.activeBrokers.map((b) => b.id),
8033
8055
  logger: this.ctx.logger.child("notification-output")
8034
8056
  });
8035
8057
  }
@@ -8090,7 +8112,7 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8090
8112
  const settings = await api.integrations.getSettings.query({ id: integration.id });
8091
8113
  const brokerId = typeof settings["brokerId"] === "string" ? settings["brokerId"] : null;
8092
8114
  if (!brokerId) continue;
8093
- if (!this.config.brokers.find((b) => b.id === brokerId)) {
8115
+ if (!this.activeBrokers.find((b) => b.id === brokerId)) {
8094
8116
  this.ctx.logger.warn("integration→broker: linked broker not found", { meta: {
8095
8117
  integrationId: integration.id,
8096
8118
  brokerId
@@ -8103,11 +8125,11 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8103
8125
  brokerId
8104
8126
  });
8105
8127
  }
8106
- const linkedBrokers = linkBrokersToIntegrations(this.config.brokers, integrationsWithBrokerId);
8107
- if (linkedBrokers.some((b, i) => b !== this.config.brokers[i])) await this.updateGlobalSettings({ brokers: linkedBrokers });
8108
- const orphans = computeBrokerCleanup(this.config.brokers, survivingIntegrationIds);
8128
+ const linkedBrokers = linkBrokersToIntegrations(this.activeBrokers, integrationsWithBrokerId);
8129
+ if (linkedBrokers.some((b, i) => b !== this.activeBrokers[i])) await this.persistBrokerEntries(linkedBrokers);
8130
+ const orphans = computeBrokerCleanup(this.activeBrokers, survivingIntegrationIds);
8109
8131
  this.ctx.logger.info("integration→broker reconcile", { meta: {
8110
- brokerCount: this.config.brokers.length,
8132
+ brokerCount: this.activeBrokers.length,
8111
8133
  integrationCount: haIntegrations.length,
8112
8134
  orphans: orphans.length
8113
8135
  } });
@@ -8204,7 +8226,8 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8204
8226
  async onConfigChanged() {
8205
8227
  const reg = this.registry;
8206
8228
  if (!reg) return;
8207
- const persisted = this.config.brokers;
8229
+ this.activeBrokers = await this.loadPersistedBrokers();
8230
+ const persisted = this.activeBrokers;
8208
8231
  const liveIds = new Set(reg.list().map((b) => b.id));
8209
8232
  const persistedIds = new Set(persisted.map((e) => e.id));
8210
8233
  for (const liveId of liveIds) if (!persistedIds.has(liveId)) try {
@@ -8242,7 +8265,7 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8242
8265
  ...b,
8243
8266
  id: created.id
8244
8267
  } : b);
8245
- await this.updateGlobalSettings({ brokers: next });
8268
+ await this.persistBrokerEntries(next);
8246
8269
  }
8247
8270
  } catch (err) {
8248
8271
  this.ctx.logger.warn("ha onConfigChanged: failed to start new broker", { meta: {
@@ -8252,9 +8275,26 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8252
8275
  }
8253
8276
  }
8254
8277
  }
8278
+ async loadPersistedBrokers() {
8279
+ const store = this.brokerStore;
8280
+ if (store !== null) {
8281
+ const fromRecords = await store.listResolved();
8282
+ if (fromRecords.length > 0) return fromRecords;
8283
+ }
8284
+ return this.config.brokers;
8285
+ }
8286
+ async persistBrokerEntries(entries) {
8287
+ this.activeBrokers = [...entries];
8288
+ const store = this.brokerStore;
8289
+ if (store !== null) {
8290
+ await store.replaceAll(entries);
8291
+ return;
8292
+ }
8293
+ await this.updateGlobalSettings({ brokers: entries });
8294
+ }
8255
8295
  buildBrokerProvider() {
8256
8296
  const ownerAddonId = this.ctx.id;
8257
- const owns = (id) => this.config.brokers.some((b) => b.id === id);
8297
+ const owns = (id) => this.activeBrokers.some((b) => b.id === id);
8258
8298
  return {
8259
8299
  list: async ({ kind }) => {
8260
8300
  if (kind && kind !== HA_KIND) return [];
@@ -8284,7 +8324,7 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8284
8324
  brokerId: entry.id,
8285
8325
  name
8286
8326
  } });
8287
- await this.updateGlobalSettings({ brokers: [...this.config.brokers, entry] });
8327
+ await this.persistBrokerEntries([...this.activeBrokers, entry]);
8288
8328
  return { id: entry.id };
8289
8329
  },
8290
8330
  remove: async ({ id }) => {
@@ -8299,8 +8339,8 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8299
8339
  brokerId: id,
8300
8340
  logger: this.ctx.logger
8301
8341
  });
8302
- const nextBrokers = this.config.brokers.filter((b) => b.id !== id);
8303
- await this.updateGlobalSettings({ brokers: nextBrokers });
8342
+ const nextBrokers = this.activeBrokers.filter((b) => b.id !== id);
8343
+ await this.persistBrokerEntries(nextBrokers);
8304
8344
  },
8305
8345
  testConnection: async ({ id }) => {
8306
8346
  if (!owns(id)) return {
@@ -8322,18 +8362,18 @@ var HaProviderAddon = class HaProviderAddon extends BaseDeviceProvider {
8322
8362
  };
8323
8363
  },
8324
8364
  getSettings: async ({ id }) => {
8325
- const entry = this.config.brokers.find((b) => b.id === id);
8365
+ const entry = this.activeBrokers.find((b) => b.id === id);
8326
8366
  if (!entry) return null;
8327
8367
  return authToSettings(entry.auth);
8328
8368
  },
8329
8369
  setSettings: async ({ id, settings }) => {
8330
8370
  if (!owns(id)) return;
8331
8371
  const entry = await this.requireRegistry().updateEntry(id, settings);
8332
- const next = this.config.brokers.map((b) => b.id === id ? entry : b);
8333
- await this.updateGlobalSettings({ brokers: next });
8372
+ const next = this.activeBrokers.map((b) => b.id === id ? entry : b);
8373
+ await this.persistBrokerEntries(next);
8334
8374
  },
8335
8375
  getBrokerConfig: async ({ id }) => {
8336
- const entry = this.config.brokers.find((b) => b.id === id);
8376
+ const entry = this.activeBrokers.find((b) => b.id === id);
8337
8377
  if (!entry) return null;
8338
8378
  return authToSettings(entry.auth);
8339
8379
  },