@homebridge-plugins/homebridge-updater 3.1.4 → 3.1.6

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.
@@ -3,12 +3,15 @@ export declare class PluginUpdateMatterPlatform {
3
3
  private readonly api;
4
4
  private updateSensor;
5
5
  private failureSensor;
6
+ private readonly staleAccessories;
6
7
  constructor(log: Logging, config: PlatformConfig, api: API);
7
8
  /**
8
9
  * Called by Homebridge for each accessory found in the platform cache.
9
- * When running in Matter mode, all cached HAP accessories are stale — unregister
10
- * them immediately to prevent ghost accessories from appearing in HomeKit.
10
+ * When running in Matter mode, all cached HAP accessories are stale — collect
11
+ * them here so they can be removed once `didFinishLaunching` fires, at which
12
+ * point the bridge is fully initialized and can process unregister calls.
11
13
  */
12
14
  configureAccessory(accessory: PlatformAccessory): void;
15
+ private removeStaleAccessories;
13
16
  }
14
17
  //# sourceMappingURL=Platform.Matter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Platform.Matter.d.ts","sourceRoot":"","sources":["../src/Platform.Matter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAOjF,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IACzB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAAe;gBAExB,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG;IAe1D;;;;OAIG;IACH,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;CAGvD"}
1
+ {"version":3,"file":"Platform.Matter.d.ts","sourceRoot":"","sources":["../src/Platform.Matter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAOjF,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IACzB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA0B;gBAE/C,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG;IAiB1D;;;;;OAKG;IACH,kBAAkB,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAItD,OAAO,CAAC,sBAAsB;CAO/B"}
@@ -6,6 +6,7 @@ export class PluginUpdateMatterPlatform {
6
6
  api;
7
7
  updateSensor;
8
8
  failureSensor;
9
+ staleAccessories = [];
9
10
  constructor(log, config, api) {
10
11
  this.api = api;
11
12
  this.failureSensor = new FailureSensor(log, api, config.failureSensorType || config.sensorType, 'matter');
@@ -19,14 +20,24 @@ export class PluginUpdateMatterPlatform {
19
20
  const failureDeviceName = `${deviceName} Failure`;
20
21
  this.failureSensor.configure({ displayName: failureDeviceName });
21
22
  }
23
+ // Defer removal of stale HAP accessories until the bridge is fully initialized
24
+ api.on('didFinishLaunching', this.removeStaleAccessories.bind(this));
22
25
  }
23
26
  /**
24
27
  * Called by Homebridge for each accessory found in the platform cache.
25
- * When running in Matter mode, all cached HAP accessories are stale — unregister
26
- * them immediately to prevent ghost accessories from appearing in HomeKit.
28
+ * When running in Matter mode, all cached HAP accessories are stale — collect
29
+ * them here so they can be removed once `didFinishLaunching` fires, at which
30
+ * point the bridge is fully initialized and can process unregister calls.
27
31
  */
28
32
  configureAccessory(accessory) {
29
- this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
33
+ this.staleAccessories.push(accessory);
34
+ }
35
+ removeStaleAccessories() {
36
+ if (this.staleAccessories.length === 0) {
37
+ return;
38
+ }
39
+ this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [...this.staleAccessories]);
40
+ this.staleAccessories.length = 0;
30
41
  }
31
42
  }
32
43
  //# sourceMappingURL=Platform.Matter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Platform.Matter.js","sourceRoot":"","sources":["../src/Platform.Matter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAEnD,MAAM,OAAO,0BAA0B;IACpB,GAAG,CAAK;IACjB,YAAY,CAAc;IAC1B,aAAa,CAAe;IAEpC,YAAY,GAAY,EAAE,MAAsB,EAAE,GAAQ;QACxD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QACzG,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;YACrD,QAAQ,EAAE,QAAQ;YAClB,oBAAoB,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;SACnH,CAAC,CAAA;QACF,4EAA4E;QAC5E,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,UAAU,GAAI,MAAc,CAAC,IAAI,IAAI,qBAAqB,CAAA;YAChE,MAAM,iBAAiB,GAAG,GAAG,UAAU,UAAU,CAAA;YACjD,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAS,CAAC,CAAA;QACzE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,kBAAkB,CAAC,SAA4B;QAC7C,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,WAAW,EAAE,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IACjF,CAAC;CACF"}
