@camstack/addon-provider-homeassistant 1.2.659 → 1.2.661

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.
@@ -5981,7 +5981,7 @@ var ZodIssueCode = {
5981
5981
  var ZodFirstPartyTypeKind;
5982
5982
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5983
5983
  //#endregion
5984
- //#region ../types/dist/sleep-D1jjWAr8.mjs
5984
+ //#region ../types/dist/sleep-9TIHFj1w.mjs
5985
5985
  /**
5986
5986
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5987
5987
  * window to float samples (D455).
@@ -7935,10 +7935,9 @@ var BaseAddon = class {
7935
7935
  *
7936
7936
  * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7937
7937
  * needs its connection fields, the default integration the addon's own sections. It is the
7938
- * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7939
- * unchanged (`integrations.setSettings` for an account integration).
7938
+ * SHAPE of the form only — the values live on the instance record.
7940
7939
  */
7941
- async integrationSettingsSchema(_instance) {
7940
+ async integrationFormSchema(_instance) {
7942
7941
  return null;
7943
7942
  }
7944
7943
  /**
@@ -7984,7 +7983,7 @@ var BaseAddon = class {
7984
7983
  * per-instance schema when it declares one, else its global schema (what they always showed).
7985
7984
  */
7986
7985
  async getIntegrationFormSchema(instance, nodeId) {
7987
- const scoped = await this.integrationSettingsSchema(instance);
7986
+ const scoped = await this.integrationFormSchema(instance);
7988
7987
  if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
7989
7988
  return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
7990
7989
  }
@@ -11997,7 +11996,7 @@ object({
11997
11996
  params: record(string(), union([string(), number()])).optional()
11998
11997
  });
11999
11998
  //#endregion
12000
- //#region ../types/dist/composition-CRNwcFYY.mjs
11999
+ //#region ../types/dist/composition-pOHbTzRB.mjs
12001
12000
  /**
12002
12001
  * The ffmpeg build every CamStack node downloads, per platform and arch.
12003
12002
  *
@@ -50856,6 +50855,9 @@ var RunningProposalEvidenceSchema = object({
50856
50855
  runsFound: number().int().nonnegative(),
50857
50856
  pausesFound: number().int().nonnegative(),
50858
50857
  longestPauseMs: number().nonnegative(),
50858
+ /** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
50859
+ pulsesFound: number().int().nonnegative(),
50860
+ longestPulseMs: number().nonnegative(),
50859
50861
  idleFloorW: number(),
50860
50862
  noiseCeilingW: number(),
50861
50863
  plateauW: number(),
@@ -56781,11 +56783,7 @@ var CreateIntegrationInputSchema = object({
56781
56783
  info: record(string(), unknown()).optional(),
56782
56784
  /** `stableId` of the discovery candidate the form was seeded from (D984). */
56783
56785
  originStableId: string().optional(),
56784
- settings: record(string(), unknown()).optional(),
56785
- /** Keys of `settings` the form's schema declares secret (by type) — kept in
56786
- * the keychain, not the table (D787). */
56787
- secretKeys: array(string()).optional(),
56788
- skipRestart: boolean().optional()
56786
+ settings: record(string(), unknown()).optional()
56789
56787
  });
