@nubisco/openbridge-core 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-core
2
+
3
+ Plugin types, registry, lifecycle and loader. The contract every OpenBridge plugin is written against.
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-core
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=lifecycle.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/lifecycle.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { PluginLifecycle } from '../lifecycle.js';
3
+ import { PluginRegistry } from '../registry.js';
4
+ function makePlugin(name, overrides = {}) {
5
+ return {
6
+ manifest: { name, version: '1.0.0' },
7
+ setup: vi.fn(),
8
+ start: vi.fn(),
9
+ stop: vi.fn(),
10
+ ...overrides,
11
+ };
12
+ }
13
+ function makeContext() {
14
+ return {
15
+ config: {},
16
+ log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
17
+ reportTelemetry: vi.fn(),
18
+ registerDevice: vi.fn(),
19
+ registerControl: vi.fn(),
20
+ registerHapBridge: vi.fn(),
21
+ restrictControl: vi.fn(),
22
+ };
23
+ }
24
+ describe('PluginLifecycle', () => {
25
+ let registry;
26
+ let lifecycle;
27
+ beforeEach(() => {
28
+ registry = new PluginRegistry();
29
+ lifecycle = new PluginLifecycle(registry);
30
+ });
31
+ describe('setup', () => {
32
+ it('calls plugin.setup and sets status to loading', async () => {
33
+ const plugin = makePlugin('test');
34
+ registry.register(plugin);
35
+ const ctx = makeContext();
36
+ await lifecycle.setup(plugin, ctx);
37
+ expect(plugin.setup).toHaveBeenCalledWith(ctx);
38
+ });
39
+ it('sets status to error if setup throws', async () => {
40
+ const plugin = makePlugin('test', {
41
+ setup: vi.fn().mockRejectedValue(new Error('setup failed')),
42
+ });
43
+ registry.register(plugin);
44
+ await expect(lifecycle.setup(plugin, makeContext())).rejects.toThrow('setup failed');
45
+ expect(registry.get('test').instance.status).toBe('error');
46
+ expect(registry.get('test').instance.error).toBe('Error: setup failed');
47
+ });
48
+ });
49
+ describe('start', () => {
50
+ it('calls plugin.start and sets status to running', async () => {
51
+ const plugin = makePlugin('test');
52
+ registry.register(plugin);
53
+ const ctx = makeContext();
54
+ await lifecycle.start(plugin, ctx);
55
+ expect(plugin.start).toHaveBeenCalledWith(ctx);
56
+ expect(registry.get('test').instance.status).toBe('running');
57
+ });
58
+ it('sets status to error if start throws', async () => {
59
+ const plugin = makePlugin('test', {
60
+ start: vi.fn().mockRejectedValue(new Error('start failed')),
61
+ });
62
+ registry.register(plugin);
63
+ await expect(lifecycle.start(plugin, makeContext())).rejects.toThrow('start failed');
64
+ expect(registry.get('test').instance.status).toBe('error');
65
+ });
66
+ });
67
+ describe('stop', () => {
68
+ it('calls plugin.stop and sets status to stopped', async () => {
69
+ const plugin = makePlugin('test');
70
+ registry.register(plugin);
71
+ await lifecycle.stop(plugin, makeContext());
72
+ expect(plugin.stop).toHaveBeenCalled();
73
+ expect(registry.get('test').instance.status).toBe('stopped');
74
+ });
75
+ });
76
+ describe('startAll', () => {
77
+ it('calls setup and start for each plugin', async () => {
78
+ const a = makePlugin('a');
79
+ const b = makePlugin('b');
80
+ registry.register(a);
81
+ registry.register(b);
82
+ await lifecycle.startAll([a, b], () => makeContext());
83
+ expect(a.setup).toHaveBeenCalled();
84
+ expect(a.start).toHaveBeenCalled();
85
+ expect(b.setup).toHaveBeenCalled();
86
+ expect(b.start).toHaveBeenCalled();
87
+ expect(registry.get('a').instance.status).toBe('running');
88
+ expect(registry.get('b').instance.status).toBe('running');
89
+ });
90
+ });
91
+ describe('stopAll', () => {
92
+ it('stops all plugins in reverse order', async () => {
93
+ const order = [];
94
+ const a = makePlugin('a', {
95
+ stop: vi.fn(async () => {
96
+ order.push('a');
97
+ }),
98
+ });
99
+ const b = makePlugin('b', {
100
+ stop: vi.fn(async () => {
101
+ order.push('b');
102
+ }),
103
+ });
104
+ registry.register(a);
105
+ registry.register(b);
106
+ await lifecycle.stopAll([a, b], () => makeContext());
107
+ expect(order).toEqual(['b', 'a']);
108
+ });
109
+ });
110
+ });
111
+ //# sourceMappingURL=lifecycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.test.js","sourceRoot":"","sources":["../../src/__tests__/lifecycle.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { PluginRegistry } from '../registry.js';
3
+ function makePlugin(name) {
4
+ return { manifest: { name, version: '1.0.0', description: `Test plugin ${name}` } };
5
+ }
6
+ describe('PluginRegistry', () => {
7
+ let registry;
8
+ beforeEach(() => {
9
+ registry = new PluginRegistry();
10
+ });
11
+ describe('register', () => {
12
+ it('registers a plugin and returns its instance', () => {
13
+ const plugin = makePlugin('test-plugin');
14
+ const instance = registry.register(plugin);
15
+ expect(instance.id).toBe('test-plugin');
16
+ expect(instance.manifest.name).toBe('test-plugin');
17
+ expect(instance.status).toBe('idle');
18
+ });
19
+ it('uses custom instance ID if provided', () => {
20
+ const plugin = makePlugin('test-plugin');
21
+ const instance = registry.register(plugin, 'custom-id');
22
+ expect(instance.id).toBe('custom-id');
23
+ });
24
+ });
25
+ describe('get', () => {
26
+ it('returns the entry for a registered plugin', () => {
27
+ const plugin = makePlugin('test-plugin');
28
+ registry.register(plugin);
29
+ const entry = registry.get('test-plugin');
30
+ expect(entry).toBeDefined();
31
+ expect(entry.instance.manifest.name).toBe('test-plugin');
32
+ expect(entry.plugin).toBe(plugin);
33
+ });
34
+ it('returns undefined for an unregistered plugin', () => {
35
+ expect(registry.get('nonexistent')).toBeUndefined();
36
+ });
37
+ });
38
+ describe('getAll', () => {
39
+ it('returns all registered instances', () => {
40
+ registry.register(makePlugin('a'));
41
+ registry.register(makePlugin('b'));
42
+ registry.register(makePlugin('c'));
43
+ const all = registry.getAll();
44
+ expect(all).toHaveLength(3);
45
+ expect(all.map((i) => i.id)).toEqual(['a', 'b', 'c']);
46
+ });
47
+ it('returns empty array when no plugins registered', () => {
48
+ expect(registry.getAll()).toEqual([]);
49
+ });
50
+ });
51
+ describe('unregister', () => {
52
+ it('removes a plugin by ID', () => {
53
+ registry.register(makePlugin('test-plugin'));
54
+ expect(registry.unregister('test-plugin')).toBe(true);
55
+ expect(registry.get('test-plugin')).toBeUndefined();
56
+ });
57
+ it('returns false for nonexistent plugin', () => {
58
+ expect(registry.unregister('nonexistent')).toBe(false);
59
+ });
60
+ });
61
+ describe('unregisterWhere', () => {
62
+ it('removes plugins matching predicate', () => {
63
+ registry.register(makePlugin('keep-a'));
64
+ registry.register(makePlugin('remove-b'));
65
+ registry.register(makePlugin('remove-c'));
66
+ registry.register(makePlugin('keep-d'));
67
+ const removed = registry.unregisterWhere((i) => i.manifest.name.startsWith('remove'));
68
+ expect(removed).toBe(2);
69
+ expect(registry.getAll()).toHaveLength(2);
70
+ expect(registry.getAll().map((i) => i.id)).toEqual(['keep-a', 'keep-d']);
71
+ });
72
+ it('returns 0 when no plugins match', () => {
73
+ registry.register(makePlugin('test'));
74
+ expect(registry.unregisterWhere(() => false)).toBe(0);
75
+ });
76
+ });
77
+ describe('updateStatus', () => {
78
+ it('updates plugin status', () => {
79
+ registry.register(makePlugin('test'));
80
+ registry.updateStatus('test', 'running');
81
+ expect(registry.get('test').instance.status).toBe('running');
82
+ });
83
+ it('sets startedAt when status is running', () => {
84
+ registry.register(makePlugin('test'));
85
+ registry.updateStatus('test', 'running');
86
+ expect(registry.get('test').instance.startedAt).toBeInstanceOf(Date);
87
+ });
88
+ it('sets stoppedAt when status is stopped', () => {
89
+ registry.register(makePlugin('test'));
90
+ registry.updateStatus('test', 'stopped');
91
+ expect(registry.get('test').instance.stoppedAt).toBeInstanceOf(Date);
92
+ });
93
+ it('sets error message when provided', () => {
94
+ registry.register(makePlugin('test'));
95
+ registry.updateStatus('test', 'error', 'Something broke');
96
+ expect(registry.get('test').instance.error).toBe('Something broke');
97
+ });
98
+ it('does nothing for nonexistent plugin', () => {
99
+ // Should not throw
100
+ registry.updateStatus('nonexistent', 'running');
101
+ });
102
+ });
103
+ });
104
+ //# sourceMappingURL=registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export type { Plugin, PluginManifest, PluginContext, PluginLogger, PluginInstance, PluginStatus, DeviceDescriptor, MetricDescriptor, InterpolationDescriptor, } from './types.js';
2
+ export { PluginRegistry } from './registry.js';
3
+ export { PluginLifecycle } from './lifecycle.js';
4
+ export { loadPlugin, loadPluginsFromDirectory } from './loader.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,MAAM,EACN,cAAc,EACd,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { PluginRegistry } from './registry.js';
2
+ export { PluginLifecycle } from './lifecycle.js';
3
+ export { loadPlugin, loadPluginsFromDirectory } from './loader.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { Plugin, PluginContext } from './types.js';
2
+ import type { PluginRegistry } from './registry.js';
3
+ export declare class PluginLifecycle {
4
+ private registry;
5
+ constructor(registry: PluginRegistry);
6
+ setup(plugin: Plugin, ctx: PluginContext): Promise<void>;
7
+ start(plugin: Plugin, ctx: PluginContext): Promise<void>;
8
+ stop(plugin: Plugin, ctx: PluginContext): Promise<void>;
9
+ startAll(plugins: Plugin[], ctxFactory: (plugin: Plugin) => PluginContext): Promise<void>;
10
+ stopAll(plugins: Plugin[], ctxFactory: (plugin: Plugin) => PluginContext): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc;IAEtC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzF,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAM/F"}
@@ -0,0 +1,53 @@
1
+ export class PluginLifecycle {
2
+ registry;
3
+ constructor(registry) {
4
+ this.registry = registry;
5
+ }
6
+ async setup(plugin, ctx) {
7
+ const id = plugin.manifest.name;
8
+ this.registry.updateStatus(id, 'loading');
9
+ try {
10
+ await plugin.setup?.(ctx);
11
+ }
12
+ catch (err) {
13
+ this.registry.updateStatus(id, 'error', String(err));
14
+ throw err;
15
+ }
16
+ }
17
+ async start(plugin, ctx) {
18
+ const id = plugin.manifest.name;
19
+ try {
20
+ await plugin.start?.(ctx);
21
+ this.registry.updateStatus(id, 'running');
22
+ }
23
+ catch (err) {
24
+ this.registry.updateStatus(id, 'error', String(err));
25
+ throw err;
26
+ }
27
+ }
28
+ async stop(plugin, ctx) {
29
+ const id = plugin.manifest.name;
30
+ try {
31
+ await plugin.stop?.(ctx);
32
+ this.registry.updateStatus(id, 'stopped');
33
+ }
34
+ catch (err) {
35
+ this.registry.updateStatus(id, 'error', String(err));
36
+ throw err;
37
+ }
38
+ }
39
+ async startAll(plugins, ctxFactory) {
40
+ for (const plugin of plugins) {
41
+ const ctx = ctxFactory(plugin);
42
+ await this.setup(plugin, ctx);
43
+ await this.start(plugin, ctx);
44
+ }
45
+ }
46
+ async stopAll(plugins, ctxFactory) {
47
+ for (const plugin of [...plugins].reverse()) {
48
+ const ctx = ctxFactory(plugin);
49
+ await this.stop(plugin, ctx);
50
+ }
51
+ }
52
+ }
53
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,QAAwB;QAAxB,aAAQ,GAAR,QAAQ,CAAgB;IAAG,CAAC;IAEhD,KAAK,CAAC,KAAK,CAAC,MAAc,EAAE,GAAkB;QAC5C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC/B,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,CAAC,CAAA;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YACpD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc,EAAE,GAAkB;QAC5C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAA;YACzB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,CAAC,CAAA;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YACpD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,GAAkB;QAC3C,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAA;YACxB,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,CAAC,CAAA;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YACpD,MAAM,GAAG,CAAA;QACX,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAiB,EAAE,UAA6C;QAC7E,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;YAC9B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;YAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAAiB,EAAE,UAA6C;QAC5E,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;YAC9B,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,4 @@
1
+ import type { Plugin } from './types.js';
2
+ export declare function loadPlugin(pluginPath: string): Promise<Plugin>;
3
+ export declare function loadPluginsFromDirectory(dir: string): Promise<Plugin[]>;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBpE;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6B7E"}
package/dist/loader.js ADDED
@@ -0,0 +1,54 @@
1
+ import { pathToFileURL } from 'url';
2
+ import { join, resolve } from 'path';
3
+ import { existsSync } from 'fs';
4
+ export async function loadPlugin(pluginPath) {
5
+ const absolutePath = resolve(pluginPath);
6
+ // Try to load as ES module
7
+ let mod;
8
+ try {
9
+ const fileUrl = pathToFileURL(absolutePath).href;
10
+ mod = await import(fileUrl);
11
+ }
12
+ catch (err) {
13
+ throw new Error(`Failed to load plugin at ${pluginPath}: ${err}`);
14
+ }
15
+ // Handle both default export and named export
16
+ const plugin = mod.default ?? mod;
17
+ if (!plugin || typeof plugin !== 'object') {
18
+ throw new Error(`Plugin at ${pluginPath} must export a plugin object`);
19
+ }
20
+ const p = plugin;
21
+ if (!p.manifest || typeof p.manifest !== 'object') {
22
+ throw new Error(`Plugin at ${pluginPath} must have a manifest`);
23
+ }
24
+ return plugin;
25
+ }
26
+ export async function loadPluginsFromDirectory(dir) {
27
+ if (!existsSync(dir))
28
+ return [];
29
+ const { readdir } = await import('fs/promises');
30
+ const entries = await readdir(dir, { withFileTypes: true });
31
+ const plugins = [];
32
+ for (const entry of entries) {
33
+ // Accept both real directories and symlinks to directories
34
+ if (!entry.isDirectory() && !entry.isSymbolicLink())
35
+ continue;
36
+ const pluginDir = join(dir, entry.name);
37
+ // Try index.js first, then index.ts, then package.json main
38
+ const candidates = [join(pluginDir, 'dist', 'index.js'), join(pluginDir, 'index.js')];
39
+ for (const candidate of candidates) {
40
+ if (existsSync(candidate)) {
41
+ try {
42
+ const plugin = await loadPlugin(candidate);
43
+ plugins.push(plugin);
44
+ break;
45
+ }
46
+ catch (err) {
47
+ console.warn(`Failed to load plugin from ${candidate}:`, err);
48
+ }
49
+ }
50
+ }
51
+ }
52
+ return plugins;
53
+ }
54
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AAG/B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IAExC,2BAA2B;IAC3B,IAAI,GAAY,CAAA;IAChB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAAA;QAChD,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,KAAK,GAAG,EAAE,CAAC,CAAA;IACnE,CAAC;IAED,8CAA8C;IAC9C,MAAM,MAAM,GAAI,GAA+B,CAAC,OAAO,IAAI,GAAG,CAAA;IAE9D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,8BAA8B,CAAC,CAAA;IACxE,CAAC;IAED,MAAM,CAAC,GAAG,MAAiC,CAAA;IAC3C,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,uBAAuB,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,MAAgB,CAAA;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,GAAW;IACxD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAE/B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAC/C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IAC3D,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,2DAA2D;QAC3D,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE;YAAE,SAAQ;QAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAEvC,4DAA4D;QAC5D,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;QAErF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAA;oBAC1C,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;oBACpB,MAAK;gBACP,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,8BAA8B,SAAS,GAAG,EAAE,GAAG,CAAC,CAAA;gBAC/D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Plugin, PluginInstance, PluginStatus } from './types.js';
2
+ export declare class PluginRegistry {
3
+ private plugins;
4
+ register(plugin: Plugin, instanceId?: string): PluginInstance;
5
+ get(id: string): {
6
+ plugin: Plugin;
7
+ instance: PluginInstance;
8
+ } | undefined;
9
+ getAll(): PluginInstance[];
10
+ unregister(id: string): boolean;
11
+ unregisterWhere(predicate: (instance: PluginInstance) => boolean): number;
12
+ updateStatus(id: string, status: PluginStatus, error?: string): void;
13
+ }
14
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEtE,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAkE;IAEjF,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,cAAc;IAW7D,GAAG,CAAC,EAAE,EAAE,MAAM;gBAb8B,MAAM;kBAAY,cAAc;;IAiB5E,MAAM,IAAI,cAAc,EAAE;IAI1B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B,eAAe,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,GAAG,MAAM;IAWzE,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM;CAQ9D"}
@@ -0,0 +1,45 @@
1
+ export class PluginRegistry {
2
+ plugins = new Map();
3
+ register(plugin, instanceId) {
4
+ const id = instanceId ?? plugin.manifest.name;
5
+ const instance = {
6
+ id,
7
+ manifest: plugin.manifest,
8
+ status: 'idle',
9
+ };
10
+ this.plugins.set(id, { plugin, instance });
11
+ return instance;
12
+ }
13
+ get(id) {
14
+ return this.plugins.get(id);
15
+ }
16
+ getAll() {
17
+ return Array.from(this.plugins.values()).map((e) => e.instance);
18
+ }
19
+ unregister(id) {
20
+ return this.plugins.delete(id);
21
+ }
22
+ unregisterWhere(predicate) {
23
+ let removed = 0;
24
+ for (const [id, entry] of this.plugins.entries()) {
25
+ if (predicate(entry.instance)) {
26
+ this.plugins.delete(id);
27
+ removed++;
28
+ }
29
+ }
30
+ return removed;
31
+ }
32
+ updateStatus(id, status, error) {
33
+ const entry = this.plugins.get(id);
34
+ if (!entry)
35
+ return;
36
+ entry.instance.status = status;
37
+ if (error)
38
+ entry.instance.error = error;
39
+ if (status === 'running')
40
+ entry.instance.startedAt = new Date();
41
+ if (status === 'stopped')
42
+ entry.instance.stoppedAt = new Date();
43
+ }
44
+ }
45
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IACjB,OAAO,GAAG,IAAI,GAAG,EAAwD,CAAA;IAEjF,QAAQ,CAAC,MAAc,EAAE,UAAmB;QAC1C,MAAM,EAAE,GAAG,UAAU,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;QAC7C,MAAM,QAAQ,GAAmB;YAC/B,EAAE;YACF,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM;SACf,CAAA;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1C,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;IACjE,CAAC;IAED,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAChC,CAAC;IAED,eAAe,CAAC,SAAgD;QAC9D,IAAI,OAAO,GAAG,CAAC,CAAA;QACf,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACjD,IAAI,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBACvB,OAAO,EAAE,CAAA;YACX,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,YAAY,CAAC,EAAU,EAAE,MAAoB,EAAE,KAAc;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAClC,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAA;QAC9B,IAAI,KAAK;YAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAA;QACvC,IAAI,MAAM,KAAK,SAAS;YAAE,KAAK,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;QAC/D,IAAI,MAAM,KAAK,SAAS;YAAE,KAAK,CAAC,QAAQ,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IACjE,CAAC;CACF"}
@@ -0,0 +1,157 @@
1
+ export interface PluginManifest {
2
+ name: string;
3
+ version: string;
4
+ description?: string;
5
+ author?: string;
6
+ openbridge?: {
7
+ minVersion?: string;
8
+ };
9
+ }
10
+ /** Describes a device's interpolation calibration capability. */
11
+ export interface InterpolationDescriptor {
12
+ /** Label for the input (X) axis, e.g. "Room Temperature (C)" */
13
+ inputLabel: string;
14
+ /** Label for the output (Y) axis, e.g. "Water Temperature (C)" */
15
+ outputLabel: string;
16
+ /** Minimum allowed input value */
17
+ inputMin: number;
18
+ /** Maximum allowed input value */
19
+ inputMax: number;
20
+ /** Minimum allowed output value */
21
+ outputMin: number;
22
+ /** Maximum allowed output value */
23
+ outputMax: number;
24
+ /** The key in the device's platform config that holds the mapping array */
25
+ configField: string;
26
+ /** Maps generic input/output keys to the config array's property names */
27
+ configShape: {
28
+ inputKey: string;
29
+ outputKey: string;
30
+ };
31
+ }
32
+ /**
33
+ * Describes one time-series a device reports.
34
+ *
35
+ * Storage cannot infer that `power` is instantaneous while `totalForwardEnergy`
36
+ * only ever climbs, and the UI cannot infer that one is watts and the other
37
+ * kilowatt-hours. Declaring them keeps plugins data-only: no plugin ships UI
38
+ * code, and core can chart any device that describes its metrics, including
39
+ * devices from plugins that do not exist yet.
40
+ */
41
+ export interface MetricDescriptor {
42
+ /** Matches the key used in reportTelemetry() */
43
+ key: string;
44
+ /** Human label, e.g. "Power" */
45
+ label: string;
46
+ /** Unit symbol, e.g. "W", "V", "A", "kWh" */
47
+ unit: string;
48
+ /**
49
+ * `instant` values are sampled points (power, voltage): rolling them up takes
50
+ * the mean, and the min/max are kept so a spike is not averaged away.
51
+ * `cumulative` values only increase (energy meters): rolling up keeps the last
52
+ * value in the window, and a total over a period is the difference between
53
+ * the window edges.
54
+ */
55
+ kind: 'instant' | 'cumulative';
56
+ /** Decimal places to display. Defaults to 2. */
57
+ precision?: number;
58
+ /**
59
+ * Retain min/max when rolling this metric into coarser tiers. Defaults to
60
+ * true for `instant` metrics. Worth disabling for values that barely move
61
+ * (voltage, power factor) to keep coarse tiers narrow.
62
+ */
63
+ trackExtremes?: boolean;
64
+ }
65
+ export interface DeviceDescriptor {
66
+ id: string;
67
+ name: string;
68
+ /** Maps to a UI widget: 'switch' | 'light' | 'thermostat' | 'dehumidifier' | 'energy_meter' | 'sensor' */
69
+ widgetType: string;
70
+ manufacturer?: string;
71
+ model?: string;
72
+ pluginId: string;
73
+ /** If present, this device supports interactive interpolation calibration */
74
+ interpolation?: InterpolationDescriptor;
75
+ /**
76
+ * Time-series this device reports. When present, OpenBridge records them to
77
+ * history and can chart them. When absent, the device is still shown live but
78
+ * nothing is stored.
79
+ */
80
+ metrics?: MetricDescriptor[];
81
+ }
82
+ export interface PluginContext {
83
+ config: Record<string, unknown>;
84
+ log: PluginLogger;
85
+ /** Report live telemetry for a device: data appears in the OpenBridge UI */
86
+ reportTelemetry(deviceId: string, data: Record<string, unknown>): void;
87
+ /** Register a device so it appears in the OpenBridge devices view */
88
+ registerDevice(device: Omit<DeviceDescriptor, 'pluginId'>): void;
89
+ /** Register a command handler so the UI can control a device */
90
+ registerControl(deviceId: string, controlId: string, handler: (value: unknown) => void | Promise<void>): void;
91
+ /** Register a HAP bridge so its QR/PIN appear in the OpenBridge UI */
92
+ registerHapBridge(info: {
93
+ setupURI: string;
94
+ pincode: string;
95
+ port: number;
96
+ name: string;
97
+ }): void;
98
+ /** Block a device control from being changed via UI or HomeKit */
99
+ restrictControl(deviceId: string, controlId: string): void;
100
+ /**
101
+ * Returns the main HAP bridge so native plugins can add accessories to it
102
+ * instead of creating their own bridge. Returns null if the bridge is not available.
103
+ */
104
+ getHapBridge?(): {
105
+ bridge: unknown;
106
+ hap: unknown;
107
+ } | null;
108
+ }
109
+ export interface PluginLogger {
110
+ info(message: string, ...args: unknown[]): void;
111
+ warn(message: string, ...args: unknown[]): void;
112
+ error(message: string, ...args: unknown[]): void;
113
+ debug(message: string, ...args: unknown[]): void;
114
+ }
115
+ export interface Plugin {
116
+ manifest: PluginManifest;
117
+ setup?(ctx: PluginContext): void | Promise<void>;
118
+ start?(ctx: PluginContext): void | Promise<void>;
119
+ stop?(ctx: PluginContext): void | Promise<void>;
120
+ }
121
+ export type PluginStatus = 'idle' | 'loading' | 'running' | 'stopped' | 'error';
122
+ export interface PluginInstance {
123
+ id: string;
124
+ manifest: PluginManifest;
125
+ status: PluginStatus;
126
+ error?: string;
127
+ startedAt?: Date;
128
+ stoppedAt?: Date;
129
+ source?: 'native' | 'homebridge';
130
+ disabled?: boolean;
131
+ platformName?: string;
132
+ /**
133
+ * npm package name the plugin was installed as.
134
+ *
135
+ * Distinct from `platformName` (what the plugin calls itself in
136
+ * `registerPlatform`) and from `manifest.name`. It matters because an
137
+ * auto-discovered Homebridge plugin's config is stored in `config.plugins[]`
138
+ * keyed by *package* name, so the UI cannot find that entry from the platform
139
+ * name alone.
140
+ */
141
+ packageName?: string;
142
+ enrichedMetadata?: Record<string, unknown>;
143
+ /** Live telemetry keyed by device ID, set via ctx.reportTelemetry() */
144
+ telemetry?: Record<string, Record<string, unknown>>;
145
+ /** Registered devices keyed by device ID, set via ctx.registerDevice() */
146
+ devices?: Record<string, DeviceDescriptor>;
147
+ /** HAP bridge info if the plugin publishes its own bridge */
148
+ hapBridge?: {
149
+ setupURI: string;
150
+ pincode: string;
151
+ port: number;
152
+ name: string;
153
+ };
154
+ /** Latest version available on npm (set by the update checker) */
155
+ availableUpdate?: string;
156
+ }
157
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@nubisco/openbridge-core",
3
+ "version": "0.29.0",
4
+ "description": "Plugin types, registry, lifecycle, and loader 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/core"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/nubisco/openbridge/issues"
15
+ },
16
+ "keywords": [
17
+ "homekit",
18
+ "home-automation",
19
+ "plugin",
20
+ "hap",
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
+ "scripts": {
50
+ "build": "tsc",
51
+ "dev": "tsc --watch",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "typecheck": "tsc --noEmit"
55
+ }
56
+ }