@nubisco/openbridge-compatibility-homebridge 0.29.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nubisco Lda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # @nubisco/openbridge-compatibility-homebridge
2
+
3
+ Compatibility shim that lets existing Homebridge `platform` plugins run inside OpenBridge unmodified.
4
+
5
+ Part of [OpenBridge](https://github.com/nubisco/openbridge), a local-first home automation bridge for developers.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @nubisco/openbridge-compatibility-homebridge
11
+ ```
12
+
13
+ Requires Node.js >= 20.
14
+
15
+ ## Documentation
16
+
17
+ See the [OpenBridge documentation](https://github.com/nubisco/openbridge#readme). This package is published from the OpenBridge monorepo and versioned in lockstep with the `openbridge` daemon.
18
+
19
+ ## License
20
+
21
+ MIT (c) Jose Silva
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prune.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/prune.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,149 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { mkdtempSync, rmSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ import { HomebridgeAPI } from '../index.js';
6
+ /**
7
+ * Minimal hap-nodejs stand-in. Only the surface HomebridgeAPI touches.
8
+ */
9
+ function fakeHap() {
10
+ class Accessory {
11
+ displayName;
12
+ UUID;
13
+ services = [];
14
+ category = 1;
15
+ constructor(displayName, UUID) {
16
+ this.displayName = displayName;
17
+ this.UUID = UUID;
18
+ }
19
+ getService() {
20
+ return { setCharacteristic: () => ({ setCharacteristic: () => ({}) }) };
21
+ }
22
+ addService() {
23
+ return {};
24
+ }
25
+ }
26
+ return {
27
+ Accessory,
28
+ Service: { AccessoryInformation: 'info' },
29
+ Characteristic: { Manufacturer: 'm', Model: 'mo', SerialNumber: 's', FirmwareRevision: 'f' },
30
+ Categories: { BRIDGE: 2 },
31
+ uuid: { generate: (s) => `uuid-${s}` },
32
+ };
33
+ }
34
+ function fakeBridge() {
35
+ return {
36
+ added: [],
37
+ removed: [],
38
+ addBridgedAccessory(acc) {
39
+ this.added.push(acc);
40
+ return acc;
41
+ },
42
+ removeBridgedAccessory(acc) {
43
+ this.removed.push(acc);
44
+ },
45
+ };
46
+ }
47
+ let home;
48
+ let api;
49
+ let bridge;
50
+ beforeEach(() => {
51
+ home = mkdtempSync(join(tmpdir(), 'ob-prune-'));
52
+ bridge = fakeBridge();
53
+ api = new HomebridgeAPI(fakeHap(), bridge);
54
+ // Keep the accessory cache inside the temp dir.
55
+ api.user.cachedAccessoryPath = () => home;
56
+ });
57
+ afterEach(() => {
58
+ rmSync(home, { recursive: true, force: true });
59
+ vi.restoreAllMocks();
60
+ });
61
+ /** Add an accessory attributed to a platform, as loadCachedAccessories would. */
62
+ function seed(displayName, uuid, platform) {
63
+ const acc = { displayName, UUID: uuid, _associatedPlatform: platform };
64
+ api._accessories.set(uuid, acc);
65
+ bridge.addBridgedAccessory(acc);
66
+ return acc;
67
+ }
68
+ describe('pruneOrphanedAccessories', () => {
69
+ it('removes accessories whose platform is no longer registered', () => {
70
+ api.registerPlatform('ShellyDS9', class {
71
+ });
72
+ seed('Pool Switch 1', 'u1', 'ShellyDS9');
73
+ seed('Home - Total', 'u2', 'Shelly3EM');
74
+ seed('Home - Fase A', 'u3', 'Shelly3EM');
75
+ const removed = api.pruneOrphanedAccessories();
76
+ // The uninstalled plugin's accessories go; the installed one's stay.
77
+ expect(removed.sort()).toEqual(['Home - Fase A', 'Home - Total']);
78
+ expect(api.getRawAccessories().map((a) => a.displayName)).toEqual(['Pool Switch 1']);
79
+ expect(bridge.removed.map((a) => a.UUID).sort()).toEqual(['u2', 'u3']);
80
+ });
81
+ it('reclaims the accessories of a plugin that loaded but was then unregistered as disabled', () => {
82
+ // A disabled plugin still has to be loaded before its platform name is
83
+ // knowable, so the loader registers it and then rolls the registration
84
+ // back. From here that is indistinguishable from never having registered,
85
+ // which is the point: its cached accessories must not survive as inert
86
+ // "Default-Manufacturer" entries in the Home app.
87
+ const before = api._platformRegistrations.length;
88
+ api.registerPlatform('ShellyDS9', class {
89
+ });
90
+ api._platformRegistrations.length = before;
91
+ seed('Pool Switch 1', 'u1', 'ShellyDS9');
92
+ seed('Pool Switch 2', 'u2', 'ShellyDS9');
93
+ expect(api.pruneOrphanedAccessories().sort()).toEqual(['Pool Switch 1', 'Pool Switch 2']);
94
+ expect(api.getRawAccessories()).toHaveLength(0);
95
+ expect(bridge.removed.map((a) => a.UUID).sort()).toEqual(['u1', 'u2']);
96
+ });
97
+ it('keeps accessories belonging to a registered platform', () => {
98
+ api.registerPlatform('WizSmarthome', class {
99
+ });
100
+ seed('Basement 1', 'u1', 'WizSmarthome');
101
+ expect(api.pruneOrphanedAccessories()).toEqual([]);
102
+ expect(api.getRawAccessories()).toHaveLength(1);
103
+ expect(bridge.removed).toEqual([]);
104
+ });
105
+ it('matches on plugin name as well as platform name', () => {
106
+ // publishExternalAccessories attributes by plugin name, not platform name.
107
+ api.registerPlatform('homebridge-camera-ffmpeg', 'Camera-ffmpeg', class {
108
+ }, true);
109
+ seed('Living Room', 'u1', 'homebridge-camera-ffmpeg');
110
+ seed('Lobby', 'u2', 'Camera-ffmpeg');
111
+ expect(api.pruneOrphanedAccessories()).toEqual([]);
112
+ expect(api.getRawAccessories()).toHaveLength(2);
113
+ });
114
+ it('leaves unattributed accessories alone', () => {
115
+ // No owner recorded, so it cannot be attributed. Silently deleting a user's
116
+ // HomeKit device is worse than leaving one stale entry behind.
117
+ seed('Mystery', 'u1', '');
118
+ expect(api.pruneOrphanedAccessories()).toEqual([]);
119
+ expect(api.getRawAccessories()).toHaveLength(1);
120
+ });
121
+ it('does nothing when there is nothing to prune', () => {
122
+ api.registerPlatform('ShellyDS9', class {
123
+ });
124
+ seed('Pool Switch 1', 'u1', 'ShellyDS9');
125
+ expect(api.pruneOrphanedAccessories()).toEqual([]);
126
+ });
127
+ it('survives a bridge that refuses the removal', () => {
128
+ api.registerPlatform('ShellyDS9', class {
129
+ });
130
+ bridge.removeBridgedAccessory = () => {
131
+ throw new Error('not bridged');
132
+ };
133
+ seed('Home - Total', 'u1', 'Shelly3EM');
134
+ // The accessory must still leave the map and the cache even if the bridge
135
+ // never had it.
136
+ expect(api.pruneOrphanedAccessories()).toEqual(['Home - Total']);
137
+ expect(api.getRawAccessories()).toEqual([]);
138
+ });
139
+ it('notifies the removal listener so the UI drops the device too', () => {
140
+ const onRemove = vi.fn();
141
+ api.onAccessoryRemove(onRemove);
142
+ api.registerPlatform('ShellyDS9', class {
143
+ });
144
+ seed('Home - Total', 'u1', 'Shelly3EM');
145
+ api.pruneOrphanedAccessories();
146
+ expect(onRemove).toHaveBeenCalledTimes(1);
147
+ });
148
+ });
149
+ //# sourceMappingURL=prune.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune.test.js","sourceRoot":"","sources":["../../src/__tests__/prune.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * @nubisco/openbridge-compatibility-homebridge
3
+ *
4
+ * Homebridge API compatibility shim for OpenBridge.
5
+ * Wraps hap-nodejs so Homebridge platform plugins can run inside OpenBridge.
6
+ */
7
+ import { EventEmitter } from 'events';
8
+ export declare function loadHapSync(): any;
9
+ export declare let hap: any;
10
+ export declare function initHap(hapNodeJs: any): void;
11
+ export interface PlatformRegistration {
12
+ pluginName: string;
13
+ platformName: string;
14
+ Constructor: new (...args: any[]) => any;
15
+ dynamic: boolean;
16
+ }
17
+ export interface AccessoryRegistration {
18
+ pluginName: string;
19
+ accessoryName: string;
20
+ Constructor: new (...args: any[]) => any;
21
+ }
22
+ export declare class HomebridgeAPI extends EventEmitter {
23
+ hap: any;
24
+ platformAccessory: any;
25
+ version: string;
26
+ serverVersion: string;
27
+ user: {
28
+ storagePath: () => string;
29
+ configPath: () => string;
30
+ persistPath: () => string;
31
+ cachedAccessoryPath: () => string;
32
+ };
33
+ private _bridge;
34
+ private _platformRegistrations;
35
+ private _platformInstances;
36
+ private _accessories;
37
+ private _onAccessoryAdd?;
38
+ private _onAccessoryRemove?;
39
+ /** Stored launch configs so platforms can be restarted after failure */
40
+ private _platformLaunchConfigs;
41
+ /** Tracks consecutive restart failures per platform for exponential backoff */
42
+ private _platformRestartAttempts;
43
+ /** Tracks last error time per platform to detect recurring failures */
44
+ private _platformLastError;
45
+ constructor(hapNodeJs: any, bridge: any);
46
+ onAccessoryAdd(fn: (accessory: any) => void): void;
47
+ onAccessoryRemove(fn: (accessory: any) => void): void;
48
+ /**
49
+ * Called by plugins in two forms:
50
+ * 4-arg: registerPlatform(pluginName, platformName, Constructor, dynamic)
51
+ * 2-arg: registerPlatform(platformName, Constructor, dynamic?)
52
+ */
53
+ registerPlatform(...args: any[]): void;
54
+ /**
55
+ * Called by plugins: homebridge.registerAccessory(pluginName, accessoryName, Constructor)
56
+ */
57
+ registerAccessory(_pluginName: string, _accessoryName: string, _Constructor: new (...args: any[]) => any): void;
58
+ /**
59
+ * Called by platform instances to add accessories to the bridge.
60
+ * api.registerPlatformAccessories(pluginName, platformName, [accessory, ...])
61
+ */
62
+ registerPlatformAccessories(_pluginName: string, _platformName: string, accessories: any | any[]): void;
63
+ /**
64
+ * Called by platform instances after mutating an accessory they already own,
65
+ * to persist the change. api.updatePlatformAccessories([accessory, ...])
66
+ *
67
+ * Homebridge only re-writes its accessory cache here, so we do the same: the
68
+ * accessory object is already live on the bridge, nothing needs re-adding.
69
+ * Plugins call this from discovery callbacks (often outside any try/catch),
70
+ * so it must never throw.
71
+ */
72
+ updatePlatformAccessories(accessories: any | any[]): void;
73
+ /**
74
+ * Called by some platform plugins to publish accessories as standalone (not bridged).
75
+ * In real Homebridge these get their own HAP server, but OpenBridge funnels
76
+ * everything through a single bridge so we add them as bridged accessories.
77
+ */
78
+ publishExternalAccessories(_pluginName: string, accessories: any | any[]): void;
79
+ /**
80
+ * Returns whether the running Homebridge version is >= the given semver string.
81
+ * We always return false (we are not Homebridge), which disables optional features
82
+ * like Adaptive Lighting that check for minimum versions.
83
+ */
84
+ versionGreaterOrEqual(_version: string): boolean;
85
+ getRawAccessories(): any[];
86
+ getAccessories(): SerializedAccessory[];
87
+ /**
88
+ * Called by platform instances to remove accessories.
89
+ */
90
+ unregisterPlatformAccessories(_pluginName: string, _platformName: string, accessories: any[]): void;
91
+ getPlatformRegistrations(): PlatformRegistration[];
92
+ /**
93
+ * Instantiate all registered platforms with the given config entries.
94
+ * registry is optional: if provided, each platform is registered as a
95
+ * PluginInstance so it appears in the OpenBridge UI plugins page.
96
+ */
97
+ launchPlatforms(configs: PlatformConfig[], log: any, registry?: any): Promise<void>;
98
+ /**
99
+ * Restart a platform that has failed. Removes old accessories,
100
+ * re-instantiates the platform, and re-emits didFinishLaunching.
101
+ */
102
+ restartPlatform(platformName: string): Promise<boolean>;
103
+ /**
104
+ * Returns the backoff delay (ms) for the next restart attempt of a platform.
105
+ * Exponential: 30s, 60s, 120s, 240s, capped at 5 minutes.
106
+ */
107
+ getRestartBackoff(platformName: string): number;
108
+ getPlatformInstances(): Map<string, any>;
109
+ /**
110
+ * Load previously cached accessories from disk and pre-populate
111
+ * the in-memory map + bridge so that platforms can re-adopt them
112
+ * via configureAccessory() before starting device discovery.
113
+ *
114
+ * Must be called after the bridge is set up but before launchPlatforms().
115
+ */
116
+ loadCachedAccessories(): void;
117
+ /**
118
+ * Drop cached accessories whose owning platform is not active.
119
+ *
120
+ * `loadCachedAccessories()` restores everything it finds and adds it to the
121
+ * bridge, because a platform has to be able to re-adopt its accessories via
122
+ * configureAccessory() before discovery starts. Nothing ever removed the
123
+ * accessories of a plugin that was no longer active, so they stayed on the
124
+ * bridge forever: still in the Home app, still listed in OpenBridge, but with
125
+ * no plugin behind them to update or control them. They show up as
126
+ * "Default-Manufacturer / Default-Model" entries that do nothing.
127
+ *
128
+ * "Not active" covers both an uninstalled plugin and a disabled one: the
129
+ * loader deliberately leaves a disabled plugin out of _platformRegistrations
130
+ * so it is reclaimed here rather than lingering as dead HomeKit entries.
131
+ *
132
+ * Attribution is by platform registration, not by discovery, so this is safe
133
+ * to call as soon as platforms have been launched: a platform registers at
134
+ * load time, long before it finishes finding devices.
135
+ *
136
+ * Accessories with no recorded owner are left alone. They cannot be
137
+ * attributed, and silently deleting a user's HomeKit devices is far worse
138
+ * than leaving one stale entry behind.
139
+ */
140
+ pruneOrphanedAccessories(): string[];
141
+ /**
142
+ * Persist the current accessory map to disk so accessories survive
143
+ * container restarts without being re-discovered by HomeKit.
144
+ */
145
+ private saveCachedAccessories;
146
+ }
147
+ export interface PlatformConfig {
148
+ platform: string;
149
+ [key: string]: unknown;
150
+ }
151
+ /** Minimal representation of an accessory stored on disk between restarts. */
152
+ export interface CachedAccessoryEntry {
153
+ UUID: string;
154
+ displayName: string;
155
+ category: number;
156
+ context: any;
157
+ associatedPlatform: string;
158
+ }
159
+ export interface SerializedCharacteristic {
160
+ uuid: string;
161
+ name: string;
162
+ value: unknown;
163
+ format: string;
164
+ perms: string[];
165
+ }
166
+ export interface SerializedService {
167
+ uuid: string;
168
+ name: string;
169
+ displayName: string;
170
+ characteristics: SerializedCharacteristic[];
171
+ }
172
+ export interface SerializedAccessory {
173
+ uuid: string;
174
+ displayName: string;
175
+ category: number;
176
+ services: SerializedService[];
177
+ reachable: boolean;
178
+ }
179
+ export declare function serializeAccessory(acc: any): SerializedAccessory;
180
+ /**
181
+ * Load a Homebridge-compatible plugin from a file path.
182
+ * Plugins use CommonJS: module.exports = function(homebridge) { ... }
183
+ */
184
+ export declare function loadHomebridgePlugin(pluginPath: string): (homebridge: HomebridgeAPI) => void;
185
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,677 @@
1
+ /**
2
+ * @nubisco/openbridge-compatibility-homebridge
3
+ *
4
+ * Homebridge API compatibility shim for OpenBridge.
5
+ * Wraps hap-nodejs so Homebridge platform plugins can run inside OpenBridge.
6
+ */
7
+ import { EventEmitter } from 'events';
8
+ import { createRequire } from 'module';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, resolve } from 'path';
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
12
+ import os from 'os';
13
+ import { Logger } from '@nubisco/openbridge-logger';
14
+ const hapLog = Logger.create('hap-compat');
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ // Synchronous load: hap-nodejs is CJS
17
+ export function loadHapSync() {
18
+ const req = createRequire(import.meta.url);
19
+ const candidates = [
20
+ resolve(__dirname, '../../../node_modules/hap-nodejs'),
21
+ resolve(__dirname, '../../../../node_modules/hap-nodejs'),
22
+ resolve(process.cwd(), 'node_modules/hap-nodejs'),
23
+ ];
24
+ for (const candidate of candidates) {
25
+ try {
26
+ return req(candidate);
27
+ }
28
+ catch {
29
+ /* try next */
30
+ }
31
+ }
32
+ throw new Error('hap-nodejs not found. Run: pnpm add hap-nodejs --filter @nubisco/openbridge-daemon');
33
+ }
34
+ export let hap = null;
35
+ export function initHap(hapNodeJs) {
36
+ hap = hapNodeJs;
37
+ }
38
+ /**
39
+ * The Homebridge API object passed to plugins.
40
+ * Plugins call: module.exports = function(homebridge) { homebridge.registerPlatform(...) }
41
+ */
42
+ /**
43
+ * PlatformAccessory: Homebridge-compatible wrapper around a hap.Accessory.
44
+ *
45
+ * hap-nodejs does NOT export PlatformAccessory; it is a Homebridge construct.
46
+ * Plugins call `new PlatformAccessory(displayName, uuid, category?)` and then
47
+ * use `.getService()`, `.addService()`, `.context`, etc.
48
+ */
49
+ function makePlatformAccessoryClass(hapNodeJs) {
50
+ const HapAccessory = hapNodeJs.Accessory;
51
+ class PlatformAccessory extends HapAccessory {
52
+ context = {};
53
+ _associatedPlugin;
54
+ _associatedPlatform;
55
+ constructor(displayName, uuid, category) {
56
+ super(displayName, uuid);
57
+ if (category !== undefined) {
58
+ this.category = category;
59
+ }
60
+ }
61
+ /**
62
+ * Override addService to match Homebridge's behavior:
63
+ * when a plugin calls addService(ServiceType, displayName) without a subtype and a service
64
+ * of the same UUID already exists, automatically use displayName as the subtype.
65
+ * Without this, hap-nodejs throws for accessories with multiple services of the same type
66
+ * (e.g. multiple TemperatureSensor services on a heat-pump accessory).
67
+ */
68
+ addService(serviceType, ...args) {
69
+ if (typeof serviceType === 'function' && args.length >= 1 && args[1] === undefined) {
70
+ const displayName = args[0];
71
+ const typeUUID = serviceType.UUID;
72
+ if (displayName && typeUUID) {
73
+ const hasConflict = this.services?.some((s) => s.UUID === typeUUID);
74
+ if (hasConflict) {
75
+ // Use displayName as subtype to allow multiple services of the same type
76
+ return super.addService(serviceType, displayName, displayName);
77
+ }
78
+ }
79
+ }
80
+ return super.addService(serviceType, ...args);
81
+ }
82
+ }
83
+ return PlatformAccessory;
84
+ }
85
+ export class HomebridgeAPI extends EventEmitter {
86
+ hap;
87
+ platformAccessory;
88
+ version = '2.6.0';
89
+ serverVersion = '2.6.0';
90
+ user;
91
+ _bridge;
92
+ _platformRegistrations = [];
93
+ _platformInstances = new Map();
94
+ _accessories = new Map();
95
+ _onAccessoryAdd;
96
+ _onAccessoryRemove;
97
+ /** Stored launch configs so platforms can be restarted after failure */
98
+ _platformLaunchConfigs = new Map();
99
+ /** Tracks consecutive restart failures per platform for exponential backoff */
100
+ _platformRestartAttempts = new Map();
101
+ /** Tracks last error time per platform to detect recurring failures */
102
+ _platformLastError = new Map();
103
+ constructor(hapNodeJs, bridge) {
104
+ super();
105
+ this._bridge = bridge;
106
+ // User storage paths (Homebridge plugins call api.user.storagePath(), etc.)
107
+ const storageBase = resolve(os.homedir(), '.openbridge');
108
+ this.user = {
109
+ storagePath: () => storageBase,
110
+ configPath: () => resolve(storageBase, 'config.json'),
111
+ persistPath: () => resolve(storageBase, 'persist'),
112
+ cachedAccessoryPath: () => resolve(storageBase, 'accessories'),
113
+ };
114
+ this.hap = hapNodeJs;
115
+ // Build PlatformAccessory from the hap.Accessory base class
116
+ this.platformAccessory = makePlatformAccessoryClass(hapNodeJs);
117
+ // Alias for plugins that access api.hap.Accessory.Categories
118
+ if (!this.hap.Accessory) {
119
+ this.hap.Accessory = { Categories: hapNodeJs.Categories };
120
+ }
121
+ else if (!this.hap.Accessory.Categories) {
122
+ this.hap.Accessory.Categories = hapNodeJs.Categories;
123
+ }
124
+ // Some plugins use api.hap.uuid
125
+ if (!this.hap.uuid) {
126
+ this.hap.uuid = hapNodeJs.uuid;
127
+ }
128
+ }
129
+ onAccessoryAdd(fn) {
130
+ this._onAccessoryAdd = fn;
131
+ }
132
+ onAccessoryRemove(fn) {
133
+ this._onAccessoryRemove = fn;
134
+ }
135
+ /**
136
+ * Called by plugins in two forms:
137
+ * 4-arg: registerPlatform(pluginName, platformName, Constructor, dynamic)
138
+ * 2-arg: registerPlatform(platformName, Constructor, dynamic?)
139
+ */
140
+ registerPlatform(...args) {
141
+ let pluginName;
142
+ let platformName;
143
+ let Constructor;
144
+ let dynamic;
145
+ if (typeof args[0] === 'string' && typeof args[1] === 'string') {
146
+ // 4-arg form: (pluginName, platformName, Constructor, dynamic)
147
+ ;
148
+ [pluginName, platformName, Constructor, dynamic = false] = args;
149
+ }
150
+ else {
151
+ // 2-arg form: (platformName, Constructor, dynamic?)
152
+ pluginName = args[0];
153
+ platformName = args[0];
154
+ Constructor = args[1];
155
+ dynamic = args[2] ?? false;
156
+ }
157
+ this._platformRegistrations.push({ pluginName, platformName, Constructor, dynamic });
158
+ }
159
+ /**
160
+ * Called by plugins: homebridge.registerAccessory(pluginName, accessoryName, Constructor)
161
+ */
162
+ registerAccessory(_pluginName, _accessoryName, _Constructor) {
163
+ // TODO: implement accessory (non-platform) registration
164
+ }
165
+ /**
166
+ * Called by platform instances to add accessories to the bridge.
167
+ * api.registerPlatformAccessories(pluginName, platformName, [accessory, ...])
168
+ */
169
+ registerPlatformAccessories(_pluginName, _platformName, accessories) {
170
+ const arr = Array.isArray(accessories) ? accessories : [accessories];
171
+ hapLog.info(`registerPlatformAccessories: adding ${arr.length} accessory(ies)`);
172
+ for (const acc of arr) {
173
+ try {
174
+ if (!acc?.UUID) {
175
+ hapLog.warn(` skipped accessory with no UUID: ${acc?.displayName}`);
176
+ continue;
177
+ }
178
+ acc._associatedPlatform = _platformName;
179
+ // If a cached version is already on the bridge, remove it first
180
+ const existing = this._accessories.get(acc.UUID);
181
+ if (existing && this._bridge) {
182
+ try {
183
+ this._bridge.removeBridgedAccessory(existing, false);
184
+ }
185
+ catch {
186
+ /* not on bridge yet */
187
+ }
188
+ }
189
+ hapLog.info(` + ${acc.displayName} (UUID: ${acc.UUID})`);
190
+ this._accessories.set(acc.UUID, acc);
191
+ if (this._bridge) {
192
+ try {
193
+ this._bridge.addBridgedAccessory(acc);
194
+ }
195
+ catch (bridgeErr) {
196
+ hapLog.warn(` bridge.addBridgedAccessory failed (non-fatal): ${bridgeErr}`);
197
+ }
198
+ }
199
+ this._onAccessoryAdd?.(acc);
200
+ }
201
+ catch (err) {
202
+ hapLog.error(` ✗ failed to register ${acc?.displayName}: ${err}`);
203
+ }
204
+ }
205
+ this.saveCachedAccessories();
206
+ }
207
+ /**
208
+ * Called by platform instances after mutating an accessory they already own,
209
+ * to persist the change. api.updatePlatformAccessories([accessory, ...])
210
+ *
211
+ * Homebridge only re-writes its accessory cache here, so we do the same: the
212
+ * accessory object is already live on the bridge, nothing needs re-adding.
213
+ * Plugins call this from discovery callbacks (often outside any try/catch),
214
+ * so it must never throw.
215
+ */
216
+ updatePlatformAccessories(accessories) {
217
+ const arr = Array.isArray(accessories) ? accessories : [accessories];
218
+ for (const acc of arr) {
219
+ if (!acc?.UUID) {
220
+ hapLog.warn(`updatePlatformAccessories: skipped accessory with no UUID: ${acc?.displayName}`);
221
+ continue;
222
+ }
223
+ if (!this._accessories.has(acc.UUID)) {
224
+ hapLog.warn(`updatePlatformAccessories: unknown accessory ${acc.displayName} (UUID: ${acc.UUID}), ignoring`);
225
+ continue;
226
+ }
227
+ // Keep the map pointing at whatever object the plugin considers current
228
+ this._accessories.set(acc.UUID, acc);
229
+ }
230
+ this.saveCachedAccessories();
231
+ }
232
+ /**
233
+ * Called by some platform plugins to publish accessories as standalone (not bridged).
234
+ * In real Homebridge these get their own HAP server, but OpenBridge funnels
235
+ * everything through a single bridge so we add them as bridged accessories.
236
+ */
237
+ publishExternalAccessories(_pluginName, accessories) {
238
+ const arr = Array.isArray(accessories) ? accessories : [accessories];
239
+ hapLog.info(`publishExternalAccessories: adding ${arr.length} accessory(ies)`);
240
+ for (const acc of arr) {
241
+ try {
242
+ if (!acc?.UUID) {
243
+ hapLog.warn(` skipped accessory with no UUID: ${acc?.displayName}`);
244
+ continue;
245
+ }
246
+ acc._associatedPlatform = _pluginName;
247
+ const existing = this._accessories.get(acc.UUID);
248
+ if (existing && this._bridge) {
249
+ try {
250
+ this._bridge.removeBridgedAccessory(existing, false);
251
+ }
252
+ catch {
253
+ /* not on bridge yet */
254
+ }
255
+ }
256
+ hapLog.info(` + ${acc.displayName} (UUID: ${acc.UUID})`);
257
+ this._accessories.set(acc.UUID, acc);
258
+ if (this._bridge) {
259
+ try {
260
+ this._bridge.addBridgedAccessory(acc);
261
+ }
262
+ catch (bridgeErr) {
263
+ hapLog.warn(` bridge.addBridgedAccessory failed (non-fatal): ${bridgeErr}`);
264
+ }
265
+ }
266
+ this._onAccessoryAdd?.(acc);
267
+ }
268
+ catch (err) {
269
+ hapLog.error(` failed to publish ${acc?.displayName}: ${err}`);
270
+ }
271
+ }
272
+ this.saveCachedAccessories();
273
+ }
274
+ /**
275
+ * Returns whether the running Homebridge version is >= the given semver string.
276
+ * We always return false (we are not Homebridge), which disables optional features
277
+ * like Adaptive Lighting that check for minimum versions.
278
+ */
279
+ versionGreaterOrEqual(_version) {
280
+ return false;
281
+ }
282
+ getRawAccessories() {
283
+ return Array.from(this._accessories.values());
284
+ }
285
+ getAccessories() {
286
+ hapLog.debug(`getAccessories called: map has ${this._accessories.size} entries`);
287
+ return Array.from(this._accessories.values()).map(serializeAccessory);
288
+ }
289
+ /**
290
+ * Called by platform instances to remove accessories.
291
+ */
292
+ unregisterPlatformAccessories(_pluginName, _platformName, accessories) {
293
+ for (const acc of accessories) {
294
+ this._accessories.delete(acc.UUID);
295
+ try {
296
+ this._bridge.removeBridgedAccessory(acc, false);
297
+ }
298
+ catch {
299
+ /* ignore if not found */
300
+ }
301
+ this._onAccessoryRemove?.(acc);
302
+ }
303
+ this.saveCachedAccessories();
304
+ }
305
+ getPlatformRegistrations() {
306
+ return [...this._platformRegistrations];
307
+ }
308
+ /**
309
+ * Instantiate all registered platforms with the given config entries.
310
+ * registry is optional: if provided, each platform is registered as a
311
+ * PluginInstance so it appears in the OpenBridge UI plugins page.
312
+ */
313
+ async launchPlatforms(configs, log, registry) {
314
+ for (const reg of this._platformRegistrations) {
315
+ const config = configs.find((c) => c.platform === reg.platformName);
316
+ if (!config) {
317
+ log.warn(`No config found for platform "${reg.platformName}", skipping`);
318
+ continue;
319
+ }
320
+ // Register as a plugin instance so the UI shows it, marked as homebridge source
321
+ if (registry) {
322
+ const pseudoPlugin = {
323
+ manifest: {
324
+ name: reg.pluginName,
325
+ version: config.version ?? '?.?.?',
326
+ description: `Platform: ${reg.platformName}`,
327
+ author: 'homebridge-compat',
328
+ },
329
+ setup: undefined,
330
+ start: undefined,
331
+ stop: undefined,
332
+ };
333
+ const instance = registry.register(pseudoPlugin, reg.platformName);
334
+ instance.source = 'homebridge';
335
+ instance.platformName = reg.platformName;
336
+ registry.updateStatus(instance.id, 'loading');
337
+ }
338
+ try {
339
+ // Give each platform its own named logger so log entries carry plugin: platformName
340
+ const platformLog = createPlatformLogger(Logger.create(reg.platformName), reg.platformName);
341
+ const instance = new reg.Constructor(platformLog, config, this);
342
+ this._platformInstances.set(reg.platformName, instance);
343
+ log.info(`Platform "${reg.platformName}" instantiated`);
344
+ // Dynamic platforms implement configureAccessory() to re-adopt cached accessories.
345
+ // Feed any existing accessories for this platform back to the new instance.
346
+ if (typeof instance.configureAccessory === 'function') {
347
+ const cached = Array.from(this._accessories.values()).filter((acc) => acc._associatedPlatform === reg.platformName);
348
+ for (const acc of cached) {
349
+ try {
350
+ instance.configureAccessory(acc);
351
+ }
352
+ catch (err) {
353
+ hapLog.warn(`configureAccessory failed for ${acc.displayName}: ${err}`);
354
+ }
355
+ }
356
+ if (cached.length > 0) {
357
+ hapLog.info(`Restored ${cached.length} cached accessory(ies) for "${reg.platformName}"`);
358
+ }
359
+ }
360
+ registry?.updateStatus(reg.platformName, 'running');
361
+ // Store launch config so we can restart the platform if it fails later
362
+ this._platformLaunchConfigs.set(reg.platformName, { config, log, registry });
363
+ this._platformRestartAttempts.set(reg.platformName, 0);
364
+ }
365
+ catch (err) {
366
+ log.error(`Platform "${reg.platformName}" failed to start: ${err}`);
367
+ registry?.updateStatus(reg.platformName, 'error', String(err));
368
+ }
369
+ }
370
+ // Signal that all plugins have loaded: platforms listen for this
371
+ hapLog.info('Emitting didFinishLaunching: platforms should start device discovery');
372
+ this.emit('didFinishLaunching');
373
+ }
374
+ /**
375
+ * Restart a platform that has failed. Removes old accessories,
376
+ * re-instantiates the platform, and re-emits didFinishLaunching.
377
+ */
378
+ async restartPlatform(platformName) {
379
+ const reg = this._platformRegistrations.find((r) => r.platformName === platformName);
380
+ const launchConfig = this._platformLaunchConfigs.get(platformName);
381
+ if (!reg || !launchConfig) {
382
+ hapLog.warn(`Cannot restart platform "${platformName}": no registration or config found`);
383
+ return false;
384
+ }
385
+ const { config, registry } = launchConfig;
386
+ const attempts = (this._platformRestartAttempts.get(platformName) ?? 0) + 1;
387
+ this._platformRestartAttempts.set(platformName, attempts);
388
+ hapLog.info(`Restarting platform "${platformName}" (attempt ${attempts})...`);
389
+ registry?.updateStatus(platformName, 'loading');
390
+ // Remove old accessories registered by this platform
391
+ const oldInstance = this._platformInstances.get(platformName);
392
+ if (oldInstance) {
393
+ const toRemove = [];
394
+ for (const [_uuid, acc] of this._accessories.entries()) {
395
+ if (acc._associatedPlatform === platformName) {
396
+ toRemove.push(acc);
397
+ }
398
+ }
399
+ for (const acc of toRemove) {
400
+ this._accessories.delete(acc.UUID);
401
+ try {
402
+ this._bridge?.removeBridgedAccessory(acc, false);
403
+ }
404
+ catch {
405
+ /* ignore */
406
+ }
407
+ }
408
+ hapLog.info(` Removed ${toRemove.length} stale accessory(ies)`);
409
+ }
410
+ try {
411
+ const platformLog = createPlatformLogger(Logger.create(reg.platformName), reg.platformName);
412
+ const instance = new reg.Constructor(platformLog, config, this);
413
+ this._platformInstances.set(platformName, instance);
414
+ // Re-emit didFinishLaunching so the new instance starts discovery
415
+ this.emit('didFinishLaunching');
416
+ hapLog.info(`Platform "${platformName}" restarted successfully`);
417
+ registry?.updateStatus(platformName, 'running');
418
+ this._platformRestartAttempts.set(platformName, 0);
419
+ return true;
420
+ }
421
+ catch (err) {
422
+ hapLog.error(`Platform "${platformName}" restart failed: ${err}`);
423
+ registry?.updateStatus(platformName, 'error', String(err));
424
+ return false;
425
+ }
426
+ }
427
+ /**
428
+ * Returns the backoff delay (ms) for the next restart attempt of a platform.
429
+ * Exponential: 30s, 60s, 120s, 240s, capped at 5 minutes.
430
+ */
431
+ getRestartBackoff(platformName) {
432
+ const attempts = this._platformRestartAttempts.get(platformName) ?? 0;
433
+ return Math.min(30_000 * Math.pow(2, attempts), 5 * 60_000);
434
+ }
435
+ getPlatformInstances() {
436
+ return this._platformInstances;
437
+ }
438
+ // ── Accessory cache persistence ──────────────────────────────────────────
439
+ /**
440
+ * Load previously cached accessories from disk and pre-populate
441
+ * the in-memory map + bridge so that platforms can re-adopt them
442
+ * via configureAccessory() before starting device discovery.
443
+ *
444
+ * Must be called after the bridge is set up but before launchPlatforms().
445
+ */
446
+ loadCachedAccessories() {
447
+ const cachePath = resolve(this.user.cachedAccessoryPath(), 'cachedAccessories.json');
448
+ if (!existsSync(cachePath)) {
449
+ hapLog.debug('No cached accessories file found, starting fresh');
450
+ return;
451
+ }
452
+ let entries;
453
+ try {
454
+ entries = JSON.parse(readFileSync(cachePath, 'utf8'));
455
+ }
456
+ catch (err) {
457
+ hapLog.warn(`Failed to read cached accessories (will start fresh): ${err}`);
458
+ return;
459
+ }
460
+ if (!Array.isArray(entries) || entries.length === 0)
461
+ return;
462
+ hapLog.info(`Restoring ${entries.length} cached accessory(ies) from disk`);
463
+ const PlatformAccessory = this.platformAccessory;
464
+ for (const entry of entries) {
465
+ try {
466
+ const acc = new PlatformAccessory(entry.displayName, entry.UUID, entry.category);
467
+ acc.context = entry.context ?? {};
468
+ acc._associatedPlatform = entry.associatedPlatform;
469
+ this._accessories.set(acc.UUID, acc);
470
+ if (this._bridge) {
471
+ try {
472
+ this._bridge.addBridgedAccessory(acc);
473
+ }
474
+ catch (bridgeErr) {
475
+ hapLog.warn(` bridge.addBridgedAccessory failed for cached "${entry.displayName}": ${bridgeErr}`);
476
+ }
477
+ }
478
+ hapLog.debug(` restored: ${entry.displayName} (UUID: ${entry.UUID})`);
479
+ }
480
+ catch (err) {
481
+ hapLog.warn(` failed to restore cached accessory "${entry.displayName}": ${err}`);
482
+ }
483
+ }
484
+ }
485
+ /**
486
+ * Drop cached accessories whose owning platform is not active.
487
+ *
488
+ * `loadCachedAccessories()` restores everything it finds and adds it to the
489
+ * bridge, because a platform has to be able to re-adopt its accessories via
490
+ * configureAccessory() before discovery starts. Nothing ever removed the
491
+ * accessories of a plugin that was no longer active, so they stayed on the
492
+ * bridge forever: still in the Home app, still listed in OpenBridge, but with
493
+ * no plugin behind them to update or control them. They show up as
494
+ * "Default-Manufacturer / Default-Model" entries that do nothing.
495
+ *
496
+ * "Not active" covers both an uninstalled plugin and a disabled one: the
497
+ * loader deliberately leaves a disabled plugin out of _platformRegistrations
498
+ * so it is reclaimed here rather than lingering as dead HomeKit entries.
499
+ *
500
+ * Attribution is by platform registration, not by discovery, so this is safe
501
+ * to call as soon as platforms have been launched: a platform registers at
502
+ * load time, long before it finishes finding devices.
503
+ *
504
+ * Accessories with no recorded owner are left alone. They cannot be
505
+ * attributed, and silently deleting a user's HomeKit devices is far worse
506
+ * than leaving one stale entry behind.
507
+ */
508
+ pruneOrphanedAccessories() {
509
+ const known = new Set();
510
+ for (const reg of this._platformRegistrations) {
511
+ known.add(reg.platformName);
512
+ known.add(reg.pluginName);
513
+ }
514
+ const orphans = Array.from(this._accessories.values()).filter((acc) => {
515
+ const owner = acc._associatedPlatform;
516
+ return typeof owner === 'string' && owner.length > 0 && !known.has(owner);
517
+ });
518
+ if (orphans.length === 0)
519
+ return [];
520
+ const removed = [];
521
+ for (const acc of orphans) {
522
+ this._accessories.delete(acc.UUID);
523
+ try {
524
+ this._bridge?.removeBridgedAccessory(acc, false);
525
+ }
526
+ catch {
527
+ /* was not on the bridge */
528
+ }
529
+ this._onAccessoryRemove?.(acc);
530
+ removed.push(acc.displayName);
531
+ hapLog.info(`Removed orphaned accessory "${acc.displayName}" (plugin "${acc._associatedPlatform}" is not active)`);
532
+ }
533
+ this.saveCachedAccessories();
534
+ return removed;
535
+ }
536
+ /**
537
+ * Persist the current accessory map to disk so accessories survive
538
+ * container restarts without being re-discovered by HomeKit.
539
+ */
540
+ saveCachedAccessories() {
541
+ const dir = this.user.cachedAccessoryPath();
542
+ const cachePath = resolve(dir, 'cachedAccessories.json');
543
+ const entries = [];
544
+ for (const acc of this._accessories.values()) {
545
+ entries.push({
546
+ UUID: acc.UUID,
547
+ displayName: acc.displayName,
548
+ category: acc.category ?? 1,
549
+ context: acc.context ?? {},
550
+ associatedPlatform: acc._associatedPlatform ?? '',
551
+ });
552
+ }
553
+ try {
554
+ mkdirSync(dir, { recursive: true });
555
+ writeFileSync(cachePath, JSON.stringify(entries, null, 2));
556
+ hapLog.debug(`Saved ${entries.length} accessory(ies) to cache`);
557
+ }
558
+ catch (err) {
559
+ hapLog.warn(`Failed to save accessory cache: ${err}`);
560
+ }
561
+ }
562
+ }
563
+ function createPlatformLogger(baseLog, platformName) {
564
+ const prefix = `[${platformName}]`;
565
+ // Homebridge platform logger is a callable function with .info/.warn/.error/.log methods
566
+ const fn = (message, ...args) => baseLog.info(`${prefix} ${message}`, ...args);
567
+ fn.info = (message, ...args) => baseLog.info(`${prefix} ${message}`, ...args);
568
+ fn.warn = (message, ...args) => baseLog.warn(`${prefix} ${message}`, ...args);
569
+ fn.error = (message, ...args) => baseLog.error(`${prefix} ${message}`, ...args);
570
+ fn.debug = (message, ...args) => baseLog.debug(`${prefix} ${message}`, ...args);
571
+ // Generic log(level, message, ...args): used by some plugins (e.g. homebridge-shelly-ds9)
572
+ fn.log = (level, message, ...args) => {
573
+ const method = fn[level] ?? fn.info;
574
+ method(message, ...args);
575
+ };
576
+ // success is treated as info in some plugins
577
+ fn.success = (message, ...args) => baseLog.info(`${prefix} ${message}`, ...args);
578
+ return fn;
579
+ }
580
+ // Map HAP service UUIDs to accessory categories. Used to infer the category
581
+ // when a plugin doesn't explicitly set one (many Homebridge plugins don't).
582
+ const SERVICE_UUID_TO_CATEGORY = {
583
+ '00000043-0000-1000-8000-0026BB765291': 5, // Lightbulb
584
+ '00000040-0000-1000-8000-0026BB765291': 3, // Fan / Fanv2
585
+ '000000B7-0000-1000-8000-0026BB765291': 3, // Fanv2
586
+ '00000041-0000-1000-8000-0026BB765291': 4, // GarageDoorOpener
587
+ '00000045-0000-1000-8000-0026BB765291': 6, // LockMechanism
588
+ '00000047-0000-1000-8000-0026BB765291': 7, // Outlet
589
+ '00000049-0000-1000-8000-0026BB765291': 8, // Switch
590
+ '0000004A-0000-1000-8000-0026BB765291': 9, // Thermostat
591
+ '00000080-0000-1000-8000-0026BB765291': 10, // ContactSensor
592
+ '00000082-0000-1000-8000-0026BB765291': 10, // HumiditySensor
593
+ '00000083-0000-1000-8000-0026BB765291': 10, // LeakSensor
594
+ '00000084-0000-1000-8000-0026BB765291': 10, // LightSensor
595
+ '00000085-0000-1000-8000-0026BB765291': 10, // MotionSensor
596
+ '00000086-0000-1000-8000-0026BB765291': 10, // OccupancySensor
597
+ '0000008A-0000-1000-8000-0026BB765291': 10, // TemperatureSensor
598
+ '0000007E-0000-1000-8000-0026BB765291': 11, // SecuritySystem
599
+ '00000081-0000-1000-8000-0026BB765291': 12, // Door
600
+ '0000008B-0000-1000-8000-0026BB765291': 13, // Window
601
+ '0000008C-0000-1000-8000-0026BB765291': 14, // WindowCovering
602
+ '00000110-0000-1000-8000-0026BB765291': 17, // CameraRTPStreamManagement
603
+ '00000121-0000-1000-8000-0026BB765291': 18, // Doorbell
604
+ '000000BB-0000-1000-8000-0026BB765291': 19, // AirPurifier
605
+ '000000BC-0000-1000-8000-0026BB765291': 20, // HeaterCooler
606
+ '000000BD-0000-1000-8000-0026BB765291': 22, // HumidifierDehumidifier
607
+ '000000D0-0000-1000-8000-0026BB765291': 29, // Valve (FAUCET)
608
+ '000000D8-0000-1000-8000-0026BB765291': 31, // Television
609
+ };
610
+ function inferCategoryFromServices(acc) {
611
+ try {
612
+ for (const svc of acc.services ?? []) {
613
+ const cat = SERVICE_UUID_TO_CATEGORY[svc.UUID];
614
+ if (cat !== undefined)
615
+ return cat;
616
+ }
617
+ }
618
+ catch {
619
+ /* ignore */
620
+ }
621
+ return 1; // OTHER
622
+ }
623
+ export function serializeAccessory(acc) {
624
+ const services = [];
625
+ try {
626
+ for (const svc of acc.services ?? []) {
627
+ const characteristics = [];
628
+ for (const ch of svc.characteristics ?? []) {
629
+ try {
630
+ characteristics.push({
631
+ uuid: ch.UUID,
632
+ name: ch.constructor?.name ?? ch.displayName ?? ch.UUID,
633
+ value: ch.value,
634
+ format: ch.props?.format ?? 'unknown',
635
+ perms: ch.props?.perms ?? [],
636
+ });
637
+ }
638
+ catch {
639
+ /* skip bad characteristic */
640
+ }
641
+ }
642
+ services.push({
643
+ uuid: svc.UUID,
644
+ name: svc.constructor?.name ?? svc.displayName ?? svc.UUID,
645
+ displayName: svc.displayName ?? '',
646
+ characteristics,
647
+ });
648
+ }
649
+ }
650
+ catch {
651
+ /* skip bad service */
652
+ }
653
+ // Use the explicit category if set and not OTHER (1), otherwise infer from services
654
+ const explicitCategory = acc.category ?? 1;
655
+ const category = explicitCategory !== 1 ? explicitCategory : inferCategoryFromServices(acc);
656
+ return {
657
+ uuid: acc.UUID,
658
+ displayName: acc.displayName,
659
+ category,
660
+ services,
661
+ reachable: acc.reachable !== false,
662
+ };
663
+ }
664
+ /**
665
+ * Load a Homebridge-compatible plugin from a file path.
666
+ * Plugins use CommonJS: module.exports = function(homebridge) { ... }
667
+ */
668
+ export function loadHomebridgePlugin(pluginPath) {
669
+ const req = createRequire(import.meta.url);
670
+ const mod = req(pluginPath);
671
+ const fn = mod.default ?? mod;
672
+ if (typeof fn !== 'function') {
673
+ throw new Error(`Homebridge plugin at ${pluginPath} must export a function`);
674
+ }
675
+ return fn;
676
+ }
677
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@nubisco/openbridge-compatibility-homebridge",
3
+ "version": "0.29.0",
4
+ "description": "Homebridge platform plugin compatibility shim for OpenBridge",
5
+ "author": "José Silva <jose@nubisco.io>",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/nubisco/openbridge#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/nubisco/openbridge.git",
11
+ "directory": "packages/compatibility-homebridge"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/nubisco/openbridge/issues"
15
+ },
16
+ "keywords": [
17
+ "homebridge",
18
+ "compatibility",
19
+ "homekit",
20
+ "home-automation",
21
+ "typescript",
22
+ "openbridge"
23
+ ],
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "import": "./dist/index.js",
30
+ "types": "./dist/index.d.ts"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist/",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "engines": {
39
+ "node": ">=20"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20.0.0",
46
+ "typescript": "^5.4.0",
47
+ "vitest": "^3.2.0"
48
+ },
49
+ "dependencies": {
50
+ "@nubisco/openbridge-logger": "^0.29.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc",
54
+ "dev": "tsc --watch",
55
+ "typecheck": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest"
58
+ }
59
+ }