56790
56788
  var UpdateIntegrationInputSchema = object({
56791
56789
  id: string(),
@@ -56806,22 +56804,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
56806
56804
  }), method(object({ id: string() }), DeleteIntegrationResultSchema, {
56807
56805
  kind: "mutation",
56808
56806
  auth: "admin"
56809
- }), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
56810
- id: string(),
56811
- settings: record(string(), unknown()),
56812
- /** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
56813
- secretKeys: array(string()).optional(),
56814
- /** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
56815
- skipRestart: boolean().optional()
56816
- }), object({ success: boolean() }), {
56817
- kind: "mutation",
56818
- auth: "admin"
56819
- }), method(object({ id: string() }), object({
56820
- rows: number().int().nonnegative(),
56821
- secrets: number().int().nonnegative()
56822
- }), {
56823
- kind: "mutation",
56824
- auth: "admin"
56825
56807
  }), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
56826
56808
  addonId: string(),
56827
56809
  settings: record(string(), unknown())
@@ -59798,6 +59780,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
59798
59780
  }), {
59799
59781
  kind: "mutation",
59800
59782
  auth: "admin"
59783
+ }), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
59784
+ rows: number().int().nonnegative(),
59785
+ secrets: number().int().nonnegative()
59786
+ }), {
59787
+ kind: "mutation",
59788
+ auth: "admin"
59789
+ }), method(object({
59790
+ integrationId: string().min(1),
59791
+ patch: record(string(), unknown())
59792
+ }), object({ written: boolean() }), {
59793
+ kind: "mutation",
59794
+ auth: "admin"
59795
+ }), method(object({
59796
+ integrationId: string().min(1),
59797
+ keys: array(string().min(1))
59798
+ }), object({
59799
+ present: boolean(),
59800
+ removed: record(string(), unknown())
59801
+ }), {
59802
+ kind: "mutation",
59803
+ auth: "admin"
59801
59804
  });
59802
59805
  method(object({
59803
59806
  sourceUrl: string(),
@@ -81311,11 +81314,15 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
81311
81314
  * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
81312
81315
  * near F. A device that is not near one level most of the time has no floor.
81313
81316
  * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
81314
- * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
81315
- * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
81317
+ * 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
81318
+ * display waking): it is neither a run nor a pause. Among the remaining
81319
+ * episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
81320
+ * two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
81321
+ * a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
81322
+ * is no run.
81316
81323
  * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
81317
- * grid a person would type; stop dwell covers the longest pause; start dwell
81318
- * covers the longest standby blip above T.
81324
+ * grid a person would type; stop dwell covers the longest pause and the
81325
+ * kind's floor; start dwell covers the longest pulse and standby blip above T.
81319
81326
  * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
81320
81327
  * run must hold exactly one true interval and nothing may flap outside.
81321
81328
  */
@@ -81326,6 +81333,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
81326
81333
  30 * SECOND_MS;
81327
81334
  60 * SECOND_MS;
81328
81335
  20 * MINUTE_MS$1;
81336
+ 90 * SECOND_MS;
81337
+ 30 * MINUTE_MS$1;
81338
+ 10 * MINUTE_MS$1;
81339
+ DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
81329
81340
  10 * SECOND_MS;
81330
81341
  10 * SECOND_MS;