1
+ {"version":3,"file":"Platform.Matter.js","sourceRoot":"","sources":["../src/Platform.Matter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAEnD,MAAM,OAAO,0BAA0B;IACpB,GAAG,CAAK;IACjB,YAAY,CAAc;IAC1B,aAAa,CAAe;IACnB,gBAAgB,GAAwB,EAAE,CAAA;IAE3D,YAAY,GAAY,EAAE,MAAsB,EAAE,GAAQ;QACxD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QACzG,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;YACrD,QAAQ,EAAE,QAAQ;YAClB,oBAAoB,EAAE,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;SACnH,CAAC,CAAA;QACF,4EAA4E;QAC5E,IAAI,sBAAsB,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,MAAM,UAAU,GAAI,MAAc,CAAC,IAAI,IAAI,qBAAqB,CAAA;YAChE,MAAM,iBAAiB,GAAG,GAAG,UAAU,UAAU,CAAA;YACjD,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAS,CAAC,CAAA;QACzE,CAAC;QACD,+EAA+E;QAC/E,GAAG,CAAC,EAAE,CAAC,oBAAoB,EAAE,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACtE,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,SAA4B;QAC7C,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACvC,CAAC;IAEO,sBAAsB;QAC5B,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAM;QACR,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,WAAW,EAAE,aAAa,EAAE,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAA;QAC9F,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAA;IAClC,CAAC;CACF"}
@@ -6,10 +6,16 @@ import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
6
6
  * When the platform runs in Matter mode, any cached HAP accessories from a previous
7
7
  * HAP-mode run (including legacy v2 accessories) are stale and must be unregistered
8
8
  * to prevent ghost/duplicate sensors in HomeKit.
9
+ *
10
+ * Removal is intentionally deferred to `didFinishLaunching` — calling
11
+ * `unregisterPlatformAccessories` during the `configureAccessory` phase (before the
12
+ * bridge is fully initialized) causes Homebridge to throw
13
+ * "Cannot find the bridged Accessory to remove."
9
14
  */
10
15
  describe('PluginUpdateMatterPlatform stale HAP cleanup', () => {
11
16
  function buildMocks() {
12
17
  const unregisterCalls = [];
18
+ const didFinishListeners = [];
13
19
  const mockLog = {
14
20
  info: vi.fn(),
15
21
  warn: vi.fn(),
@@ -19,7 +25,11 @@ describe('PluginUpdateMatterPlatform stale HAP cleanup', () => {
19
25
  const mockApi = {
20
26
  matter: { registerPlatformAccessories: vi.fn(), uuid: { generate: vi.fn().mockReturnValue('matter-uuid') } },
21
27
  hap: { uuid: { generate: vi.fn().mockReturnValue('hap-uuid') } },
22
- on: vi.fn(),
28
+ on: vi.fn((event, cb) => {
29
+ if (event === 'didFinishLaunching') {
30
+ didFinishListeners.push(cb);
31
+ }
32
+ }),
23
33
  user: { storagePath: vi.fn().mockReturnValue('/tmp') },
24
34
  unregisterPlatformAccessories: vi.fn((...args) => {
25
35
  unregisterCalls.push({ pluginName: args[0], platformName: args[1], accessories: args[2] });
@@ -34,42 +44,81 @@ describe('PluginUpdateMatterPlatform stale HAP cleanup', () => {
34
44
  autoUpdatePlugins: false,
35
45
  autoUpdateNode: false,
36
46
  };
37
- return { mockLog, mockApi, mockConfig, unregisterCalls };
47
+ function fireDidFinishLaunching() {
48
+ for (const cb of didFinishListeners) {
49
+ cb();
50
+ }
51
+ }
52
+ return { mockLog, mockApi, mockConfig, unregisterCalls, fireDidFinishLaunching };
38
53
  }
39
54
  /**
40
- * Simulate configureAccessory logic directly to avoid importing real Homebridge modules.
55
+ * Build a simulator that mirrors PluginUpdateMatterPlatform's stale-accessory
56
+ * handling without importing the real class (which would pull in Homebridge modules).
41
57
  *
42
- * This mirrors what PluginUpdateMatterPlatform.configureAccessory does:
43
- * it must call api.unregisterPlatformAccessories for each stale HAP accessory.
58
+ * - configureAccessory: collects accessories into a stale list (no immediate removal)
59
+ * - removeStaleAccessories: called on didFinishLaunching; batches all collected
60
+ * accessories into a single unregisterPlatformAccessories call
44
61
  */
45
- function simulateConfigureAccessory(api, accessory) {
46
- api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
62
+ function buildSimulator(api) {
63
+ const staleAccessories = [];
64
+ function configureAccessory(accessory) {
65
+ staleAccessories.push(accessory);
66
+ }
67
+ function removeStaleAccessories() {
68
+ if (staleAccessories.length === 0) {
69
+ return;
70
+ }
71
+ api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [...staleAccessories]);
72
+ staleAccessories.length = 0;
73
+ }
74
+ return { configureAccessory, removeStaleAccessories };
47
75
  }
48
- it('unregisters a stale legacy v2 HAP accessory (PluginUpdate UUID)', () => {
76
+ it('does not unregister stale accessories immediately during configureAccessory', () => {
77
+ const { mockApi, unregisterCalls } = buildMocks();
78
+ const { configureAccessory } = buildSimulator(mockApi);
79
+ const legacyAccessory = { UUID: mockApi.hap.uuid.generate('PluginUpdate'), displayName: 'Homebridge Plugin Update' };
80
+ configureAccessory(legacyAccessory);
81
+ // Must NOT be called yet — bridge is not fully initialized until didFinishLaunching
82
+ expect(unregisterCalls).toHaveLength(0);
83
+ });
84
+ it('unregisters a stale legacy v2 HAP accessory (PluginUpdate UUID) after didFinishLaunching', () => {
49
85
  const { mockApi, unregisterCalls } = buildMocks();
86
+ const { configureAccessory, removeStaleAccessories } = buildSimulator(mockApi);
50
87
  const legacyAccessory = { UUID: mockApi.hap.uuid.generate('PluginUpdate'), displayName: 'Homebridge Plugin Update' };
51
- simulateConfigureAccessory(mockApi, legacyAccessory);
88
+ configureAccessory(legacyAccessory);
89
+ removeStaleAccessories();
52
90
  expect(unregisterCalls).toHaveLength(1);
53
91
  expect(unregisterCalls[0].pluginName).toBe(PLUGIN_NAME);
54
92
  expect(unregisterCalls[0].platformName).toBe(PLATFORM_NAME);
55
93
  expect(unregisterCalls[0].accessories).toContain(legacyAccessory);
56
94
  });
57
- it('unregisters a stale v3 HAP update-sensor accessory (PluginUpdateCheck-UpdateSensor UUID)', () => {
95
+ it('unregisters a stale v3 HAP update-sensor accessory (PluginUpdateCheck-UpdateSensor UUID) after didFinishLaunching', () => {
58
96
  const { mockApi, unregisterCalls } = buildMocks();
97
+ const { configureAccessory, removeStaleAccessories } = buildSimulator(mockApi);
59
98
  const v3Accessory = { UUID: mockApi.hap.uuid.generate('PluginUpdateCheck-UpdateSensor'), displayName: 'PluginUpdate' };
60
- simulateConfigureAccessory(mockApi, v3Accessory);
99
+ configureAccessory(v3Accessory);
100
+ removeStaleAccessories();
61
101
  expect(unregisterCalls).toHaveLength(1);
62
102
  expect(unregisterCalls[0].accessories).toContain(v3Accessory);
63
103
  });
64
- it('unregisters multiple stale accessories when called for each', () => {
104
+ it('unregisters multiple stale accessories in a single batch after didFinishLaunching', () => {
65
105
  const { mockApi, unregisterCalls } = buildMocks();
106
+ const { configureAccessory, removeStaleAccessories } = buildSimulator(mockApi);
66
107
  const accessory1 = { UUID: 'uuid-1', displayName: 'Accessory 1' };
67
108
  const accessory2 = { UUID: 'uuid-2', displayName: 'Accessory 2' };
68
- simulateConfigureAccessory(mockApi, accessory1);
69
- simulateConfigureAccessory(mockApi, accessory2);
70
- expect(unregisterCalls).toHaveLength(2);
109
+ configureAccessory(accessory1);
110
+ configureAccessory(accessory2);
111
+ removeStaleAccessories();
112
+ // All stale accessories are batched into a single unregister call
113
+ expect(unregisterCalls).toHaveLength(1);
71
114
  expect(unregisterCalls[0].accessories).toContain(accessory1);
72
- expect(unregisterCalls[1].accessories).toContain(accessory2);
115
+ expect(unregisterCalls[0].accessories).toContain(accessory2);
116
+ });
117
+ it('does not call unregisterPlatformAccessories when there are no cached accessories', () => {
118
+ const { mockApi, unregisterCalls } = buildMocks();
119
+ const { removeStaleAccessories } = buildSimulator(mockApi);
120
+ removeStaleAccessories();
121
+ expect(unregisterCalls).toHaveLength(0);
73
122
  });
74
123
  });
75
124
  //# sourceMappingURL=Platform.Matter.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Platform.Matter.test.js","sourceRoot":"","sources":["../src/Platform.Matter.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Platform.Matter.test.js","sourceRoot":"","sources":["../src/Platform.Matter.test.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import type { API } from 'homebridge';
2
- export declare function migratePlatformAliasInPluginConfigs(configs: Array<Record<string, unknown>>): number;
2
+ export declare function migratePlatformAliasInPluginConfigs(configs: unknown): number;
3
3
  export declare function migrateLegacyPlatformAlias(api: API): Promise<void>;
4
4
  //# sourceMappingURL=configMigration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"configMigration.d.ts","sourceRoot":"","sources":["../src/configMigration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAOrC,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAcnG;AAED,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BxE"}
1
+ {"version":3,"file":"configMigration.d.ts","sourceRoot":"","sources":["../src/configMigration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAoB,MAAM,YAAY,CAAA;AAUvD,wBAAgB,mCAAmC,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAc5E;AAED,wBAAsB,0BAA0B,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDxE"}
@@ -1,3 +1,5 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import path from 'node:path';
1
3
  import { PLUGIN_NAME, PLATFORM_NAME } from './settings.js';
2
4
  import { UiApi } from './ui-api.js';
3
5
  const LEGACY_PLATFORM_NAME = 'PluginUpdate';
@@ -26,6 +28,30 @@ export async function migrateLegacyPlatformAlias(api) {
26
28
  debug: () => { },
27
29
  };
28
30
  try {
31
+ // Primary approach: read config.json directly so that legacy 'PluginUpdate' entries
32
+ // are found and migrated regardless of which npm package name they were last saved
33
+ // under. This is required when upgrading from the old unscoped package
34
+ // (homebridge-plugin-update-check) or from a v2.x install where the platform alias
35
+ // was still 'PluginUpdate', because the Homebridge UI API only returns entries for
36
+ // the current plugin alias ('HomebridgeUpdater') and will return an empty array
37
+ // before the first migration completes.
38
+ const configPath = path.resolve(hbStoragePath, 'config.json');
39
+ let hbConfig;
40
+ try {
41
+ hbConfig = JSON.parse(readFileSync(configPath, 'utf8'));
42
+ }
43
+ catch {
44
+ hbConfig = undefined;
45
+ }
46
+ if (hbConfig?.platforms && Array.isArray(hbConfig.platforms)) {
47
+ const updatedDirect = migratePlatformAliasInPluginConfigs(hbConfig.platforms);
48
+ if (updatedDirect > 0) {
49
+ writeFileSync(configPath, JSON.stringify(hbConfig, null, 4), 'utf8');
50
+ }
51
+ // config.json was readable and parseable — no need to try the UI API.
52
+ return;
53
+ }
54
+ // config.json could not be read or parsed — fall back to the UI API.
29
55
  const uiApi = new UiApi(hbStoragePath, silentLog);
30
56
  if (!uiApi.isConfigured()) {
31
57
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"configMigration.js","sourceRoot":"","sources":["../src/configMigration.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAEnC,MAAM,oBAAoB,GAAG,cAAc,CAAA;AAE3C,MAAM,UAAU,mCAAmC,CAAC,OAAuC;IACzF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAA;IACV,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,cAAc,IAAI,OAAO,EAAE,CAAC;QACrC,IAAI,cAAc,EAAE,QAAQ,KAAK,oBAAoB,EAAE,CAAC;YACtD,cAAc,CAAC,QAAQ,GAAG,aAAa,CAAA;YACvC,OAAO,EAAE,CAAA;QACX,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,GAAQ;IACvD,MAAM,aAAa,GAAI,GAAG,CAAC,IAAY,EAAE,WAAW,EAAE,EAAE,CAAA;IACxD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAM;IACR,CAAC;IAED,MAAM,SAAS,GAAG;QAChB,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;QACd,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;QACd,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;QACf,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;KAChB,CAAA;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,aAAa,EAAE,SAAgB,CAAC,CAAA;QACxD,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC;YAC1B,OAAM;QACR,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,CAAA;QAC9D,MAAM,OAAO,GAAG,mCAAmC,CAAC,aAAa,CAAC,CAAA;QAClE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAM;QACR,CAAC;QAED,MAAM,KAAK,CAAC,kBAAkB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAA;QAC1D,MAAM,KAAK,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,8DAA8D;IAChE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"configMigration.js","sourceRoot":"","sources":["../src/configMigration.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,12 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { migratePlatformAliasInPluginConfigs } from './configMigration.js';
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest';
2
+ import path from 'node:path';
3
+ // Mock node:fs before any imports that use it — vitest hoists vi.mock automatically.
4
+ vi.mock('node:fs', () => ({
5
+ readFileSync: vi.fn(),
6
+ writeFileSync: vi.fn(),
7
+ }));
8
+ import * as fs from 'node:fs';
9
+ import { migratePlatformAliasInPluginConfigs, migrateLegacyPlatformAlias } from './configMigration.js';
3
10
  describe('config migration', () => {
4
11
  it('should migrate legacy platform alias in plugin config entries', () => {
5
12
  const pluginConfigs = [
@@ -19,5 +26,94 @@ describe('config migration', () => {
19
26
  expect(updated).toBe(0);
20
27
  expect(pluginConfigs[0].platform).toBe('HomebridgeUpdater');
21
28
  });
29
+ it('should return 0 for a non-array input', () => {
30
+ expect(migratePlatformAliasInPluginConfigs(null)).toBe(0);
31
+ expect(migratePlatformAliasInPluginConfigs(undefined)).toBe(0);
32
+ });
33
+ });
34
+ describe('migrateLegacyPlatformAlias (direct file migration)', () => {
35
+ const FAKE_STORAGE = path.join(path.sep, 'fake', 'homebridge');
36
+ const FAKE_CONFIG_PATH = path.resolve(FAKE_STORAGE, 'config.json');
37
+ const readFileSyncMock = vi.mocked(fs.readFileSync);
38
+ const writeFileSyncMock = vi.mocked(fs.writeFileSync);
39
+ function makeApi(storagePath) {
40
+ return {
41
+ user: { storagePath: () => storagePath },
42
+ };
43
+ }
44
+ beforeEach(() => {
45
+ vi.clearAllMocks();
46
+ });
47
+ it('should do nothing when storagePath is missing', async () => {
48
+ await migrateLegacyPlatformAlias(makeApi(undefined));
49
+ expect(readFileSyncMock).not.toHaveBeenCalled();
50
+ expect(writeFileSyncMock).not.toHaveBeenCalled();
51
+ });
52
+ it('should migrate PluginUpdate → HomebridgeUpdater entries directly in config.json', async () => {
53
+ const originalConfig = {
54
+ bridge: { name: 'Homebridge', username: 'AA:BB:CC:DD:EE:FF', port: 51826 },
55
+ platforms: [
56
+ { platform: 'PluginUpdate', name: 'Plugin Update', checkPluginUpdates: true },
57
+ { platform: 'OtherPlugin', name: 'Other' },
58
+ ],
59
+ };
60
+ readFileSyncMock.mockReturnValue(JSON.stringify(originalConfig));
61
+ writeFileSyncMock.mockImplementation(() => { });
62
+ await migrateLegacyPlatformAlias(makeApi(FAKE_STORAGE));
63
+ expect(writeFileSyncMock).toHaveBeenCalledTimes(1);
64
+ const [writtenPath, writtenData] = writeFileSyncMock.mock.calls[0];
65
+ expect(writtenPath).toBe(FAKE_CONFIG_PATH);
66
+ const written = JSON.parse(writtenData);
67
+ expect(written.platforms[0].platform).toBe('HomebridgeUpdater');
68
+ expect(written.platforms[0].name).toBe('Plugin Update');
69
+ expect(written.platforms[0].checkPluginUpdates).toBe(true);
70
+ // Unrelated platform entries must remain untouched
71
+ expect(written.platforms[1].platform).toBe('OtherPlugin');
72
+ });
73
+ it('should not write config.json when no legacy entries exist', async () => {
74
+ const currentConfig = {
75
+ bridge: { name: 'Homebridge', username: 'AA:BB:CC:DD:EE:FF', port: 51826 },
76
+ platforms: [
77
+ { platform: 'HomebridgeUpdater', name: 'Updater' },
78
+ ],
79
+ };
80
+ readFileSyncMock.mockReturnValue(JSON.stringify(currentConfig));
81
+ writeFileSyncMock.mockImplementation(() => { });
82
+ await migrateLegacyPlatformAlias(makeApi(FAKE_STORAGE));
83
+ expect(writeFileSyncMock).not.toHaveBeenCalled();
84
+ });
85
+ it('should not throw when config.json cannot be read', async () => {
86
+ readFileSyncMock.mockImplementation(() => {
87
+ throw new Error('ENOENT: no such file');
88
+ });
89
+ writeFileSyncMock.mockImplementation(() => { });
90
+ await expect(migrateLegacyPlatformAlias(makeApi(FAKE_STORAGE))).resolves.toBeUndefined();
91
+ expect(writeFileSyncMock).not.toHaveBeenCalled();
92
+ });
93
+ it('should preserve all config fields (_bridge, etc.) when migrating', async () => {
94
+ const configWithBridge = {
95
+ bridge: { name: 'Homebridge', username: 'AA:BB:CC:DD:EE:FF', port: 51826 },
96
+ platforms: [
97
+ {
98
+ platform: 'PluginUpdate',
99
+ name: 'Plugin Update',
100
+ _bridge: { username: '11:22:33:44:55:66', port: 51828, name: 'Plugin Update Child Bridge' },
101
+ checkPluginUpdates: true,
102
+ autoUpdatePlugins: false,
103
+ },
104
+ ],
105
+ };
106
+ readFileSyncMock.mockReturnValue(JSON.stringify(configWithBridge));
107
+ writeFileSyncMock.mockImplementation(() => { });
108
+ await migrateLegacyPlatformAlias(makeApi(FAKE_STORAGE));
109
+ expect(writeFileSyncMock).toHaveBeenCalledTimes(1);
110
+ const written = JSON.parse(writeFileSyncMock.mock.calls[0][1]);
111
+ const migratedPlatform = written.platforms[0];
112
+ expect(migratedPlatform.platform).toBe('HomebridgeUpdater');
113
+ // Child bridge config must be preserved intact
114
+ expect(migratedPlatform._bridge).toEqual(configWithBridge.platforms[0]._bridge);
115
+ expect(migratedPlatform.checkPluginUpdates).toBe(true);
116
+ expect(migratedPlatform.autoUpdatePlugins).toBe(false);
117
+ });
22
118
  });
23
119
  //# sourceMappingURL=configMigration.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"configMigration.test.js","sourceRoot":"","sources":["../src/configMigration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAE1E,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,aAAa,GAAmC;YACpD,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE;YACpD,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE;SAC3C,CAAA;QAED,MAAM,OAAO,GAAG,mCAAmC,CAAC,aAAa,CAAC,CAAA;QAElE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QAC3D,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,aAAa,GAAmC;YACpD,EAAE,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,SAAS,EAAE;SACnD,CAAA;QAED,MAAM,OAAO,GAAG,mCAAmC,CAAC,aAAa,CAAC,CAAA;QAElE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"configMigration.test.js","sourceRoot":"","sources":["../src/configMigration.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@homebridge-plugins/homebridge-updater",
3
3
  "displayName": "Homebridge Updater",
4
4
  "type": "module",
5
- "version": "3.1.4",
5
+ "version": "3.1.6",
6
6
  "description": "A Homebridge plugin for checking for updates to Homebridge and plugins",
7
7
  "author": "David Maher",
8
8
  "license": "BSD-2-Clause",