@camstack/addon-import-alexa 0.2.185 → 0.2.186

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 CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.186] - 2026-11-05
11
+
12
+ ### Changed
13
+
14
+ - An Alexa integration links to its account through the account record
15
+
10
16
  ## [0.2.185] - 2026-11-04
11
17
 
12
18
  ### Changed
package/dist/addon.js CHANGED
@@ -6044,7 +6044,7 @@ function number(params) {
6044
6044
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
6045
6045
  }
6046
6046
  //#endregion
6047
- //#region ../types/dist/sleep-Cv4Zmie9.mjs
6047
+ //#region ../types/dist/sleep-9TIHFj1w.mjs
6048
6048
  /**
6049
6049
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6050
6050
  * window to float samples (D455).
@@ -7988,10 +7988,9 @@ var BaseAddon = class {
7988
7988
  *
7989
7989
  * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7990
7990
  * needs its connection fields, the default integration the addon's own sections. It is the
7991
- * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7992
- * unchanged (`integrations.setSettings` for an account integration).
7991
+ * SHAPE of the form only — the values live on the instance record.
7993
7992
  */
7994
- async integrationSettingsSchema(_instance) {
7993
+ async integrationFormSchema(_instance) {
7995
7994
  return null;
7996
7995
  }
7997
7996
  /**
@@ -8037,7 +8036,7 @@ var BaseAddon = class {
8037
8036
  * per-instance schema when it declares one, else its global schema (what they always showed).
8038
8037
  */
8039
8038
  async getIntegrationFormSchema(instance, nodeId) {
8040
- const scoped = await this.integrationSettingsSchema(instance);
8039
+ const scoped = await this.integrationFormSchema(instance);
8041
8040
  if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
8042
8041
  return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
8043
8042
  }
@@ -9311,6 +9310,7 @@ function defineEntryKind(name, spec) {
9311
9310
  class: "config",
9312
9311
  writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
9313
9312
  retention: { none: "an entry goes only when the operator deletes it" },
9313
+ ...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
9314
9314
  ...spec.database === void 0 ? {} : { database: spec.database },
9315
9315
  ...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
9316
9316
  ...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
@@ -11980,7 +11980,7 @@ object({
11980
11980
  params: record(string(), union([string(), number$1()])).optional()
11981
11981
  });
11982
11982
  //#endregion
11983
- //#region ../types/dist/composition-CRNwcFYY.mjs
11983
+ //#region ../types/dist/composition-pOHbTzRB.mjs
11984
11984
  /**
11985
11985
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11986
11986
  *
@@ -50460,6 +50460,9 @@ var RunningProposalEvidenceSchema = object({
50460
50460
  runsFound: number$1().int().nonnegative(),
50461
50461
  pausesFound: number$1().int().nonnegative(),
50462
50462
  longestPauseMs: number$1().nonnegative(),
50463
+ /** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
50464
+ pulsesFound: number$1().int().nonnegative(),
50465
+ longestPulseMs: number$1().nonnegative(),
50463
50466
  idleFloorW: number$1(),
50464
50467
  noiseCeilingW: number$1(),
50465
50468
  plateauW: number$1(),
@@ -56305,11 +56308,7 @@ var CreateIntegrationInputSchema = object({
56305
56308
  info: record(string(), unknown()).optional(),
56306
56309
  /** `stableId` of the discovery candidate the form was seeded from (D984). */
56307
56310
  originStableId: string().optional(),
56308
- settings: record(string(), unknown()).optional(),
56309
- /** Keys of `settings` the form's schema declares secret (by type) — kept in
56310
- * the keychain, not the table (D787). */
56311
- secretKeys: array(string()).optional(),
56312
- skipRestart: boolean().optional()
56311
+ settings: record(string(), unknown()).optional()
56313
56312
  });