81331
81342
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
@@ -86610,13 +86621,6 @@ Object.freeze({
86610
86621
  access: "create",
86611
86622
  role: "admin"
86612
86623
  },
86613
- "integrations.clearSettings": {
86614
- capName: "integrations",
86615
- capScope: "system",
86616
- addonId: null,
86617
- access: "delete",
86618
- role: "admin"
86619
- },
86620
86624
  "integrations.create": {
86621
86625
  capName: "integrations",
86622
86626
  capScope: "system",
@@ -86652,13 +86656,6 @@ Object.freeze({
86652
86656
  access: "view",
86653
86657
  role: "admin"
86654
86658
  },
86655
- "integrations.getSettings": {
86656
- capName: "integrations",
86657
- capScope: "system",
86658
- addonId: null,
86659
- access: "view",
86660
- role: "admin"
86661
- },
86662
86659
  "integrations.list": {
86663
86660
  capName: "integrations",
86664
86661
  capScope: "system",
@@ -86666,13 +86663,6 @@ Object.freeze({
86666
86663
  access: "view",
86667
86664
  role: "admin"
86668
86665
  },
86669
- "integrations.setSettings": {
86670
- capName: "integrations",
86671
- capScope: "system",
86672
- addonId: null,
86673
- access: "create",
86674
- role: "admin"
86675
- },
86676
86666
  "integrations.testConnection": {
86677
86667
  capName: "integrations",
86678
86668
  capScope: "system",
@@ -87667,6 +87657,13 @@ Object.freeze({
87667
87657
  access: "view",
87668
87658
  role: "admin"
87669
87659
  },
87660
+ "migrations.clearLegacyIntegrationRows": {
87661
+ capName: "migrations",
87662
+ capScope: "system",
87663
+ addonId: null,
87664
+ access: "delete",
87665
+ role: "admin"
87666
+ },
87670
87667
  "migrations.declareOwner": {
87671
87668
  capName: "migrations",
87672
87669
  capScope: "system",
@@ -87674,6 +87671,13 @@ Object.freeze({
87674
87671
  access: "create",
87675
87672
  role: "admin"
87676
87673
  },
87674
+ "migrations.deleteLegacyIntegrationRowKeys": {
87675
+ capName: "migrations",
87676
+ capScope: "system",
87677
+ addonId: null,
87678
+ access: "delete",
87679
+ role: "admin"
87680
+ },
87677
87681
  "migrations.dryRun": {
87678
87682
  capName: "migrations",
87679
87683
  capScope: "system",
@@ -87709,6 +87713,20 @@ Object.freeze({
87709
87713
  access: "create",
87710
87714
  role: "admin"
87711
87715
  },
87716
+ "migrations.patchLegacyIntegrationRows": {
87717
+ capName: "migrations",
87718
+ capScope: "system",
87719
+ addonId: null,
87720
+ access: "create",
87721
+ role: "admin"
87722
+ },
87723
+ "migrations.readLegacyIntegrationRows": {
87724
+ capName: "migrations",
87725
+ capScope: "system",
87726
+ addonId: null,
87727
+ access: "view",
87728
+ role: "admin"
87729
+ },
87712
87730
  "migrations.restorePreMigration": {
87713
87731
  capName: "migrations",
87714
87732
  capScope: "system",
@@ -98388,13 +98406,18 @@ var HA_BROKER_KIND = "home-assistant";
98388
98406
  async function listHomeAssistantBrokers(query) {
98389
98407
  return (await query({})).filter((broker) => broker.kind === HA_BROKER_KIND);
98390
98408
  }
98391
- function haInstanceSettingsPortsOver(api) {
98409
+ function refsOfKeys(stored, keys) {
98410
+ const picked = {};
98411
+ for (const key of keys) if (Object.prototype.hasOwnProperty.call(stored, key)) picked[key] = stored[key];
98412
+ return collectSecretMarkerRefs(picked);
98413
+ }
98414
+ function haInstanceSettingsPortsOver(api, secrets = null) {
98392
98415
  const listInstances = async () => {
98393
98416
  const all = await api.list.query();
98394
98417
  const rows = [];
98395
98418
  for (const integration of all) {
98396
98419
  if (integration.addonId !== "provider-homeassistant") continue;
98397
- const settings = await api.getSettings.query({ id: integration.id });
98420
+ const settings = await api.readLegacyIntegrationRows.query({ integrationId: integration.id });
98398
98421
  const brokerId = settings["brokerId"];
98399
98422
  rows.push({
98400
98423
  integrationId: integration.id,
@@ -98404,20 +98427,26 @@ function haInstanceSettingsPortsOver(api) {
98404
98427
  }
98405
98428
  return rows;
98406
98429
  };
98430
+ const owns = async (integrationId) => {
98431
+ return (await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant");
98432
+ };
98407
98433
  return {
98408
98434
  listInstances,
98409
98435
  patchInstanceSettings: async (integrationId, patch) => {
98410
- if (!(await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant")) return false;
98411
- const stored = await api.getSettings.query({ id: integrationId });
98412
- await api.setSettings.mutate({
98413
- id: integrationId,
98414
- settings: {
98415
- ...stored,
98416
- ...patch
98417
- },
98418
- skipRestart: true
98419
- });
98420
- return true;
98436
+ if (!await owns(integrationId)) return false;
98437
+ return (await api.patchLegacyIntegrationRows.mutate({
98438
+ integrationId,
98439
+ patch: { ...patch }
98440
+ })).written;
98441
+ },
98442
+ clearInstanceSettingsKeys: async (integrationId, keys) => {
98443
+ if (!await owns(integrationId)) return false;
98444
+ const refs = refsOfKeys(await api.readLegacyIntegrationRows.query({ integrationId }), keys);
98445
+ if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
98446
+ return (await api.deleteLegacyIntegrationRowKeys.mutate({
98447
+ integrationId,
98448
+ keys
98449
+ })).present;
98421
98450
  }
98422
98451
  };
98423
98452
  }
@@ -5980,7 +5980,7 @@ var ZodIssueCode = {
5980
5980
  var ZodFirstPartyTypeKind;
5981
5981
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5982
5982
  //#endregion
5983
- //#region ../types/dist/sleep-D1jjWAr8.mjs
5983
+ //#region ../types/dist/sleep-9TIHFj1w.mjs
5984
5984
  /**
5985
5985
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5986
5986
  * window to float samples (D455).
@@ -7934,10 +7934,9 @@ var BaseAddon = class {
7934
7934
  *
7935
7935
  * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7936
7936
  * needs its connection fields, the default integration the addon's own sections. It is the
7937
- * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7938
- * unchanged (`integrations.setSettings` for an account integration).
7937
+ * SHAPE of the form only — the values live on the instance record.
7939
7938
  */
7940
- async integrationSettingsSchema(_instance) {
7939
+ async integrationFormSchema(_instance) {
7941
7940
  return null;
7942
7941
  }
7943
7942
  /**
@@ -7983,7 +7982,7 @@ var BaseAddon = class {
7983
7982
  * per-instance schema when it declares one, else its global schema (what they always showed).
7984
7983
  */
7985
7984
  async getIntegrationFormSchema(instance, nodeId) {
7986
- const scoped = await this.integrationSettingsSchema(instance);
7985
+ const scoped = await this.integrationFormSchema(instance);
7987
7986
  if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
7988
7987
  return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
7989
7988
  }
@@ -11996,7 +11995,7 @@ object({
11996
11995
  params: record(string(), union([string(), number()])).optional()
11997
11996
  });
11998
11997
  //#endregion
11999
- //#region ../types/dist/composition-CRNwcFYY.mjs
11998
+ //#region ../types/dist/composition-pOHbTzRB.mjs
12000
11999
  /**
12001
12000
  * The ffmpeg build every CamStack node downloads, per platform and arch.
12002
12001
  *
@@ -50855,6 +50854,9 @@ var RunningProposalEvidenceSchema = object({
50855
50854
  runsFound: number().int().nonnegative(),
50856
50855
  pausesFound: number().int().nonnegative(),
50857
50856
  longestPauseMs: number().nonnegative(),
50857
+ /** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
50858
+ pulsesFound: number().int().nonnegative(),
50859
+ longestPulseMs: number().nonnegative(),
50858
50860
  idleFloorW: number(),
50859
50861
  noiseCeilingW: number(),
50860
50862
  plateauW: number(),
@@ -56780,11 +56782,7 @@ var CreateIntegrationInputSchema = object({
56780
56782
  info: record(string(), unknown()).optional(),
56781
56783
  /** `stableId` of the discovery candidate the form was seeded from (D984). */
56782
56784
  originStableId: string().optional(),
56783
- settings: record(string(), unknown()).optional(),
56784
- /** Keys of `settings` the form's schema declares secret (by type) — kept in
56785
- * the keychain, not the table (D787). */
56786
- secretKeys: array(string()).optional(),
56787
- skipRestart: boolean().optional()
56785
+ settings: record(string(), unknown()).optional()
56788
56786
  });
56789
56787
  var UpdateIntegrationInputSchema = object({
56790
56788
  id: string(),
@@ -56805,22 +56803,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
56805
56803
  }), method(object({ id: string() }), DeleteIntegrationResultSchema, {
56806
56804
  kind: "mutation",
56807
56805
  auth: "admin"
56808
- }), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
56809
- id: string(),
56810
- settings: record(string(), unknown()),
56811
- /** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
56812
- secretKeys: array(string()).optional(),
56813
- /** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
56814
- skipRestart: boolean().optional()
56815
- }), object({ success: boolean() }), {
56816
- kind: "mutation",
56817
- auth: "admin"
56818
- }), method(object({ id: string() }), object({
56819
- rows: number().int().nonnegative(),
56820
- secrets: number().int().nonnegative()
56821
- }), {
56822
- kind: "mutation",
56823
- auth: "admin"
56824
56806
  }), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
56825
56807
  addonId: string(),
56826
56808
  settings: record(string(), unknown())
@@ -59797,6 +59779,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
59797
59779
  }), {
59798
59780
  kind: "mutation",
59799
59781
  auth: "admin"
59782
+ }), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
59783
+ rows: number().int().nonnegative(),
59784
+ secrets: number().int().nonnegative()
59785
+ }), {
59786
+ kind: "mutation",
59787
+ auth: "admin"
59788
+ }), method(object({
59789
+ integrationId: string().min(1),
59790
+ patch: record(string(), unknown())
59791
+ }), object({ written: boolean() }), {
59792
+ kind: "mutation",
59793
+ auth: "admin"
59794
+ }), method(object({
59795
+ integrationId: string().min(1),
59796
+ keys: array(string().min(1))
59797
+ }), object({
59798
+ present: boolean(),
59799
+ removed: record(string(), unknown())
59800
+ }), {
59801
+ kind: "mutation",
59802
+ auth: "admin"
59800
59803
  });
59801
59804
  method(object({
59802
59805
  sourceUrl: string(),
@@ -81310,11 +81313,15 @@ function runningFromMediaPlayer(state, previous, fetchedAt, transitionAt) {
81310
81313
  * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
81311
81314
  * near F. A device that is not near one level most of the time has no floor.
81312
81315
  * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
81313
- * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
81314
- * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
81316
+ * 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
81317
+ * display waking): it is neither a run nor a pause. Among the remaining
81318
+ * episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
81319
+ * two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
81320
+ * a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
81321
+ * is no run.
81315
81322
  * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
81316
- * grid a person would type; stop dwell covers the longest pause; start dwell
81317
- * covers the longest standby blip above T.
81323
+ * grid a person would type; stop dwell covers the longest pause and the
81324
+ * kind's floor; start dwell covers the longest pulse and standby blip above T.
81318
81325
  * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
81319
81326
  * run must hold exactly one true interval and nothing may flap outside.
81320
81327
  */
@@ -81325,6 +81332,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
81325
81332
  30 * SECOND_MS;
81326
81333
  60 * SECOND_MS;
81327
81334
  20 * MINUTE_MS$1;
81335
+ 90 * SECOND_MS;
81336
+ 30 * MINUTE_MS$1;
81337
+ 10 * MINUTE_MS$1;
81338
+ DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
81328
81339
  10 * SECOND_MS;
81329
81340
  10 * SECOND_MS;
81330
81341
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
@@ -86609,13 +86620,6 @@ Object.freeze({
86609
86620
  access: "create",
86610
86621
  role: "admin"
86611
86622
  },
86612
- "integrations.clearSettings": {
86613
- capName: "integrations",
86614
- capScope: "system",
86615
- addonId: null,
86616
- access: "delete",
86617
- role: "admin"
86618
- },
86619
86623
  "integrations.create": {
86620
86624
  capName: "integrations",
86621
86625
  capScope: "system",
@@ -86651,13 +86655,6 @@ Object.freeze({
86651
86655
  access: "view",
86652
86656
  role: "admin"
86653
86657
  },
86654
- "integrations.getSettings": {
86655
- capName: "integrations",
86656
- capScope: "system",
86657
- addonId: null,
86658
- access: "view",
86659
- role: "admin"
86660
- },
86661
86658
  "integrations.list": {
86662
86659
  capName: "integrations",
86663
86660
  capScope: "system",
@@ -86665,13 +86662,6 @@ Object.freeze({
86665
86662
  access: "view",
86666
86663
  role: "admin"
86667
86664
  },
86668
- "integrations.setSettings": {
86669
- capName: "integrations",
86670
- capScope: "system",
86671
- addonId: null,
86672
- access: "create",
86673
- role: "admin"
86674
- },
86675
86665
  "integrations.testConnection": {
86676
86666
  capName: "integrations",
86677
86667
  capScope: "system",
@@ -87666,6 +87656,13 @@ Object.freeze({
87666
87656
  access: "view",
87667
87657
  role: "admin"
87668
87658
  },
87659
+ "migrations.clearLegacyIntegrationRows": {
87660
+ capName: "migrations",
87661
+ capScope: "system",
87662
+ addonId: null,
87663
+ access: "delete",
87664
+ role: "admin"
87665
+ },
87669
87666
  "migrations.declareOwner": {
87670
87667
  capName: "migrations",
87671
87668
  capScope: "system",
@@ -87673,6 +87670,13 @@ Object.freeze({
87673
87670
  access: "create",
87674
87671
  role: "admin"
87675
87672
  },
87673
+ "migrations.deleteLegacyIntegrationRowKeys": {
87674
+ capName: "migrations",
87675
+ capScope: "system",
87676
+ addonId: null,
87677
+ access: "delete",
87678
+ role: "admin"
87679
+ },
87676
87680
  "migrations.dryRun": {
87677
87681
  capName: "migrations",
87678
87682
  capScope: "system",
@@ -87708,6 +87712,20 @@ Object.freeze({
87708
87712
  access: "create",
87709
87713
  role: "admin"
87710
87714
  },
87715
+ "migrations.patchLegacyIntegrationRows": {
87716
+ capName: "migrations",
87717
+ capScope: "system",
87718
+ addonId: null,
87719
+ access: "create",
87720
+ role: "admin"
87721
+ },
87722
+ "migrations.readLegacyIntegrationRows": {
87723
+ capName: "migrations",
87724
+ capScope: "system",
87725
+ addonId: null,
87726
+ access: "view",
87727
+ role: "admin"
87728
+ },
87711
87729
  "migrations.restorePreMigration": {
87712
87730
  capName: "migrations",
87713
87731
  capScope: "system",
@@ -98387,13 +98405,18 @@ var HA_BROKER_KIND = "home-assistant";
98387
98405
  async function listHomeAssistantBrokers(query) {
98388
98406
  return (await query({})).filter((broker) => broker.kind === HA_BROKER_KIND);
98389
98407
  }
98390
- function haInstanceSettingsPortsOver(api) {
98408
+ function refsOfKeys(stored, keys) {
98409
+ const picked = {};
98410
+ for (const key of keys) if (Object.prototype.hasOwnProperty.call(stored, key)) picked[key] = stored[key];
98411
+ return collectSecretMarkerRefs(picked);
98412
+ }
98413
+ function haInstanceSettingsPortsOver(api, secrets = null) {
98391
98414
  const listInstances = async () => {
98392
98415
  const all = await api.list.query();
98393
98416
  const rows = [];
98394
98417
  for (const integration of all) {
98395
98418
  if (integration.addonId !== "provider-homeassistant") continue;
98396
- const settings = await api.getSettings.query({ id: integration.id });
98419
+ const settings = await api.readLegacyIntegrationRows.query({ integrationId: integration.id });
98397
98420
  const brokerId = settings["brokerId"];
98398
98421
  rows.push({
98399
98422
  integrationId: integration.id,
@@ -98403,20 +98426,26 @@ function haInstanceSettingsPortsOver(api) {
98403
98426
  }
98404
98427
  return rows;
98405
98428
  };
98429
+ const owns = async (integrationId) => {
98430
+ return (await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant");
98431
+ };
98406
98432
  return {
98407
98433
  listInstances,
98408
98434
  patchInstanceSettings: async (integrationId, patch) => {
98409
- if (!(await api.list.query()).some((i) => i.id === integrationId && i.addonId === "provider-homeassistant")) return false;
98410
- const stored = await api.getSettings.query({ id: integrationId });
98411
- await api.setSettings.mutate({
98412
- id: integrationId,
98413
- settings: {
98414
- ...stored,
98415
- ...patch
98416
- },
98417
- skipRestart: true
98418
- });
98419
- return true;
98435
+ if (!await owns(integrationId)) return false;
98436
+ return (await api.patchLegacyIntegrationRows.mutate({
98437
+ integrationId,
98438
+ patch: { ...patch }
98439
+ })).written;
98440
+ },
98441
+ clearInstanceSettingsKeys: async (integrationId, keys) => {
98442
+ if (!await owns(integrationId)) return false;
98443
+ const refs = refsOfKeys(await api.readLegacyIntegrationRows.query({ integrationId }), keys);
98444
+ if (refs.length > 0 && secrets !== null) await secrets.delete(refs);
98445
+ return (await api.deleteLegacyIntegrationRowKeys.mutate({
98446
+ integrationId,
98447
+ keys
98448
+ })).present;
98420
98449
  }
98421
98450
  };
98422
98451
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homeassistant",
3
- "version": "1.2.659",
3
+ "version": "1.2.661",
4
4
  "description": "Home Assistant device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",
@@ -137,7 +137,7 @@
137
137
  "description": "Device provider (import) + native entity export (push). Two addons, one bundle, separate processes."
138
138
  },
139
139
  "requires": {
140
- "server": ">=1.2.768"
140
+ "server": ">=1.2.770"
141
141
  }
142
142
  },
143
143
  "files": [