@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
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { Logger } from "@matter/main";
7
+ import { MatterBle } from "@matter/main/protocol";
8
+ import { BleProxyCommand, BleProxyEvent } from "./BleProxyProtocol.js";
9
+ const logger = Logger.get("ProxyBleClient");
10
+ class ProxyBleClient {
11
+ #handler;
12
+ #discoveredPeripherals = /* @__PURE__ */ new Map();
13
+ #deviceDiscoveredCallback;
14
+ #isScanning = false;
15
+ #eventObserver = (event, data) => {
16
+ if (event === BleProxyEvent.DeviceDiscovered) {
17
+ this.#handleDeviceDiscovered(data);
18
+ } else if (event === BleProxyEvent.ScanStopped) {
19
+ logger.info(`Scan stopped by proxy client: ${data.reason ?? "unknown"}`);
20
+ this.#isScanning = false;
21
+ }
22
+ };
23
+ constructor(handler) {
24
+ this.#handler = handler;
25
+ this.#handler.eventReceived.on(this.#eventObserver);
26
+ }
27
+ setDiscoveryCallback(callback) {
28
+ this.#deviceDiscoveredCallback = callback;
29
+ for (const { peripheral, matterServiceData } of this.#discoveredPeripherals.values()) {
30
+ this.#deviceDiscoveredCallback(peripheral, matterServiceData);
31
+ }
32
+ }
33
+ async startScanning() {
34
+ if (this.#isScanning) {
35
+ return;
36
+ }
37
+ if (!this.#handler.connected) {
38
+ logger.info("BLE proxy not connected, deferring scan start");
39
+ return;
40
+ }
41
+ logger.debug("Start BLE scanning via proxy ...");
42
+ await this.#handler.sendCommand(BleProxyCommand.StartScan, {
43
+ service_uuids: ["fff6"],
44
+ allow_duplicates: true
45
+ });
46
+ this.#isScanning = true;
47
+ }
48
+ async stopScanning() {
49
+ if (!this.#isScanning) {
50
+ return;
51
+ }
52
+ if (!this.#handler.connected) {
53
+ this.#isScanning = false;
54
+ return;
55
+ }
56
+ logger.debug("Stop BLE scanning via proxy ...");
57
+ await this.#handler.sendCommand(BleProxyCommand.StopScan);
58
+ this.#isScanning = false;
59
+ }
60
+ close() {
61
+ this.#isScanning = false;
62
+ this.#handler.eventReceived.off(this.#eventObserver);
63
+ }
64
+ #handleDeviceDiscovered(data) {
65
+ const { address, name, rssi, connectable, service_data } = data;
66
+ const serviceData = /* @__PURE__ */ new Map();
67
+ let matterServiceData;
68
+ if (service_data) {
69
+ for (const [uuid, base64Value] of Object.entries(service_data)) {
70
+ const bytes = Buffer.from(base64Value, "base64");
71
+ serviceData.set(uuid, bytes);
72
+ if (MatterBle.isServiceUuid(uuid)) {
73
+ matterServiceData = bytes;
74
+ }
75
+ }
76
+ }
77
+ const peripheral = {
78
+ address,
79
+ name,
80
+ rssi,
81
+ connectable,
82
+ serviceData
83
+ };
84
+ if (!connectable) {
85
+ logger.debug(`Peripheral ${address} is not connectable, ignoring`);
86
+ return;
87
+ }
88
+ if (matterServiceData === void 0 || matterServiceData.length !== 8) {
89
+ logger.debug(`Peripheral ${address} does not advertise valid Matter service data, ignoring`);
90
+ return;
91
+ }
92
+ logger.debug(`Discovered device ${address} (${name ?? "unnamed"}) via proxy`);
93
+ this.#discoveredPeripherals.set(address, { peripheral, matterServiceData });
94
+ this.#deviceDiscoveredCallback?.(peripheral, matterServiceData);
95
+ }
96
+ }
97
+ export {
98
+ ProxyBleClient
99
+ };
100
+ //# sourceMappingURL=ProxyBleClient.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ProxyBleClient.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAE1B,SAAS,iBAAiB,qBAAgD;AAE1E,MAAM,SAAS,OAAO,IAAI,gBAAgB;AAoBnC,MAAM,eAAe;AAAA,EACf;AAAA,EACA,yBAAyB,oBAAI,IAA4E;AAAA,EAClH;AAAA,EACA,cAAc;AAAA,EAEL,iBAAiB,CAAC,OAAe,SAAkC;AACxE,QAAI,UAAU,cAAc,kBAAkB;AAC1C,WAAK,wBAAwB,IAAuC;AAAA,IACxE,WAAW,UAAU,cAAc,aAAa;AAC5C,aAAO,KAAK,iCAAkC,KAA6B,UAAU,SAAS,EAAE;AAChG,WAAK,cAAc;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,YAAY,SAA0B;AAClC,SAAK,WAAW;AAChB,SAAK,SAAS,cAAc,GAAG,KAAK,cAAc;AAAA,EACtD;AAAA,EAEA,qBAAqB,UAAsF;AACvG,SAAK,4BAA4B;AACjC,eAAW,EAAE,YAAY,kBAAkB,KAAK,KAAK,uBAAuB,OAAO,GAAG;AAClF,WAAK,0BAA0B,YAAY,iBAAiB;AAAA,IAChE;AAAA,EACJ;AAAA,EAEA,MAAM,gBAA+B;AACjC,QAAI,KAAK,aAAa;AAClB;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK,SAAS,WAAW;AAC1B,aAAO,KAAK,+CAA+C;AAC3D;AAAA,IACJ;AAEA,WAAO,MAAM,kCAAkC;AAC/C,UAAM,KAAK,SAAS,YAAY,gBAAgB,WAAW;AAAA,MACvD,eAAe,CAAC,MAAM;AAAA,MACtB,kBAAkB;AAAA,IACtB,CAAC;AACD,SAAK,cAAc;AAAA,EACvB;AAAA,EAEA,MAAM,eAA8B;AAChC,QAAI,CAAC,KAAK,aAAa;AACnB;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK,SAAS,WAAW;AAC1B,WAAK,cAAc;AACnB;AAAA,IACJ;AAEA,WAAO,MAAM,iCAAiC;AAC9C,UAAM,KAAK,SAAS,YAAY,gBAAgB,QAAQ;AACxD,SAAK,cAAc;AAAA,EACvB;AAAA,EAEA,QAAc;AACV,SAAK,cAAc;AACnB,SAAK,SAAS,cAAc,IAAI,KAAK,cAAc;AAAA,EACvD;AAAA,EAEA,wBAAwB,MAAkC;AACtD,UAAM,EAAE,SAAS,MAAM,MAAM,aAAa,aAAa,IAAI;AAI3D,UAAM,cAAc,oBAAI,IAAwB;AAChD,QAAI;AACJ,QAAI,cAAc;AACd,iBAAW,CAAC,MAAM,WAAW,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC5D,cAAM,QAAQ,OAAO,KAAK,aAAa,QAAQ;AAC/C,oBAAY,IAAI,MAAM,KAAK;AAC3B,YAAI,UAAU,cAAc,IAAI,GAAG;AAC/B,8BAAoB;AAAA,QACxB;AAAA,MACJ;AAAA,IACJ;AAEA,UAAM,aAA8B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAEA,QAAI,CAAC,aAAa;AACd,aAAO,MAAM,cAAc,OAAO,+BAA+B;AACjE;AAAA,IACJ;AAEA,QAAI,sBAAsB,UAAa,kBAAkB,WAAW,GAAG;AACnE,aAAO,MAAM,cAAc,OAAO,yDAAyD;AAC3F;AAAA,IACJ;AAEA,WAAO,MAAM,qBAAqB,OAAO,KAAK,QAAQ,SAAS,aAAa;AAC5E,SAAK,uBAAuB,IAAI,SAAS,EAAE,YAAY,kBAAkB,CAAC;AAC1E,SAAK,4BAA4B,YAAY,iBAAiB;AAAA,EAClE;AACJ;",
5
+ "names": []
6
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { BleScanner as BaseBleScanner, type DiscoveredBleDevice } from "@matter/main/protocol";
7
+ import type { ProxyBleClient, ProxyPeripheral } from "./ProxyBleClient.js";
8
+ export type { DiscoveredBleDevice } from "@matter/main/protocol";
9
+ export type DiscoveredProxyBleDevice = Omit<DiscoveredBleDevice, "peripheral"> & {
10
+ peripheral: ProxyPeripheral;
11
+ };
12
+ /**
13
+ * BLE scanner that discovers Matter devices through the BLE proxy.
14
+ *
15
+ * Extends matter.js's base `BleScanner`, which already handles the
16
+ * `findCommissionableDevicesContinuously` waiter loop, advertisement parsing,
17
+ * and cancellation semantics. We only narrow the `getDiscoveredDevice` return
18
+ * type to expose the proxy-side `ProxyPeripheral` and route `closeClient`
19
+ * through `ProxyBleClient.close()`.
20
+ */
21
+ export declare class ProxyBleScanner extends BaseBleScanner {
22
+ #private;
23
+ constructor(proxyClient: ProxyBleClient);
24
+ getDiscoveredDevice(address: string): DiscoveredProxyBleDevice;
25
+ protected closeClient(): void;
26
+ }
27
+ //# sourceMappingURL=ProxyBleScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProxyBleScanner.d.ts","sourceRoot":"","sources":["../../src/ProxyBleScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3E,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,MAAM,wBAAwB,GAAG,IAAI,CAAC,mBAAmB,EAAE,YAAY,CAAC,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAEjH;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,cAAc;;IAG/C,YAAY,WAAW,EAAE,cAAc,EAGtC;IAEQ,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,wBAAwB,CAEtE;IAED,UAAmB,WAAW,IAAI,IAAI,CAErC;CACJ"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { BleScanner as BaseBleScanner } from "@matter/main/protocol";
7
+ class ProxyBleScanner extends BaseBleScanner {
8
+ #proxyClient;
9
+ constructor(proxyClient) {
10
+ super(proxyClient);
11
+ this.#proxyClient = proxyClient;
12
+ }
13
+ getDiscoveredDevice(address) {
14
+ return super.getDiscoveredDevice(address);
15
+ }
16
+ closeClient() {
17
+ this.#proxyClient.close();
18
+ }
19
+ }
20
+ export {
21
+ ProxyBleScanner
22
+ };
23
+ //# sourceMappingURL=ProxyBleScanner.js.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ProxyBleScanner.ts"],
4
+ "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,SAAS,cAAc,sBAAgD;AAgBhE,MAAM,wBAAwB,eAAe;AAAA,EACvC;AAAA,EAET,YAAY,aAA6B;AACrC,UAAM,WAAW;AACjB,SAAK,eAAe;AAAA,EACxB;AAAA,EAES,oBAAoB,SAA2C;AACpE,WAAO,MAAM,oBAAoB,OAAO;AAAA,EAC5C;AAAA,EAEmB,cAAoB;AACnC,SAAK,aAAa,MAAM;AAAA,EAC5B;AACJ;",
5
+ "names": []
6
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025-2026 Open Home Foundation
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ export declare class NobleBleProxyClient {
7
+ #private;
8
+ constructor(serverUrl: string, hciId?: number);
9
+ connect(): Promise<void>;
10
+ close(): void;
11
+ }
12
+ //# sourceMappingURL=NobleBleProxyClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NobleBleProxyClient.d.ts","sourceRoot":"","sources":["../../../src/example/NobleBleProxyClient.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA6EH,qBAAa,mBAAmB;;IAY5B,YAAY,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAI5C;IAEK,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAsE7B;IAED,KAAK,IAAI,IAAI,CAeZ;CA4eJ"}