56314
56313
  var UpdateIntegrationInputSchema = object({
56315
56314
  id: string(),
@@ -56330,16 +56329,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
56330
56329
  }), method(object({ id: string() }), DeleteIntegrationResultSchema, {
56331
56330
  kind: "mutation",
56332
56331
  auth: "admin"
56333
- }), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
56334
- id: string(),
56335
- settings: record(string(), unknown()),
56336
- /** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
56337
- secretKeys: array(string()).optional(),
56338
- /** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
56339
- skipRestart: boolean().optional()
56340
- }), object({ success: boolean() }), {
56341
- kind: "mutation",
56342
- auth: "admin"
56343
56332
  }), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
56344
56333
  addonId: string(),
56345
56334
  settings: record(string(), unknown())
@@ -59316,6 +59305,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
59316
59305
  }), {
59317
59306
  kind: "mutation",
59318
59307
  auth: "admin"
59308
+ }), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
59309
+ rows: number$1().int().nonnegative(),
59310
+ secrets: number$1().int().nonnegative()
59311
+ }), {
59312
+ kind: "mutation",
59313
+ auth: "admin"
59314
+ }), method(object({
59315
+ integrationId: string().min(1),
59316
+ patch: record(string(), unknown())
59317
+ }), object({ written: boolean() }), {
59318
+ kind: "mutation",
59319
+ auth: "admin"
59320
+ }), method(object({
59321
+ integrationId: string().min(1),
59322
+ keys: array(string().min(1))
59323
+ }), object({
59324
+ present: boolean(),
59325
+ removed: record(string(), unknown())
59326
+ }), {
59327
+ kind: "mutation",
59328
+ auth: "admin"
59319
59329
  });
59320
59330
  method(object({
59321
59331
  sourceUrl: string(),
@@ -80642,11 +80652,15 @@ discriminatedUnion("kind", [object({
80642
80652
  * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
80643
80653
  * near F. A device that is not near one level most of the time has no floor.
80644
80654
  * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
80645
- * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
80646
- * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
80655
+ * 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
80656
+ * display waking): it is neither a run nor a pause. Among the remaining
80657
+ * episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
80658
+ * two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
80659
+ * a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
80660
+ * is no run.
80647
80661
  * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
80648
- * grid a person would type; stop dwell covers the longest pause; start dwell
80649
- * covers the longest standby blip above T.
80662
+ * grid a person would type; stop dwell covers the longest pause and the
80663
+ * kind's floor; start dwell covers the longest pulse and standby blip above T.
80650
80664
  * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
80651
80665
  * run must hold exactly one true interval and nothing may flap outside.
80652
80666
  */
@@ -80657,6 +80671,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
80657
80671
  30 * SECOND_MS;
80658
80672
  60 * SECOND_MS;
80659
80673
  20 * MINUTE_MS$1;
80674
+ 90 * SECOND_MS;
80675
+ 30 * MINUTE_MS$1;
80676
+ 10 * MINUTE_MS$1;
80677
+ DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
80660
80678
  10 * SECOND_MS;
80661
80679
  10 * SECOND_MS;
