@matter-server/ble-proxy 0.0.1

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.
Files changed (50) hide show
  1. package/README.md +116 -0
  2. package/dist/esm/BleProxyHandler.d.ts +39 -0
  3. package/dist/esm/BleProxyHandler.d.ts.map +1 -0
  4. package/dist/esm/BleProxyHandler.js +256 -0
  5. package/dist/esm/BleProxyHandler.js.map +6 -0
  6. package/dist/esm/BleProxyProtocol.d.ts +230 -0
  7. package/dist/esm/BleProxyProtocol.d.ts.map +1 -0
  8. package/dist/esm/BleProxyProtocol.js +82 -0
  9. package/dist/esm/BleProxyProtocol.js.map +6 -0
  10. package/dist/esm/ProxyBle.d.ts +24 -0
  11. package/dist/esm/ProxyBle.d.ts.map +1 -0
  12. package/dist/esm/ProxyBle.js +50 -0
  13. package/dist/esm/ProxyBle.js.map +6 -0
  14. package/dist/esm/ProxyBleChannel.d.ts +38 -0
  15. package/dist/esm/ProxyBleChannel.d.ts.map +1 -0
  16. package/dist/esm/ProxyBleChannel.js +314 -0
  17. package/dist/esm/ProxyBleChannel.js.map +6 -0
  18. package/dist/esm/ProxyBleClient.d.ts +32 -0
  19. package/dist/esm/ProxyBleClient.d.ts.map +1 -0
  20. package/dist/esm/ProxyBleClient.js +100 -0
  21. package/dist/esm/ProxyBleClient.js.map +6 -0
  22. package/dist/esm/ProxyBleScanner.d.ts +27 -0
  23. package/dist/esm/ProxyBleScanner.d.ts.map +1 -0
  24. package/dist/esm/ProxyBleScanner.js +23 -0
  25. package/dist/esm/ProxyBleScanner.js.map +6 -0
  26. package/dist/esm/example/NobleBleProxyClient.d.ts +12 -0
  27. package/dist/esm/example/NobleBleProxyClient.d.ts.map +1 -0
  28. package/dist/esm/example/NobleBleProxyClient.js +520 -0
  29. package/dist/esm/example/NobleBleProxyClient.js.map +6 -0
  30. package/dist/esm/example/noble-ble-proxy.d.ts +7 -0
  31. package/dist/esm/example/noble-ble-proxy.d.ts.map +1 -0
  32. package/dist/esm/example/noble-ble-proxy.js +45 -0
  33. package/dist/esm/example/noble-ble-proxy.js.map +6 -0
  34. package/dist/esm/index.d.ts +15 -0
  35. package/dist/esm/index.d.ts.map +1 -0
  36. package/dist/esm/index.js +12 -0
  37. package/dist/esm/index.js.map +6 -0
  38. package/dist/esm/package.json +3 -0
  39. package/package.json +46 -0
  40. package/src/BleProxyHandler.ts +345 -0
  41. package/src/BleProxyProtocol.ts +287 -0
  42. package/src/ProxyBle.ts +64 -0
  43. package/src/ProxyBleChannel.ts +407 -0
  44. package/src/ProxyBleClient.ts +136 -0
  45. package/src/ProxyBleScanner.ts +38 -0
  46. package/src/example/NobleBleProxyClient.ts +679 -0
  47. package/src/example/noble-ble-proxy.ts +62 -0
  48. package/src/index.ts +16 -0
  49. package/src/tsconfig.json +15 -0
  50. package/src/tsconfig.tsbuildinfo +1 -0
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # @matter-server/ble-proxy
2
+
3
+ BLE proxy support for the Matter server — enables BLE commissioning of Matter devices through a remote Bluetooth adapter over WebSocket.
4
+
5
+ ## Overview
6
+
7
+ Instead of requiring a Bluetooth adapter on the server host, a **proxy client** sits next to the BLE hardware and executes BLE commands on behalf of the server over a WebSocket connection:
8
+
9
+ ```
10
+ [Matter Device] <-- BLE --> [Proxy Client] <-- WebSocket /ble --> [Matter Server]
11
+ ```
12
+
13
+ The primary use case is Home Assistant (with local or ESPHome BLE proxies) acting as the proxy client. See the [BLE Proxy Protocol documentation](../../docs/ble-proxy-protocol.md) for the full protocol specification.
14
+
15
+ For a Python implementation of the protocol (Bleak-based CLI + reusable library used by the Home Assistant Matter integration), see [`python_ble_proxy/`](../../python_ble_proxy/) and the [`matter-ble-proxy`](https://pypi.org/project/matter-ble-proxy/) package on PyPI.
16
+
17
+ ## Enabling BLE Proxy Mode on the Server
18
+
19
+ Start the Matter server with the `--ble-proxy` flag:
20
+
21
+ ```bash
22
+ npm run server -- --ble-proxy
23
+ # or
24
+ BLE_PROXY=true npm run server
25
+ ```
26
+
27
+ This exposes a `/ble` WebSocket endpoint (e.g. `ws://localhost:5580/ble`) that proxy clients connect to.
28
+
29
+ > **Note:** `--ble-proxy` and `--bluetooth-adapter` are mutually exclusive.
30
+
31
+ ## Noble Example Client
32
+
33
+ The package includes a reference proxy client that bridges a local Bluetooth adapter to the server using [Noble](https://github.com/stoprocent/noble). This is useful for:
34
+ - Testing BLE commissioning without Home Assistant
35
+ - Running the server on a machine without native BLE bindings
36
+
37
+ ### Prerequisites
38
+
39
+ - A host with a Bluetooth adapter (Linux or macOS)
40
+ - Server running with `--ble-proxy`
41
+ - `@matter/nodejs-ble` optional dependency available (listed in `optionalDependencies`)
42
+
43
+ For Noble-specific setup (permissions, platform requirements, known limitations), see the
44
+ [Noble prerequisites section](https://github.com/matter-js/matter.js/tree/main/packages/nodejs-ble#prerequisites-and-limitations)
45
+ in the `@matter/nodejs-ble` README.
46
+
47
+ ### Running
48
+
49
+ ```bash
50
+ # Default: connect to ws://localhost:5580/ble
51
+ npm run noble-ble-proxy
52
+
53
+ # Custom server URL
54
+ npm run noble-ble-proxy -- --server ws://192.168.1.100:5580/ble
55
+
56
+ # Specific HCI adapter
57
+ npm run noble-ble-proxy -- --hci-id 1
58
+
59
+ # Help
60
+ npm run noble-ble-proxy -- --help
61
+ ```
62
+
63
+ Once connected, you will see:
64
+
65
+ ```
66
+ Connecting to ws://localhost:5580/ble...
67
+ BLE proxy handshake complete (protocol v1)
68
+ Connected. BLE proxy active. Press Ctrl+C to stop.
69
+ ```
70
+
71
+ The proxy stays connected and handles BLE commissioning commands transparently whenever a commission-via-BLE is triggered.
72
+
73
+ ## Python Example Client
74
+
75
+ The repository also ships a Python reference proxy client built on
76
+ [Bleak](https://github.com/hbldh/bleak), published to PyPI as
77
+ [`matter-ble-proxy`](https://pypi.org/project/matter-ble-proxy/). Same use
78
+ cases as the Noble client; pick whichever stack you already have set up. The
79
+ Home Assistant Matter integration consumes the library form of this package.
80
+
81
+ ### Prerequisites
82
+
83
+ - Python 3.12+
84
+ - A host with a Bluetooth adapter (Linux, macOS, or Windows — Bleak supports all three)
85
+ - Server running with `--ble-proxy`
86
+
87
+ ### Running from a release
88
+
89
+ ```bash
90
+ pip install matter-ble-proxy
91
+ matter-ble-proxy --server ws://localhost:5580/ble
92
+ ```
93
+
94
+ ### Running from this repository
95
+
96
+ ```bash
97
+ # Default: connect to ws://localhost:5580/ble
98
+ npm run python-ble-proxy:run
99
+
100
+ # Custom server URL
101
+ npm run python-ble-proxy:run -- --server ws://192.168.1.100:5580/ble --log-level INFO
102
+ ```
103
+
104
+ Once connected, you will see:
105
+
106
+ ```
107
+ 17:46:35.541 INFO matter_ble_proxy.cli: Connected. BLE proxy active. Press Ctrl+C to stop.
108
+ ```
109
+
110
+ See [`python_ble_proxy/`](../../python_ble_proxy/) for the library API
111
+ (`MatterBleProxy`, `BleScanSource`, `BleDeviceResolver`, ...) used by
112
+ integrators that bring their own BLE source.
113
+
114
+ ## Home Assistant Integration
115
+
116
+ The Home Assistant Matter integration automatically connects to `/ble` when the server reports `ble_proxy_enabled: true`. Start the server with `--ble-proxy` (or `ble_proxy: true` in the add-on config). No further HA-side configuration is needed.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { WebServerHandler } from "@matter-server/ws-controller";
7
+ import { Observable } from "@matter/main";
8
+ import type { createServer } from "node:http";
9
+ import { type BinaryFrame, type BleProxyCommandMap, type BleProxyCommandName, type BleProxyEventName } from "./BleProxyProtocol.js";
10
+ type HttpServer = ReturnType<typeof createServer>;
11
+ /**
12
+ * WebSocket server handler for the /ble BLE proxy endpoint.
13
+ *
14
+ * Accepts a single client connection, performs the protocol handshake,
15
+ * and routes commands/events/binary frames between the proxy implementation
16
+ * and the connected BLE proxy client.
17
+ */
18
+ export declare class BleProxyHandler implements WebServerHandler {
19
+ #private;
20
+ /** Emitted when a JSON event is received from the BLE proxy client. */
21
+ readonly eventReceived: Observable<[event: BleProxyEventName, data: Record<string, unknown>], void>;
22
+ /** Emitted when a binary frame is received from the BLE proxy client. */
23
+ readonly binaryFrameReceived: Observable<[frame: BinaryFrame], void>;
24
+ get connected(): boolean;
25
+ register(server: HttpServer): Promise<void>;
26
+ unregister(): Promise<void>;
27
+ /**
28
+ * Send a typed command to the BLE proxy client and wait for the response.
29
+ * The return type is inferred from the command name via BleProxyCommandMap.
30
+ * Rejects if no client is connected or the client disconnects before responding.
31
+ */
32
+ sendCommand<C extends BleProxyCommandName>(command: C, ...rest: BleProxyCommandMap[C]["args"] extends undefined ? [] : [args: BleProxyCommandMap[C]["args"]]): Promise<BleProxyCommandMap[C]["result"]>;
33
+ /**
34
+ * Send a binary frame to the BLE proxy client.
35
+ */
36
+ sendBinaryFrame(opcode: number, connectionHandle: number, payload: Uint8Array): void;
37
+ }
38
+ export {};
39
+ //# sourceMappingURL=BleProxyHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BleProxyHandler.d.ts","sourceRoot":"","sources":["../../src/BleProxyHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAyB,UAAU,EAAqC,MAAM,cAAc,CAAC;AACpG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAIH,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EAKzB,MAAM,uBAAuB,CAAC;AAE/B,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AAclD;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;;IAcpD,uEAAuE;IACvE,QAAQ,CAAC,aAAa,8EAA+E;IAErG,yEAAyE;IACzE,QAAQ,CAAC,mBAAmB,yCAA0C;IAEtE,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEhD;IAED,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAmC1B;IAED;;;;OAIG;IACG,WAAW,CAAC,CAAC,SAAS,mBAAmB,EAC3C,OAAO,EAAE,CAAC,EACV,GAAG,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,SAAS,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GACtG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CA0B1C;IAED;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAMnF;CAwHJ"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { createPromise, Logger, Observable, Seconds, Time, withTimeout } from "@matter/main";
7
+ import { WebSocket, WebSocketServer } from "ws";
8
+ import {
9
+ BLE_PROXY_PROTOCOL_VERSION,
10
+ decodeBinaryFrame,
11
+ encodeBinaryFrame
12
+ } from "./BleProxyProtocol.js";
13
+ const logger = Logger.get("BleProxyHandler");
14
+ const HANDSHAKE_TIMEOUT = Seconds(10);
15
+ const COMMAND_TIMEOUT = Seconds(60);
16
+ class BleProxyHandler {
17
+ #wss;
18
+ /** Upgrade listener removers, one per HTTP server `register()` call (multi-bind). */
19
+ #removeUpgradeListeners = [];
20
+ #client;
21
+ #handshakeComplete = false;
22
+ #pendingCommands = /* @__PURE__ */ new Map();
23
+ /** Command ID counter. Rolls over at 0xFFFF to stay in safe integer range. */
24
+ #nextCommandId = 0;
25
+ #closed = false;
26
+ /** Emitted when a JSON event is received from the BLE proxy client. */
27
+ eventReceived = new Observable();
28
+ /** Emitted when a binary frame is received from the BLE proxy client. */
29
+ binaryFrameReceived = new Observable();
30
+ get connected() {
31
+ return this.#handshakeComplete && this.#client?.readyState === WebSocket.OPEN;
32
+ }
33
+ async register(server) {
34
+ const wss = this.#wss = new WebSocketServer({ noServer: true });
35
+ const upgradeHandler = (req, socket, head) => {
36
+ logger.debug(`Upgrade request received: ${req.url}`);
37
+ const path = req.url?.split("?")[0];
38
+ if (path === "/ble") {
39
+ req._matterHandledUpgrade = true;
40
+ wss.handleUpgrade(
41
+ req,
42
+ socket,
43
+ head,
44
+ (ws) => wss.emit("connection", ws, req)
45
+ );
46
+ }
47
+ };
48
+ server.on("upgrade", upgradeHandler);
49
+ this.#removeUpgradeListeners.push(() => server.removeListener("upgrade", upgradeHandler));
50
+ logger.info("BLE proxy WebSocket endpoint registered on /ble");
51
+ wss.on("connection", (ws) => {
52
+ if (this.#closed) {
53
+ ws.close();
54
+ return;
55
+ }
56
+ if (this.#client) {
57
+ logger.warn("Rejecting new BLE proxy client - only one connection allowed");
58
+ ws.close(4e3, "Only one BLE proxy client allowed");
59
+ return;
60
+ }
61
+ logger.info("BLE proxy client connected, waiting for handshake");
62
+ this.#client = ws;
63
+ this.#handshakeComplete = false;
64
+ const handshakeTimer = Time.getTimer("BLE proxy handshake timeout", HANDSHAKE_TIMEOUT, () => {
65
+ if (!this.#handshakeComplete) {
66
+ logger.warn("BLE proxy handshake timeout - closing connection");
67
+ ws.close(4001, "Handshake timeout");
68
+ this.#cleanupClient();
69
+ }
70
+ }).start();
71
+ ws.on("message", (data, isBinary) => {
72
+ if (isBinary) {
73
+ this.#handleBinaryMessage(data);
74
+ } else {
75
+ this.#handleTextMessage(data.toString(), handshakeTimer);
76
+ }
77
+ });
78
+ ws.on("close", () => {
79
+ handshakeTimer.stop();
80
+ logger.info("BLE proxy client disconnected");
81
+ this.#cleanupClient();
82
+ });
83
+ ws.on("error", (err) => {
84
+ logger.error("BLE proxy WebSocket error:", err);
85
+ handshakeTimer.stop();
86
+ this.#cleanupClient();
87
+ });
88
+ });
89
+ }
90
+ unregister() {
91
+ if (!this.#wss || this.#closed) {
92
+ return Promise.resolve();
93
+ }
94
+ this.#closed = true;
95
+ for (const remove of this.#removeUpgradeListeners) remove();
96
+ this.#removeUpgradeListeners = [];
97
+ if (this.#client && this.#client.readyState === WebSocket.OPEN) {
98
+ this.#client.close();
99
+ }
100
+ this.#cleanupClient();
101
+ const wss = this.#wss;
102
+ this.#wss = void 0;
103
+ wss.clients.forEach((client) => {
104
+ if (client.readyState === WebSocket.OPEN) {
105
+ client.close();
106
+ }
107
+ });
108
+ return new Promise((resolve, reject) => {
109
+ wss.close((err) => {
110
+ if (err) {
111
+ reject(err);
112
+ } else {
113
+ resolve();
114
+ }
115
+ });
116
+ });
117
+ }
118
+ /**
119
+ * Send a typed command to the BLE proxy client and wait for the response.
120
+ * The return type is inferred from the command name via BleProxyCommandMap.
121
+ * Rejects if no client is connected or the client disconnects before responding.
122
+ */
123
+ async sendCommand(command, ...rest) {
124
+ if (!this.connected || !this.#client) {
125
+ throw new Error("BLE proxy client not connected");
126
+ }
127
+ const args = rest[0];
128
+ const id = this.#nextCommandId;
129
+ this.#nextCommandId = this.#nextCommandId + 1 & 65535;
130
+ const message = { id, command };
131
+ if (args !== void 0) {
132
+ message.args = args;
133
+ }
134
+ const { promise, resolver, rejecter } = createPromise();
135
+ this.#pendingCommands.set(id, { resolver, rejecter });
136
+ this.#client.send(JSON.stringify(message), (err) => {
137
+ if (err) {
138
+ this.#pendingCommands.delete(id);
139
+ rejecter(new Error(`Failed to send command ${command}: ${err.message}`));
140
+ }
141
+ });
142
+ return withTimeout(COMMAND_TIMEOUT, promise, () => this.#pendingCommands.delete(id));
143
+ }
144
+ /**
145
+ * Send a binary frame to the BLE proxy client.
146
+ */
147
+ sendBinaryFrame(opcode, connectionHandle, payload) {
148
+ if (!this.connected || !this.#client) {
149
+ throw new Error("BLE proxy client not connected");
150
+ }
151
+ const frame = encodeBinaryFrame(opcode, connectionHandle, payload);
152
+ this.#client.send(frame);
153
+ }
154
+ #handleTextMessage(raw, handshakeTimer) {
155
+ let parsed;
156
+ try {
157
+ parsed = JSON.parse(raw);
158
+ } catch {
159
+ logger.warn("Received invalid JSON from BLE proxy client");
160
+ return;
161
+ }
162
+ const msg = parsed;
163
+ if (!this.#handshakeComplete) {
164
+ this.#handleHandshake(msg, handshakeTimer);
165
+ return;
166
+ }
167
+ if ("id" in msg && "success" in msg) {
168
+ this.#handleResponse(msg);
169
+ return;
170
+ }
171
+ if ("event" in msg && "data" in msg) {
172
+ this.#handleEvent(msg);
173
+ return;
174
+ }
175
+ logger.warn("Received unknown message from BLE proxy client:", msg);
176
+ }
177
+ #handleHandshake(msg, handshakeTimer) {
178
+ if (msg.type !== "hello") {
179
+ logger.warn(`Expected hello message, got: ${JSON.stringify(msg)}`);
180
+ this.#client?.close(4002, "Expected hello message");
181
+ this.#cleanupClient();
182
+ return;
183
+ }
184
+ const hello = msg;
185
+ handshakeTimer.stop();
186
+ if (hello.version !== BLE_PROXY_PROTOCOL_VERSION) {
187
+ logger.warn(
188
+ `BLE proxy client version ${hello.version} not supported (server supports ${BLE_PROXY_PROTOCOL_VERSION})`
189
+ );
190
+ this.#client?.send(
191
+ JSON.stringify({
192
+ type: "hello_response",
193
+ version: BLE_PROXY_PROTOCOL_VERSION,
194
+ error: "unsupported_version",
195
+ message: `Server supports protocol version ${BLE_PROXY_PROTOCOL_VERSION}, client sent version ${hello.version}`
196
+ })
197
+ );
198
+ this.#client?.close(4003, "Unsupported protocol version");
199
+ this.#cleanupClient();
200
+ return;
201
+ }
202
+ this.#handshakeComplete = true;
203
+ this.#client?.send(
204
+ JSON.stringify({
205
+ type: "hello_response",
206
+ version: BLE_PROXY_PROTOCOL_VERSION
207
+ })
208
+ );
209
+ logger.info(`BLE proxy handshake complete (version ${BLE_PROXY_PROTOCOL_VERSION})`);
210
+ }
211
+ #handleResponse(msg) {
212
+ const pending = this.#pendingCommands.get(msg.id);
213
+ if (!pending) {
214
+ logger.warn(`Received response for unknown command id ${msg.id}`);
215
+ return;
216
+ }
217
+ this.#pendingCommands.delete(msg.id);
218
+ if (msg.success) {
219
+ pending.resolver(msg.result);
220
+ } else {
221
+ pending.rejecter(new Error(`${msg.error}: ${msg.message}`));
222
+ }
223
+ }
224
+ #handleEvent(msg) {
225
+ this.eventReceived.emit(msg.event, msg.data);
226
+ }
227
+ #handleBinaryMessage(data) {
228
+ if (!this.#handshakeComplete) {
229
+ logger.warn("Received binary frame before handshake");
230
+ return;
231
+ }
232
+ try {
233
+ const frame = decodeBinaryFrame(new Uint8Array(data));
234
+ this.binaryFrameReceived.emit(frame);
235
+ } catch (err) {
236
+ logger.error("Failed to decode binary frame:", err);
237
+ }
238
+ }
239
+ #cleanupClient() {
240
+ if (this.#client) {
241
+ if (this.#client.readyState === WebSocket.OPEN) {
242
+ this.#client.close();
243
+ }
244
+ this.#client = void 0;
245
+ }
246
+ this.#handshakeComplete = false;
247
+ for (const [id, pending] of this.#pendingCommands) {
248
+ pending.rejecter(new Error("BLE proxy client disconnected"));
249
+ this.#pendingCommands.delete(id);
250
+ }
251
+ }
252
+ }
253
+ export {
254
+ BleProxyHandler
255
+ };
256
+ //# sourceMappingURL=BleProxyHandler.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/BleProxyHandler.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,SAAS,eAAe,QAAQ,YAAY,SAAS,MAAa,mBAAmB;AAErF,SAAS,WAAW,uBAAuB;AAC3C;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OASG;AAIP,MAAM,SAAS,OAAO,IAAI,iBAAiB;AAE3C,MAAM,oBAAoB,QAAQ,EAAE;AAQpC,MAAM,kBAAkB,QAAQ,EAAE;AAS3B,MAAM,gBAA4C;AAAA,EACrD;AAAA;AAAA,EAEA,0BAA0C,CAAC;AAAA,EAC3C;AAAA,EACA,qBAAqB;AAAA,EACrB,mBAAmB,oBAAI,IAGrB;AAAA;AAAA,EAEF,iBAAiB;AAAA,EACjB,UAAU;AAAA;AAAA,EAGD,gBAAgB,IAAI,WAAsE;AAAA;AAAA,EAG1F,sBAAsB,IAAI,WAAiC;AAAA,EAEpE,IAAI,YAAqB;AACrB,WAAO,KAAK,sBAAsB,KAAK,SAAS,eAAe,UAAU;AAAA,EAC7E;AAAA,EAEA,MAAM,SAAS,QAAmC;AAK9C,UAAM,MAAO,KAAK,OAAO,IAAI,gBAAgB,EAAE,UAAU,KAAK,CAAC;AAC/D,UAAM,iBAAiB,CACnB,KACA,QACA,SACC;AACD,aAAO,MAAM,6BAA6B,IAAI,GAAG,EAAE;AACnD,YAAM,OAAO,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC;AAClC,UAAI,SAAS,QAAQ;AACjB,YAAI,wBAAwB;AAC5B,YAAI;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAM,IAAI,KAAK,cAAc,IAAI,GAAG;AAAA,QACxC;AAAA,MACJ;AAAA,IACJ;AACA,WAAO,GAAG,WAAW,cAAc;AACnC,SAAK,wBAAwB,KAAK,MAAM,OAAO,eAAe,WAAW,cAAc,CAAC;AACxF,WAAO,KAAK,iDAAiD;AAE7D,QAAI,GAAG,cAAc,QAAM;AACvB,UAAI,KAAK,SAAS;AACd,WAAG,MAAM;AACT;AAAA,MACJ;AAEA,UAAI,KAAK,SAAS;AACd,eAAO,KAAK,8DAA8D;AAC1E,WAAG,MAAM,KAAM,mCAAmC;AAClD;AAAA,MACJ;AAEA,aAAO,KAAK,mDAAmD;AAC/D,WAAK,UAAU;AACf,WAAK,qBAAqB;AAE1B,YAAM,iBAAiB,KAAK,SAAS,+BAA+B,mBAAmB,MAAM;AACzF,YAAI,CAAC,KAAK,oBAAoB;AAC1B,iBAAO,KAAK,kDAAkD;AAC9D,aAAG,MAAM,MAAM,mBAAmB;AAClC,eAAK,eAAe;AAAA,QACxB;AAAA,MACJ,CAAC,EAAE,MAAM;AAET,SAAG,GAAG,WAAW,CAAC,MAAM,aAAa;AACjC,YAAI,UAAU;AACV,eAAK,qBAAqB,IAAc;AAAA,QAC5C,OAAO;AACH,eAAK,mBAAmB,KAAK,SAAS,GAAG,cAAc;AAAA,QAC3D;AAAA,MACJ,CAAC;AAED,SAAG,GAAG,SAAS,MAAM;AACjB,uBAAe,KAAK;AACpB,eAAO,KAAK,+BAA+B;AAC3C,aAAK,eAAe;AAAA,MACxB,CAAC;AAED,SAAG,GAAG,SAAS,SAAO;AAClB,eAAO,MAAM,8BAA8B,GAAG;AAC9C,uBAAe,KAAK;AACpB,aAAK,eAAe;AAAA,MACxB,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AAAA,EAEA,aAA4B;AACxB,QAAI,CAAC,KAAK,QAAQ,KAAK,SAAS;AAC5B,aAAO,QAAQ,QAAQ;AAAA,IAC3B;AAEA,SAAK,UAAU;AACf,eAAW,UAAU,KAAK,wBAAyB,QAAO;AAC1D,SAAK,0BAA0B,CAAC;AAGhC,QAAI,KAAK,WAAW,KAAK,QAAQ,eAAe,UAAU,MAAM;AAC5D,WAAK,QAAQ,MAAM;AAAA,IACvB;AACA,SAAK,eAAe;AAEpB,UAAM,MAAM,KAAK;AACjB,SAAK,OAAO;AAGZ,QAAI,QAAQ,QAAQ,YAAU;AAC1B,UAAI,OAAO,eAAe,UAAU,MAAM;AACtC,eAAO,MAAM;AAAA,MACjB;AAAA,IACJ,CAAC;AAGD,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1C,UAAI,MAAM,SAAO;AACb,YAAI,KAAK;AACL,iBAAO,GAAG;AAAA,QACd,OAAO;AACH,kBAAQ;AAAA,QACZ;AAAA,MACJ,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACF,YACG,MACqC;AACxC,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,SAAS;AAClC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACpD;AAEA,UAAM,OAAO,KAAK,CAAC;AACnB,UAAM,KAAK,KAAK;AAChB,SAAK,iBAAkB,KAAK,iBAAiB,IAAK;AAClD,UAAM,UAA0B,EAAE,IAAI,QAAQ;AAC9C,QAAI,SAAS,QAAW;AACpB,cAAQ,OAAO;AAAA,IACnB;AAEA,UAAM,EAAE,SAAS,UAAU,SAAS,IAAI,cAAmD;AAC3F,SAAK,iBAAiB,IAAI,IAAI,EAAE,UAAU,SAAS,CAAC;AAEpD,SAAK,QAAQ,KAAK,KAAK,UAAU,OAAO,GAAG,SAAO;AAC9C,UAAI,KAAK;AACL,aAAK,iBAAiB,OAAO,EAAE;AAC/B,iBAAS,IAAI,MAAM,0BAA0B,OAAO,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,MAC3E;AAAA,IACJ,CAAC;AAED,WAAO,YAAY,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,OAAO,EAAE,CAAC;AAAA,EAGvF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,QAAgB,kBAA0B,SAA2B;AACjF,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK,SAAS;AAClC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACpD;AACA,UAAM,QAAQ,kBAAkB,QAAQ,kBAAkB,OAAO;AACjE,SAAK,QAAQ,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,mBAAmB,KAAa,gBAA6B;AACzD,QAAI;AACJ,QAAI;AACA,eAAS,KAAK,MAAM,GAAG;AAAA,IAC3B,QAAQ;AACJ,aAAO,KAAK,6CAA6C;AACzD;AAAA,IACJ;AAEA,UAAM,MAAM;AAGZ,QAAI,CAAC,KAAK,oBAAoB;AAC1B,WAAK,iBAAiB,KAAK,cAAc;AACzC;AAAA,IACJ;AAGA,QAAI,QAAQ,OAAO,aAAa,KAAK;AACjC,WAAK,gBAAgB,GAAiC;AACtD;AAAA,IACJ;AAGA,QAAI,WAAW,OAAO,UAAU,KAAK;AACjC,WAAK,aAAa,GAA8B;AAChD;AAAA,IACJ;AAEA,WAAO,KAAK,mDAAmD,GAAG;AAAA,EACtE;AAAA,EAEA,iBAAiB,KAA8B,gBAA6B;AACxE,QAAI,IAAI,SAAS,SAAS;AACtB,aAAO,KAAK,gCAAgC,KAAK,UAAU,GAAG,CAAC,EAAE;AACjE,WAAK,SAAS,MAAM,MAAM,wBAAwB;AAClD,WAAK,eAAe;AACpB;AAAA,IACJ;AAEA,UAAM,QAAQ;AACd,mBAAe,KAAK;AAEpB,QAAI,MAAM,YAAY,4BAA4B;AAC9C,aAAO;AAAA,QACH,4BAA4B,MAAM,OAAO,mCAAmC,0BAA0B;AAAA,MAC1G;AACA,WAAK,SAAS;AAAA,QACV,KAAK,UAAU;AAAA,UACX,MAAM;AAAA,UACN,SAAS;AAAA,UACT,OAAO;AAAA,UACP,SAAS,oCAAoC,0BAA0B,yBAAyB,MAAM,OAAO;AAAA,QACjH,CAAC;AAAA,MACL;AACA,WAAK,SAAS,MAAM,MAAM,8BAA8B;AACxD,WAAK,eAAe;AACpB;AAAA,IACJ;AAEA,SAAK,qBAAqB;AAC1B,SAAK,SAAS;AAAA,MACV,KAAK,UAAU;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,MACb,CAAC;AAAA,IACL;AACA,WAAO,KAAK,yCAAyC,0BAA0B,GAAG;AAAA,EACtF;AAAA,EAEA,gBAAgB,KAA4B;AACxC,UAAM,UAAU,KAAK,iBAAiB,IAAI,IAAI,EAAE;AAChD,QAAI,CAAC,SAAS;AACV,aAAO,KAAK,4CAA4C,IAAI,EAAE,EAAE;AAChE;AAAA,IACJ;AACA,SAAK,iBAAiB,OAAO,IAAI,EAAE;AAEnC,QAAI,IAAI,SAAS;AACb,cAAQ,SAAS,IAAI,MAAM;AAAA,IAC/B,OAAO;AACH,cAAQ,SAAS,IAAI,MAAM,GAAG,IAAI,KAAK,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,IAC9D;AAAA,EACJ;AAAA,EAEA,aAAa,KAAyB;AAClC,SAAK,cAAc,KAAK,IAAI,OAAO,IAAI,IAAI;AAAA,EAC/C;AAAA,EAEA,qBAAqB,MAAoB;AACrC,QAAI,CAAC,KAAK,oBAAoB;AAC1B,aAAO,KAAK,wCAAwC;AACpD;AAAA,IACJ;AAEA,QAAI;AACA,YAAM,QAAQ,kBAAkB,IAAI,WAAW,IAAI,CAAC;AACpD,WAAK,oBAAoB,KAAK,KAAK;AAAA,IACvC,SAAS,KAAK;AACV,aAAO,MAAM,kCAAkC,GAAG;AAAA,IACtD;AAAA,EACJ;AAAA,EAEA,iBAAuB;AACnB,QAAI,KAAK,SAAS;AACd,UAAI,KAAK,QAAQ,eAAe,UAAU,MAAM;AAC5C,aAAK,QAAQ,MAAM;AAAA,MACvB;AACA,WAAK,UAAU;AAAA,IACnB;AACA,SAAK,qBAAqB;AAG1B,eAAW,CAAC,IAAI,OAAO,KAAK,KAAK,kBAAkB;AAC/C,cAAQ,SAAS,IAAI,MAAM,+BAA+B,CAAC;AAC3D,WAAK,iBAAiB,OAAO,EAAE;AAAA,IACnC;AAAA,EACJ;AACJ;",
5
+ "names": []
6
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ /**
7
+ * BLE Proxy Protocol constants, types, and codec.
8
+ * See docs/ble-proxy-protocol.md for the full specification.
9
+ */
10
+ export declare const BLE_PROXY_PROTOCOL_VERSION = 1;
11
+ export interface HelloMessage {
12
+ type: "hello";
13
+ version: number;
14
+ }
15
+ export interface HelloResponseMessage {
16
+ type: "hello_response";
17
+ version: number;
18
+ error?: string;
19
+ message?: string;
20
+ }
21
+ export type HandshakeMessage = HelloMessage | HelloResponseMessage;
22
+ export declare const BleProxyCommand: {
23
+ readonly StartScan: "start_scan";
24
+ readonly StopScan: "stop_scan";
25
+ readonly Connect: "connect";
26
+ readonly Disconnect: "disconnect";
27
+ readonly DiscoverServices: "discover_services";
28
+ readonly DiscoverCharacteristics: "discover_characteristics";
29
+ readonly ReadCharacteristic: "read_characteristic";
30
+ readonly WriteCharacteristic: "write_characteristic";
31
+ readonly SubscribeCharacteristic: "subscribe_characteristic";
32
+ readonly UnsubscribeCharacteristic: "unsubscribe_characteristic";
33
+ readonly RequestMtu: "request_mtu";
34
+ };
35
+ export type BleProxyCommandName = (typeof BleProxyCommand)[keyof typeof BleProxyCommand];
36
+ export declare const BleProxyEvent: {
37
+ readonly DeviceDiscovered: "device_discovered";
38
+ readonly Disconnected: "disconnected";
39
+ readonly ScanStopped: "scan_stopped";
40
+ readonly CharacteristicNotification: "characteristic_notification";
41
+ };
42
+ export type BleProxyEventName = (typeof BleProxyEvent)[keyof typeof BleProxyEvent];
43
+ export interface StartScanArgs {
44
+ service_uuids?: string[];
45
+ allow_duplicates?: boolean;
46
+ }
47
+ export interface ConnectArgs {
48
+ address: string;
49
+ timeout?: number;
50
+ }
51
+ export interface DisconnectArgs {
52
+ connection_handle: number;
53
+ }
54
+ export interface DiscoverServicesArgs {
55
+ connection_handle: number;
56
+ }
57
+ export interface DiscoverCharacteristicsArgs {
58
+ connection_handle: number;
59
+ service_uuid: string;
60
+ }
61
+ export interface ReadCharacteristicArgs {
62
+ connection_handle: number;
63
+ characteristic_uuid: string;
64
+ }
65
+ export interface WriteCharacteristicArgs {
66
+ connection_handle: number;
67
+ characteristic_uuid: string;
68
+ value: string;
69
+ response?: boolean;
70
+ }
71
+ export interface SubscribeCharacteristicArgs {
72
+ connection_handle: number;
73
+ characteristic_uuid: string;
74
+ }
75
+ export interface UnsubscribeCharacteristicArgs {
76
+ connection_handle: number;
77
+ characteristic_uuid: string;
78
+ }
79
+ export interface RequestMtuArgs {
80
+ connection_handle: number;
81
+ mtu: number;
82
+ }
83
+ export interface ConnectResult {
84
+ connection_handle: number;
85
+ mtu: number;
86
+ }
87
+ export interface DiscoverServicesResult {
88
+ services: Array<{
89
+ uuid: string;
90
+ }>;
91
+ }
92
+ export interface DiscoverCharacteristicsResult {
93
+ characteristics: Array<{
94
+ uuid: string;
95
+ properties: string[];
96
+ }>;
97
+ }
98
+ export interface ReadCharacteristicResult {
99
+ value: string;
100
+ }
101
+ export interface RequestMtuResult {
102
+ mtu: number;
103
+ }
104
+ export interface DeviceDiscoveredData {
105
+ address: string;
106
+ name?: string;
107
+ rssi?: number;
108
+ connectable: boolean;
109
+ service_data?: Record<string, string>;
110
+ manufacturer_data?: Record<string, string>;
111
+ service_uuids?: string[];
112
+ }
113
+ export interface DisconnectedData {
114
+ connection_handle: number;
115
+ reason?: string;
116
+ }
117
+ export interface ScanStoppedData {
118
+ reason: string;
119
+ }
120
+ export interface CharacteristicNotificationData {
121
+ connection_handle: number;
122
+ characteristic_uuid: string;
123
+ value: string;
124
+ }
125
+ /** Maps each command name to its args and result types for type-safe sendCommand. */
126
+ export interface BleProxyCommandMap {
127
+ [BleProxyCommand.StartScan]: {
128
+ args: StartScanArgs;
129
+ result: void;
130
+ };
131
+ [BleProxyCommand.StopScan]: {
132
+ args: undefined;
133
+ result: void;
134
+ };
135
+ [BleProxyCommand.Connect]: {
136
+ args: ConnectArgs;
137
+ result: ConnectResult;
138
+ };
139
+ [BleProxyCommand.Disconnect]: {
140
+ args: DisconnectArgs;
141
+ result: void;
142
+ };
143
+ [BleProxyCommand.DiscoverServices]: {
144
+ args: DiscoverServicesArgs;
145
+ result: DiscoverServicesResult;
146
+ };
147
+ [BleProxyCommand.DiscoverCharacteristics]: {
148
+ args: DiscoverCharacteristicsArgs;
149
+ result: DiscoverCharacteristicsResult;
150
+ };
151
+ [BleProxyCommand.ReadCharacteristic]: {
152
+ args: ReadCharacteristicArgs;
153
+ result: ReadCharacteristicResult;
154
+ };
155
+ [BleProxyCommand.WriteCharacteristic]: {
156
+ args: WriteCharacteristicArgs;
157
+ result: void;
158
+ };
159
+ [BleProxyCommand.SubscribeCharacteristic]: {
160
+ args: SubscribeCharacteristicArgs;
161
+ result: void;
162
+ };
163
+ [BleProxyCommand.UnsubscribeCharacteristic]: {
164
+ args: UnsubscribeCharacteristicArgs;
165
+ result: void;
166
+ };
167
+ [BleProxyCommand.RequestMtu]: {
168
+ args: RequestMtuArgs;
169
+ result: RequestMtuResult;
170
+ };
171
+ }
172
+ export interface CommandMessage {
173
+ id: number;
174
+ command: BleProxyCommandName;
175
+ args?: Record<string, unknown>;
176
+ }
177
+ export interface SuccessResponseMessage {
178
+ id: number;
179
+ success: true;
180
+ result?: Record<string, unknown>;
181
+ }
182
+ export interface ErrorResponseMessage {
183
+ id: number;
184
+ success: false;
185
+ error: string;
186
+ message: string;
187
+ }
188
+ export type ResponseMessage = SuccessResponseMessage | ErrorResponseMessage;
189
+ export interface EventMessage {
190
+ event: BleProxyEventName;
191
+ data: Record<string, unknown>;
192
+ }
193
+ export declare const BleProxyErrorCode: {
194
+ readonly BluetoothUnavailable: "bluetooth_unavailable";
195
+ readonly AlreadyScanning: "already_scanning";
196
+ readonly NotScanning: "not_scanning";
197
+ readonly DeviceNotFound: "device_not_found";
198
+ readonly ConnectionFailed: "connection_failed";
199
+ readonly AlreadyConnected: "already_connected";
200
+ readonly NotConnected: "not_connected";
201
+ readonly Timeout: "timeout";
202
+ readonly ServiceNotFound: "service_not_found";
203
+ readonly CharacteristicNotFound: "characteristic_not_found";
204
+ readonly ReadFailed: "read_failed";
205
+ readonly WriteFailed: "write_failed";
206
+ readonly SubscribeFailed: "subscribe_failed";
207
+ readonly NotSubscribed: "not_subscribed";
208
+ readonly NotifyNotSupported: "notify_not_supported";
209
+ readonly MtuRequestFailed: "mtu_request_failed";
210
+ readonly DiscoveryFailed: "discovery_failed";
211
+ readonly InternalError: "internal_error";
212
+ };
213
+ export type BleProxyErrorCodeValue = (typeof BleProxyErrorCode)[keyof typeof BleProxyErrorCode];
214
+ export declare const BinaryFrameOpcode: {
215
+ /** Server -> Client: write payload to the active write characteristic */
216
+ readonly WriteData: 1;
217
+ /** Client -> Server: notification data from a subscribed characteristic */
218
+ readonly Notification: 2;
219
+ /** Client -> Server: response data for a read_characteristic command */
220
+ readonly ReadResponse: 3;
221
+ };
222
+ export type BinaryFrameOpcodeValue = (typeof BinaryFrameOpcode)[keyof typeof BinaryFrameOpcode];
223
+ export interface BinaryFrame {
224
+ opcode: number;
225
+ connectionHandle: number;
226
+ payload: Uint8Array;
227
+ }
228
+ export declare function encodeBinaryFrame(opcode: number, connectionHandle: number, payload: Uint8Array): Uint8Array;
229
+ export declare function decodeBinaryFrame(data: Uint8Array): BinaryFrame;
230
+ //# sourceMappingURL=BleProxyProtocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BleProxyProtocol.d.ts","sourceRoot":"","sources":["../../src/BleProxyProtocol.ts"],"names":[],"mappings":"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"}