80662
80680
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
@@ -85976,13 +85994,6 @@ Object.freeze({
85976
85994
  access: "view",
85977
85995
  role: "admin"
85978
85996
  },
85979
- "integrations.getSettings": {
85980
- capName: "integrations",
85981
- capScope: "system",
85982
- addonId: null,
85983
- access: "view",
85984
- role: "admin"
85985
- },
85986
85997
  "integrations.list": {
85987
85998
  capName: "integrations",
85988
85999
  capScope: "system",
@@ -85990,13 +86001,6 @@ Object.freeze({
85990
86001
  access: "view",
85991
86002
  role: "admin"
85992
86003
  },
85993
- "integrations.setSettings": {
85994
- capName: "integrations",
85995
- capScope: "system",
85996
- addonId: null,
85997
- access: "create",
85998
- role: "admin"
85999
- },
86000
86004
  "integrations.testConnection": {
86001
86005
  capName: "integrations",
86002
86006
  capScope: "system",
@@ -86991,6 +86995,13 @@ Object.freeze({
86991
86995
  access: "view",
86992
86996
  role: "admin"
86993
86997
  },
86998
+ "migrations.clearLegacyIntegrationRows": {
86999
+ capName: "migrations",
87000
+ capScope: "system",
87001
+ addonId: null,
87002
+ access: "delete",
87003
+ role: "admin"
87004
+ },
86994
87005
  "migrations.declareOwner": {
86995
87006
  capName: "migrations",
86996
87007
  capScope: "system",
@@ -86998,6 +87009,13 @@ Object.freeze({
86998
87009
  access: "create",
86999
87010
  role: "admin"
87000
87011
  },
87012
+ "migrations.deleteLegacyIntegrationRowKeys": {
87013
+ capName: "migrations",
87014
+ capScope: "system",
87015
+ addonId: null,
87016
+ access: "delete",
87017
+ role: "admin"
87018
+ },
87001
87019
  "migrations.dryRun": {
87002
87020
  capName: "migrations",
87003
87021
  capScope: "system",
@@ -87033,6 +87051,20 @@ Object.freeze({
87033
87051
  access: "create",
87034
87052
  role: "admin"
87035
87053
  },
87054
+ "migrations.patchLegacyIntegrationRows": {
87055
+ capName: "migrations",
87056
+ capScope: "system",
87057
+ addonId: null,
87058
+ access: "create",
87059
+ role: "admin"
87060
+ },
87061
+ "migrations.readLegacyIntegrationRows": {
87062
+ capName: "migrations",
87063
+ capScope: "system",
87064
+ addonId: null,
87065
+ access: "view",
87066
+ role: "admin"
87067
+ },
87036
87068
  "migrations.restorePreMigration": {
87037
87069
  capName: "migrations",
87038
87070
  capScope: "system",
@@ -145507,18 +145539,10 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
145507
145539
  try {
145508
145540
  const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id);
145509
145541
  const surviving = new Set(mine.map((i) => i.id));
145510
- for (const integration of mine) {
145511
- const settings = await this.ctx.api.integrations.getSettings.query({ id: integration.id });
145512
- const brokerId = typeof settings["brokerId"] === "string" ? settings["brokerId"] : void 0;
145513
- if (brokerId === void 0) continue;
145514
- if (!this.activeBrokers.some((b) => b.id === brokerId)) {
145515
- this.ctx.logger.warn("Alexa integration→broker: linked broker not found", { meta: {
145516
- integrationId: integration.id,
145517
- brokerId
145518
- } });
145519
- continue;
145520
- }
145521
- this.requireRegistry().linkIntegration(integration.id, brokerId);
145542
+ for (const broker of this.activeBrokers) {
145543
+ const integrationId = broker.integrationId;
145544
+ if (integrationId === void 0 || !surviving.has(integrationId)) continue;
145545
+ this.requireRegistry().linkIntegration(integrationId, broker.id);
145522
145546
  }
145523
145547
  const toRemove = this.activeBrokers.filter((b) => b.integrationId !== void 0 && !surviving.has(b.integrationId)).map((b) => b.id);
145524
145548
  if (toRemove.length === 0) return;
@@ -145560,9 +145584,9 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
145560
145584
  },
145561
145585
  logger: this.ctx.logger,
145562
145586
  getBrokerIdForIntegration: async (id) => {
145563
- const brokerId = (await this.ctx.api.integrations.getSettings.query({ id }))["brokerId"];
145564
- if (typeof brokerId !== "string") throw new Error(`integration ${id} has no linked brokerId`);
145565
- return brokerId;
145587
+ const broker = this.activeBrokers.find((entry) => entry.integrationId === id);
145588
+ if (broker === void 0) throw new Error(`integration ${id} has no linked brokerId`);
145589
+ return broker.id;
145566
145590
  },
145567
145591
  listAdoptedAlexa: async () => {
145568
145592
  const reg = this.ctx.kernel.deviceRegistry;
package/dist/addon.mjs CHANGED
@@ -6042,7 +6042,7 @@ function number(params) {
6042
6042
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
6043
6043
  }
6044
6044
  //#endregion
6045
- //#region ../types/dist/sleep-Cv4Zmie9.mjs
6045
+ //#region ../types/dist/sleep-9TIHFj1w.mjs
6046
6046
  /**
6047
6047
  * The audio chunk plane's byte format, and the ONE expansion from a coded
6048
6048
  * window to float samples (D455).
@@ -7986,10 +7986,9 @@ var BaseAddon = class {
7986
7986
  *
7987
7987
  * Override it only when an `instanceMode: multiple` addon's instances differ: an NVR integration
7988
7988
  * needs its connection fields, the default integration the addon's own sections. It is the
7989
- * SHAPE of the form only — the values live in `integrations.getSettings`, and the write path is
7990
- * unchanged (`integrations.setSettings` for an account integration).
7989
+ * SHAPE of the form only — the values live on the instance record.
7991
7990
  */
7992
- async integrationSettingsSchema(_instance) {
7991
+ async integrationFormSchema(_instance) {
7993
7992
  return null;
7994
7993
  }
7995
7994
  /**
@@ -8035,7 +8034,7 @@ var BaseAddon = class {
8035
8034
  * per-instance schema when it declares one, else its global schema (what they always showed).
8036
8035
  */
8037
8036
  async getIntegrationFormSchema(instance, nodeId) {
8038
- const scoped = await this.integrationSettingsSchema(instance);
8037
+ const scoped = await this.integrationFormSchema(instance);
8039
8038
  if (scoped === null) return this.getGlobalSettings(void 0, void 0, nodeId);
8040
8039
  return hydrateSchema(scoped, {}, { inlineSecretsAsViews: true });
8041
8040
  }
@@ -9309,6 +9308,7 @@ function defineEntryKind(name, spec) {
9309
9308
  class: "config",
9310
9309
  writeTrigger: spec.writeTrigger ?? "an operator adds or edits an entry in the entries UI",
9311
9310
  retention: { none: "an entry goes only when the operator deletes it" },
9311
+ ...spec.maxDataBytes === void 0 ? {} : { maxDataBytes: spec.maxDataBytes },
9312
9312
  ...spec.database === void 0 ? {} : { database: spec.database },
9313
9313
  ...spec.indexes === void 0 ? {} : { indexes: spec.indexes },
9314
9314
  ...spec.secretArrayKeys === void 0 ? {} : { secretArrayKeys: spec.secretArrayKeys },
@@ -11978,7 +11978,7 @@ object({
11978
11978
  params: record(string(), union([string(), number$1()])).optional()
11979
11979
  });
11980
11980
  //#endregion
11981
- //#region ../types/dist/composition-CRNwcFYY.mjs
11981
+ //#region ../types/dist/composition-pOHbTzRB.mjs
11982
11982
  /**
11983
11983
  * The ffmpeg build every CamStack node downloads, per platform and arch.
11984
11984
  *
@@ -50458,6 +50458,9 @@ var RunningProposalEvidenceSchema = object({
50458
50458
  runsFound: number$1().int().nonnegative(),
50459
50459
  pausesFound: number$1().int().nonnegative(),
50460
50460
  longestPauseMs: number$1().nonnegative(),
50461
+ /** Episodes shorter than ~90 s (an anti-crease pulse, a display waking): never a run, never a pause. */
50462
+ pulsesFound: number$1().int().nonnegative(),
50463
+ longestPulseMs: number$1().nonnegative(),
50461
50464
  idleFloorW: number$1(),
50462
50465
  noiseCeilingW: number$1(),
50463
50466
  plateauW: number$1(),
@@ -56303,11 +56306,7 @@ var CreateIntegrationInputSchema = object({
56303
56306
  info: record(string(), unknown()).optional(),
56304
56307
  /** `stableId` of the discovery candidate the form was seeded from (D984). */
56305
56308
  originStableId: string().optional(),
56306
- settings: record(string(), unknown()).optional(),
56307
- /** Keys of `settings` the form's schema declares secret (by type) — kept in
56308
- * the keychain, not the table (D787). */
56309
- secretKeys: array(string()).optional(),
56310
- skipRestart: boolean().optional()
56309
+ settings: record(string(), unknown()).optional()
56311
56310
  });
56312
56311
  var UpdateIntegrationInputSchema = object({
56313
56312
  id: string(),
@@ -56328,16 +56327,6 @@ method(_void(), array(IntegrationWithStateSchema)), method(object({ id: string()
56328
56327
  }), method(object({ id: string() }), DeleteIntegrationResultSchema, {
56329
56328
  kind: "mutation",
56330
56329
  auth: "admin"
56331
- }), method(object({ id: string() }), record(string(), unknown()), { auth: "admin" }), method(object({
56332
- id: string(),
56333
- settings: record(string(), unknown()),
56334
- /** Keys the form's schema declares secret (by type) — keychain-stored (D787). */
56335
- secretKeys: array(string()).optional(),
56336
- /** The integration's own addon applies the change in-process and asks the hub not to respawn it. */
56337
- skipRestart: boolean().optional()
56338
- }), object({ success: boolean() }), {
56339
- kind: "mutation",
56340
- auth: "admin"
56341
56330
  }), method(_void(), array(AvailableIntegrationTypeSchema), { auth: "admin" }), method(object({
56342
56331
  addonId: string(),
56343
56332
  settings: record(string(), unknown())
@@ -59314,6 +59303,27 @@ method(object({}), object({ entries: array(MigrationLedgerEntrySchema) }), { aut
59314
59303
  }), {
59315
59304
  kind: "mutation",
59316
59305
  auth: "admin"
59306
+ }), method(object({ integrationId: string().min(1) }), record(string(), unknown()), { auth: "admin" }), method(object({ integrationId: string().min(1) }), object({
59307
+ rows: number$1().int().nonnegative(),
59308
+ secrets: number$1().int().nonnegative()
59309
+ }), {
59310
+ kind: "mutation",
59311
+ auth: "admin"
59312
+ }), method(object({
59313
+ integrationId: string().min(1),
59314
+ patch: record(string(), unknown())
59315
+ }), object({ written: boolean() }), {
59316
+ kind: "mutation",
59317
+ auth: "admin"
59318
+ }), method(object({
59319
+ integrationId: string().min(1),
59320
+ keys: array(string().min(1))
59321
+ }), object({
59322
+ present: boolean(),
59323
+ removed: record(string(), unknown())
59324
+ }), {
59325
+ kind: "mutation",
59326
+ auth: "admin"
59317
59327
  });
59318
59328
  method(object({
59319
59329
  sourceUrl: string(),
@@ -80640,11 +80650,15 @@ discriminatedUnion("kind", [object({
80640
80650
  * 1. idle floor F = time-weighted median; noise ceiling N = highest value seen
80641
80651
  * near F. A device that is not near one level most of the time has no floor.
80642
80652
  * 2. coarse activity = above max(2N, N + 5 W); consecutive stretches are episodes.
80643
- * 3. gaps between episodes split in two by the largest log-scale jump (>= 3x):
80644
- * the short ones are pauses INSIDE a run (a soak), the long ones separate runs.
80653
+ * 3. an episode shorter than `PULSE_MAX_MS` is a PULSE (an anti-crease tumble, a
80654
+ * display waking): it is neither a run nor a pause. Among the remaining
80655
+ * episodes, gaps over `PAUSE_MAX_MS` always separate runs; the rest split in
80656
+ * two by the largest log-scale jump (>= 3x): the short ones are pauses INSIDE
80657
+ * a run (a soak), the long ones separate runs. A stretch under `MIN_RUN_MS`
80658
+ * is no run.
80645
80659
  * 4. T = geometric mean of N and the plateau's 10th percentile, snapped to a
80646
- * grid a person would type; stop dwell covers the longest pause; start dwell
80647
- * covers the longest standby blip above T.
80660
+ * grid a person would type; stop dwell covers the longest pause and the
80661
+ * kind's floor; start dwell covers the longest pulse and standby blip above T.
80648
80662
  * 5. the numbers are proved by REPLAY through the real `dwell` evaluation: each
80649
80663
  * run must hold exactly one true interval and nothing may flap outside.
80650
80664
  */
@@ -80655,6 +80669,10 @@ var MINUTE_MS$1 = 60 * SECOND_MS;
80655
80669
  30 * SECOND_MS;
80656
80670
  60 * SECOND_MS;
80657
80671
  20 * MINUTE_MS$1;
80672
+ 90 * SECOND_MS;
80673
+ 30 * MINUTE_MS$1;
80674
+ 10 * MINUTE_MS$1;
80675
+ DeviceType.Dryer, 3 * MINUTE_MS$1, DeviceType.Dishwasher, 3 * MINUTE_MS$1, DeviceType.Washer, 10 * MINUTE_MS$1;
80658
80676
  10 * SECOND_MS;
80659
80677
  10 * SECOND_MS;
80660
80678
  DeviceFeature.FanSpeed, DeviceFeature.FanPreset, DeviceFeature.FanDirection, DeviceFeature.FanOscillating, DeviceFeature.CoverStoppable, DeviceFeature.CoverPositionable, DeviceFeature.CoverTilt, DeviceFeature.ValvePositionable, DeviceFeature.MediaPlayerVolume, DeviceFeature.ClimateFanMode;
@@ -85974,13 +85992,6 @@ Object.freeze({
85974
85992
  access: "view",
85975
85993
  role: "admin"
85976
85994
  },
85977
- "integrations.getSettings": {
85978
- capName: "integrations",
85979
- capScope: "system",
85980
- addonId: null,
85981
- access: "view",
85982
- role: "admin"
85983
- },
85984
85995
  "integrations.list": {
85985
85996
  capName: "integrations",
85986
85997
  capScope: "system",
@@ -85988,13 +85999,6 @@ Object.freeze({
85988
85999
  access: "view",
85989
86000
  role: "admin"
85990
86001
  },
85991
- "integrations.setSettings": {
85992
- capName: "integrations",
85993
- capScope: "system",
85994
- addonId: null,
85995
- access: "create",
85996
- role: "admin"
85997
- },
85998
86002
  "integrations.testConnection": {
85999
86003
  capName: "integrations",
86000
86004
  capScope: "system",
@@ -86989,6 +86993,13 @@ Object.freeze({
86989
86993
  access: "view",
86990
86994
  role: "admin"
86991
86995
  },
86996
+ "migrations.clearLegacyIntegrationRows": {
86997
+ capName: "migrations",
86998
+ capScope: "system",
86999
+ addonId: null,
87000
+ access: "delete",
87001
+ role: "admin"
87002
+ },
86992
87003
  "migrations.declareOwner": {
86993
87004
  capName: "migrations",
86994
87005
  capScope: "system",
@@ -86996,6 +87007,13 @@ Object.freeze({
86996
87007
  access: "create",
86997
87008
  role: "admin"
86998
87009
  },
87010
+ "migrations.deleteLegacyIntegrationRowKeys": {
87011
+ capName: "migrations",
87012
+ capScope: "system",
87013
+ addonId: null,
87014
+ access: "delete",
87015
+ role: "admin"
87016
+ },
86999
87017
  "migrations.dryRun": {
87000
87018
  capName: "migrations",
87001
87019
  capScope: "system",
@@ -87031,6 +87049,20 @@ Object.freeze({
87031
87049
  access: "create",
87032
87050
  role: "admin"
87033
87051
  },
87052
+ "migrations.patchLegacyIntegrationRows": {
87053
+ capName: "migrations",
87054
+ capScope: "system",
87055
+ addonId: null,
87056
+ access: "create",
87057
+ role: "admin"
87058
+ },
87059
+ "migrations.readLegacyIntegrationRows": {
87060
+ capName: "migrations",
87061
+ capScope: "system",
87062
+ addonId: null,
87063
+ access: "view",
87064
+ role: "admin"
87065
+ },
87034
87066
  "migrations.restorePreMigration": {
87035
87067
  capName: "migrations",
87036
87068
  capScope: "system",
@@ -145505,18 +145537,10 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
145505
145537
  try {
145506
145538
  const mine = (await this.ctx.api.integrations.list.query()).filter((i) => i.addonId === this.ctx.id);
145507
145539
  const surviving = new Set(mine.map((i) => i.id));
145508
- for (const integration of mine) {
145509
- const settings = await this.ctx.api.integrations.getSettings.query({ id: integration.id });
145510
- const brokerId = typeof settings["brokerId"] === "string" ? settings["brokerId"] : void 0;
145511
- if (brokerId === void 0) continue;
145512
- if (!this.activeBrokers.some((b) => b.id === brokerId)) {
145513
- this.ctx.logger.warn("Alexa integration→broker: linked broker not found", { meta: {
145514
- integrationId: integration.id,
145515
- brokerId
145516
- } });
145517
- continue;
145518
- }
145519
- this.requireRegistry().linkIntegration(integration.id, brokerId);
145540
+ for (const broker of this.activeBrokers) {
145541
+ const integrationId = broker.integrationId;
145542
+ if (integrationId === void 0 || !surviving.has(integrationId)) continue;
145543
+ this.requireRegistry().linkIntegration(integrationId, broker.id);
145520
145544
  }
145521
145545
  const toRemove = this.activeBrokers.filter((b) => b.integrationId !== void 0 && !surviving.has(b.integrationId)).map((b) => b.id);
145522
145546
  if (toRemove.length === 0) return;
@@ -145558,9 +145582,9 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
145558
145582
  },
145559
145583
  logger: this.ctx.logger,
145560
145584
  getBrokerIdForIntegration: async (id) => {
145561
- const brokerId = (await this.ctx.api.integrations.getSettings.query({ id }))["brokerId"];
145562
- if (typeof brokerId !== "string") throw new Error(`integration ${id} has no linked brokerId`);
145563
- return brokerId;
145585
+ const broker = this.activeBrokers.find((entry) => entry.integrationId === id);
145586
+ if (broker === void 0) throw new Error(`integration ${id} has no linked brokerId`);
145587
+ return broker.id;
145564
145588
  },
145565
145589
  listAdoptedAlexa: async () => {
145566
145590
  const reg = this.ctx.kernel.deviceRegistry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-import-alexa",
3
- "version": "0.2.185",
3
+ "version": "0.2.186",
4
4
  "description": "Alexa device-import provider for CamStack — imports the smart-home devices in a user's Alexa account via the unofficial alexa-remote2 cookie/token client (the inverse of the Alexa exporter)",
5
5
  "keywords": [
6
6
  "camstack",
@@ -72,7 +72,7 @@
72
72
  }
73
73
  ],
74
74
  "requires": {
75
- "server": ">=1.2.763"
75
+ "server": ">=1.2.770"
76
76
  }
77
77
  },
78
78
  "files": [