@voltras/node-sdk 0.1.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.
Files changed (203) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +272 -0
  3. package/dist/cjs/bluetooth/adapters/base.js +116 -0
  4. package/dist/cjs/bluetooth/adapters/base.js.map +1 -0
  5. package/dist/cjs/bluetooth/adapters/index.js +58 -0
  6. package/dist/cjs/bluetooth/adapters/index.js.map +1 -0
  7. package/dist/cjs/bluetooth/adapters/native.js +473 -0
  8. package/dist/cjs/bluetooth/adapters/native.js.map +1 -0
  9. package/dist/cjs/bluetooth/adapters/node.js +228 -0
  10. package/dist/cjs/bluetooth/adapters/node.js.map +1 -0
  11. package/dist/cjs/bluetooth/adapters/types.js +11 -0
  12. package/dist/cjs/bluetooth/adapters/types.js.map +1 -0
  13. package/dist/cjs/bluetooth/adapters/web-bluetooth-base.js +187 -0
  14. package/dist/cjs/bluetooth/adapters/web-bluetooth-base.js.map +1 -0
  15. package/dist/cjs/bluetooth/adapters/web.js +112 -0
  16. package/dist/cjs/bluetooth/adapters/web.js.map +1 -0
  17. package/dist/cjs/bluetooth/controllers/scanner-controller.js +145 -0
  18. package/dist/cjs/bluetooth/controllers/scanner-controller.js.map +1 -0
  19. package/dist/cjs/bluetooth/index.js +27 -0
  20. package/dist/cjs/bluetooth/index.js.map +1 -0
  21. package/dist/cjs/bluetooth/models/connection.js +68 -0
  22. package/dist/cjs/bluetooth/models/connection.js.map +1 -0
  23. package/dist/cjs/bluetooth/models/device.js +26 -0
  24. package/dist/cjs/bluetooth/models/device.js.map +1 -0
  25. package/dist/cjs/bluetooth/models/environment.js +106 -0
  26. package/dist/cjs/bluetooth/models/environment.js.map +1 -0
  27. package/dist/cjs/errors.js +167 -0
  28. package/dist/cjs/errors.js.map +1 -0
  29. package/dist/cjs/index.js +116 -0
  30. package/dist/cjs/index.js.map +1 -0
  31. package/dist/cjs/react/hooks.js +262 -0
  32. package/dist/cjs/react/hooks.js.map +1 -0
  33. package/dist/cjs/react/index.js +18 -0
  34. package/dist/cjs/react/index.js.map +1 -0
  35. package/dist/cjs/sdk/index.js +14 -0
  36. package/dist/cjs/sdk/index.js.map +1 -0
  37. package/dist/cjs/sdk/types.js +8 -0
  38. package/dist/cjs/sdk/types.js.map +1 -0
  39. package/dist/cjs/sdk/voltra-client.js +632 -0
  40. package/dist/cjs/sdk/voltra-client.js.map +1 -0
  41. package/dist/cjs/sdk/voltra-manager.js +419 -0
  42. package/dist/cjs/sdk/voltra-manager.js.map +1 -0
  43. package/dist/cjs/shared/index.js +12 -0
  44. package/dist/cjs/shared/index.js.map +1 -0
  45. package/dist/cjs/shared/utils.js +51 -0
  46. package/dist/cjs/shared/utils.js.map +1 -0
  47. package/dist/cjs/voltra/index.js +56 -0
  48. package/dist/cjs/voltra/index.js.map +1 -0
  49. package/dist/cjs/voltra/models/connection.js +68 -0
  50. package/dist/cjs/voltra/models/connection.js.map +1 -0
  51. package/dist/cjs/voltra/models/device-filter.js +28 -0
  52. package/dist/cjs/voltra/models/device-filter.js.map +1 -0
  53. package/dist/cjs/voltra/models/device.js +152 -0
  54. package/dist/cjs/voltra/models/device.js.map +1 -0
  55. package/dist/cjs/voltra/models/telemetry/frame.js +46 -0
  56. package/dist/cjs/voltra/models/telemetry/frame.js.map +1 -0
  57. package/dist/cjs/voltra/models/telemetry/index.js +14 -0
  58. package/dist/cjs/voltra/models/telemetry/index.js.map +1 -0
  59. package/dist/cjs/voltra/protocol/commands.js +230 -0
  60. package/dist/cjs/voltra/protocol/commands.js.map +1 -0
  61. package/dist/cjs/voltra/protocol/constants.js +136 -0
  62. package/dist/cjs/voltra/protocol/constants.js.map +1 -0
  63. package/dist/cjs/voltra/protocol/data/chains.json +830 -0
  64. package/dist/cjs/voltra/protocol/data/eccentric.json +1598 -0
  65. package/dist/cjs/voltra/protocol/data/protocol.json +54 -0
  66. package/dist/cjs/voltra/protocol/data/weights.json +62 -0
  67. package/dist/cjs/voltra/protocol/index.js +25 -0
  68. package/dist/cjs/voltra/protocol/index.js.map +1 -0
  69. package/dist/cjs/voltra/protocol/telemetry-decoder.js +146 -0
  70. package/dist/cjs/voltra/protocol/telemetry-decoder.js.map +1 -0
  71. package/dist/esm/bluetooth/adapters/base.js +112 -0
  72. package/dist/esm/bluetooth/adapters/base.js.map +1 -0
  73. package/dist/esm/bluetooth/adapters/index.js +51 -0
  74. package/dist/esm/bluetooth/adapters/index.js.map +1 -0
  75. package/dist/esm/bluetooth/adapters/native.js +469 -0
  76. package/dist/esm/bluetooth/adapters/native.js.map +1 -0
  77. package/dist/esm/bluetooth/adapters/node.js +191 -0
  78. package/dist/esm/bluetooth/adapters/node.js.map +1 -0
  79. package/dist/esm/bluetooth/adapters/types.js +10 -0
  80. package/dist/esm/bluetooth/adapters/types.js.map +1 -0
  81. package/dist/esm/bluetooth/adapters/web-bluetooth-base.js +183 -0
  82. package/dist/esm/bluetooth/adapters/web-bluetooth-base.js.map +1 -0
  83. package/dist/esm/bluetooth/adapters/web.js +108 -0
  84. package/dist/esm/bluetooth/adapters/web.js.map +1 -0
  85. package/dist/esm/bluetooth/controllers/scanner-controller.js +141 -0
  86. package/dist/esm/bluetooth/controllers/scanner-controller.js.map +1 -0
  87. package/dist/esm/bluetooth/index.js +17 -0
  88. package/dist/esm/bluetooth/index.js.map +1 -0
  89. package/dist/esm/bluetooth/models/connection.js +63 -0
  90. package/dist/esm/bluetooth/models/connection.js.map +1 -0
  91. package/dist/esm/bluetooth/models/device.js +22 -0
  92. package/dist/esm/bluetooth/models/device.js.map +1 -0
  93. package/dist/esm/bluetooth/models/environment.js +101 -0
  94. package/dist/esm/bluetooth/models/environment.js.map +1 -0
  95. package/dist/esm/errors.js +155 -0
  96. package/dist/esm/errors.js.map +1 -0
  97. package/dist/esm/index.js +72 -0
  98. package/dist/esm/index.js.map +1 -0
  99. package/dist/esm/react/hooks.js +257 -0
  100. package/dist/esm/react/hooks.js.map +1 -0
  101. package/dist/esm/react/index.js +12 -0
  102. package/dist/esm/react/index.js.map +1 -0
  103. package/dist/esm/sdk/index.js +9 -0
  104. package/dist/esm/sdk/index.js.map +1 -0
  105. package/dist/esm/sdk/types.js +7 -0
  106. package/dist/esm/sdk/types.js.map +1 -0
  107. package/dist/esm/sdk/voltra-client.js +628 -0
  108. package/dist/esm/sdk/voltra-client.js.map +1 -0
  109. package/dist/esm/sdk/voltra-manager.js +415 -0
  110. package/dist/esm/sdk/voltra-manager.js.map +1 -0
  111. package/dist/esm/shared/index.js +5 -0
  112. package/dist/esm/shared/index.js.map +1 -0
  113. package/dist/esm/shared/utils.js +45 -0
  114. package/dist/esm/shared/utils.js.map +1 -0
  115. package/dist/esm/voltra/index.js +26 -0
  116. package/dist/esm/voltra/index.js.map +1 -0
  117. package/dist/esm/voltra/models/connection.js +63 -0
  118. package/dist/esm/voltra/models/connection.js.map +1 -0
  119. package/dist/esm/voltra/models/device-filter.js +23 -0
  120. package/dist/esm/voltra/models/device-filter.js.map +1 -0
  121. package/dist/esm/voltra/models/device.js +148 -0
  122. package/dist/esm/voltra/models/device.js.map +1 -0
  123. package/dist/esm/voltra/models/telemetry/frame.js +40 -0
  124. package/dist/esm/voltra/models/telemetry/frame.js.map +1 -0
  125. package/dist/esm/voltra/models/telemetry/index.js +7 -0
  126. package/dist/esm/voltra/models/telemetry/index.js.map +1 -0
  127. package/dist/esm/voltra/protocol/commands.js +224 -0
  128. package/dist/esm/voltra/protocol/commands.js.map +1 -0
  129. package/dist/esm/voltra/protocol/constants.js +130 -0
  130. package/dist/esm/voltra/protocol/constants.js.map +1 -0
  131. package/dist/esm/voltra/protocol/data/chains.json +830 -0
  132. package/dist/esm/voltra/protocol/data/eccentric.json +1598 -0
  133. package/dist/esm/voltra/protocol/data/protocol.json +54 -0
  134. package/dist/esm/voltra/protocol/data/weights.json +62 -0
  135. package/dist/esm/voltra/protocol/index.js +9 -0
  136. package/dist/esm/voltra/protocol/index.js.map +1 -0
  137. package/dist/esm/voltra/protocol/telemetry-decoder.js +140 -0
  138. package/dist/esm/voltra/protocol/telemetry-decoder.js.map +1 -0
  139. package/dist/types/bluetooth/adapters/base.d.ts +85 -0
  140. package/dist/types/bluetooth/adapters/base.d.ts.map +1 -0
  141. package/dist/types/bluetooth/adapters/index.d.ts +35 -0
  142. package/dist/types/bluetooth/adapters/index.d.ts.map +1 -0
  143. package/dist/types/bluetooth/adapters/native.d.ts +109 -0
  144. package/dist/types/bluetooth/adapters/native.d.ts.map +1 -0
  145. package/dist/types/bluetooth/adapters/node.d.ts +91 -0
  146. package/dist/types/bluetooth/adapters/node.d.ts.map +1 -0
  147. package/dist/types/bluetooth/adapters/types.d.ts +102 -0
  148. package/dist/types/bluetooth/adapters/types.d.ts.map +1 -0
  149. package/dist/types/bluetooth/adapters/web-bluetooth-base.d.ts +90 -0
  150. package/dist/types/bluetooth/adapters/web-bluetooth-base.d.ts.map +1 -0
  151. package/dist/types/bluetooth/adapters/web.d.ts +57 -0
  152. package/dist/types/bluetooth/adapters/web.d.ts.map +1 -0
  153. package/dist/types/bluetooth/controllers/scanner-controller.d.ts +93 -0
  154. package/dist/types/bluetooth/controllers/scanner-controller.d.ts.map +1 -0
  155. package/dist/types/bluetooth/index.d.ts +14 -0
  156. package/dist/types/bluetooth/index.d.ts.map +1 -0
  157. package/dist/types/bluetooth/models/connection.d.ts +37 -0
  158. package/dist/types/bluetooth/models/connection.d.ts.map +1 -0
  159. package/dist/types/bluetooth/models/device.d.ts +25 -0
  160. package/dist/types/bluetooth/models/device.d.ts.map +1 -0
  161. package/dist/types/bluetooth/models/environment.d.ts +45 -0
  162. package/dist/types/bluetooth/models/environment.d.ts.map +1 -0
  163. package/dist/types/errors.d.ts +113 -0
  164. package/dist/types/errors.d.ts.map +1 -0
  165. package/dist/types/index.d.ts +55 -0
  166. package/dist/types/index.d.ts.map +1 -0
  167. package/dist/types/react/hooks.d.ts +130 -0
  168. package/dist/types/react/hooks.d.ts.map +1 -0
  169. package/dist/types/react/index.d.ts +12 -0
  170. package/dist/types/react/index.d.ts.map +1 -0
  171. package/dist/types/sdk/index.d.ts +11 -0
  172. package/dist/types/sdk/index.d.ts.map +1 -0
  173. package/dist/types/sdk/types.d.ts +104 -0
  174. package/dist/types/sdk/types.d.ts.map +1 -0
  175. package/dist/types/sdk/voltra-client.d.ts +221 -0
  176. package/dist/types/sdk/voltra-client.d.ts.map +1 -0
  177. package/dist/types/sdk/voltra-manager.d.ts +226 -0
  178. package/dist/types/sdk/voltra-manager.d.ts.map +1 -0
  179. package/dist/types/shared/index.d.ts +5 -0
  180. package/dist/types/shared/index.d.ts.map +1 -0
  181. package/dist/types/shared/utils.d.ts +25 -0
  182. package/dist/types/shared/utils.d.ts.map +1 -0
  183. package/dist/types/voltra/index.d.ts +13 -0
  184. package/dist/types/voltra/index.d.ts.map +1 -0
  185. package/dist/types/voltra/models/connection.d.ts +37 -0
  186. package/dist/types/voltra/models/connection.d.ts.map +1 -0
  187. package/dist/types/voltra/models/device-filter.d.ts +19 -0
  188. package/dist/types/voltra/models/device-filter.d.ts.map +1 -0
  189. package/dist/types/voltra/models/device.d.ts +105 -0
  190. package/dist/types/voltra/models/device.d.ts.map +1 -0
  191. package/dist/types/voltra/models/telemetry/frame.d.ts +41 -0
  192. package/dist/types/voltra/models/telemetry/frame.d.ts.map +1 -0
  193. package/dist/types/voltra/models/telemetry/index.d.ts +8 -0
  194. package/dist/types/voltra/models/telemetry/index.d.ts.map +1 -0
  195. package/dist/types/voltra/protocol/commands.d.ts +99 -0
  196. package/dist/types/voltra/protocol/commands.d.ts.map +1 -0
  197. package/dist/types/voltra/protocol/constants.d.ts +103 -0
  198. package/dist/types/voltra/protocol/constants.d.ts.map +1 -0
  199. package/dist/types/voltra/protocol/index.d.ts +9 -0
  200. package/dist/types/voltra/protocol/index.d.ts.map +1 -0
  201. package/dist/types/voltra/protocol/telemetry-decoder.d.ts +45 -0
  202. package/dist/types/voltra/protocol/telemetry-decoder.d.ts.map +1 -0
  203. package/package.json +111 -0
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /**
3
+ * NodeBLEAdapter
4
+ *
5
+ * BLE adapter for Node.js using the webbluetooth npm package.
6
+ * Implements the same W3C Web Bluetooth API for server-side BLE.
7
+ *
8
+ * Requirements:
9
+ * - Node.js environment
10
+ * - webbluetooth npm package
11
+ * - Platform-specific Bluetooth support (macOS, Linux, Windows)
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || (function () {
30
+ var ownKeys = function(o) {
31
+ ownKeys = Object.getOwnPropertyNames || function (o) {
32
+ var ar = [];
33
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
+ return ar;
35
+ };
36
+ return ownKeys(o);
37
+ };
38
+ return function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ })();
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.NodeBLEAdapter = void 0;
48
+ const web_bluetooth_base_1 = require("./web-bluetooth-base");
49
+ // Dynamic import for webbluetooth to avoid bundling issues in non-Node environments
50
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
+ let BluetoothClass = null;
52
+ /**
53
+ * BLE adapter for Node.js environments using webbluetooth package.
54
+ *
55
+ * Device selection flow:
56
+ * 1. Call scan() - starts BLE scan
57
+ * 2. Devices are discovered via deviceFound callback
58
+ * 3. deviceChooser function selects a device (or first match by default)
59
+ * 4. Call connect() to establish GATT connection
60
+ */
61
+ class NodeBLEAdapter extends web_bluetooth_base_1.WebBluetoothBase {
62
+ constructor(config) {
63
+ super(config);
64
+ /** Device selected during scan, stored for connect() */
65
+ this.selectedDevice = null;
66
+ /** List of discovered devices during current scan */
67
+ this.discoveredDevices = [];
68
+ this.deviceChooser = config.deviceChooser ?? null;
69
+ }
70
+ /**
71
+ * Set the device chooser function.
72
+ * Called during scan to programmatically select a device.
73
+ *
74
+ * @param chooser Function that receives discovered devices and returns the chosen one
75
+ */
76
+ setDeviceChooser(chooser) {
77
+ this.deviceChooser = chooser;
78
+ }
79
+ /**
80
+ * Ensure webbluetooth is loaded (lazy load to avoid bundler issues).
81
+ */
82
+ async ensureBluetoothLoaded() {
83
+ if (!BluetoothClass) {
84
+ try {
85
+ // Dynamic import for Node.js - get the Bluetooth class constructor
86
+ const webbluetooth = await Promise.resolve().then(() => __importStar(require('webbluetooth')));
87
+ BluetoothClass = webbluetooth.Bluetooth;
88
+ }
89
+ catch {
90
+ throw new Error('webbluetooth package not found. Install with: npm install webbluetooth');
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Scan for devices programmatically.
96
+ *
97
+ * In Node.js, there's no browser picker. Devices are discovered via
98
+ * the deviceFound callback, and the deviceChooser function selects one.
99
+ *
100
+ * IMPORTANT: The webbluetooth package requires creating a new Bluetooth
101
+ * instance with deviceFound in the constructor for the callback to work
102
+ * reliably. Using the default singleton doesn't call the callback consistently.
103
+ *
104
+ * @param timeout Scan timeout in seconds
105
+ * @returns Array of discovered devices (selection happens via deviceChooser)
106
+ */
107
+ async scan(timeout) {
108
+ await this.ensureBluetoothLoaded();
109
+ this.discoveredDevices = [];
110
+ this.selectedDevice = null;
111
+ return new Promise((resolve, reject) => {
112
+ const timeoutId = setTimeout(() => {
113
+ // Timeout - return discovered devices
114
+ console.log(`[NodeBLE] Scan timeout. Found ${this.discoveredDevices.length} device(s)`);
115
+ resolve(this.discoveredDevices);
116
+ }, timeout * 1000);
117
+ // Create a new Bluetooth instance with deviceFound in constructor
118
+ // This is required for the callback to fire reliably in webbluetooth
119
+ const bluetooth = new BluetoothClass({
120
+ deviceFound: (device, selectFn) => {
121
+ // Apply name prefix filter manually (more reliable than built-in filter)
122
+ if (this.config.deviceNamePrefix &&
123
+ !device.name?.startsWith(this.config.deviceNamePrefix)) {
124
+ // Device doesn't match prefix, skip it
125
+ return false;
126
+ }
127
+ const discoveredDevice = {
128
+ id: device.id,
129
+ name: device.name ?? 'Unknown Device',
130
+ rssi: null,
131
+ };
132
+ // Add to discovered list
133
+ if (!this.discoveredDevices.find((d) => d.id === device.id)) {
134
+ this.discoveredDevices.push(discoveredDevice);
135
+ console.log(`[NodeBLE] Found device: ${device.name}`);
136
+ }
137
+ // Check if we should select this device
138
+ let shouldSelect = false;
139
+ if (this.deviceChooser) {
140
+ // Use custom chooser
141
+ const chosen = this.deviceChooser(this.discoveredDevices);
142
+ shouldSelect = chosen?.id === device.id;
143
+ }
144
+ else {
145
+ // Default: select first matching device
146
+ shouldSelect = true;
147
+ }
148
+ if (shouldSelect) {
149
+ console.log(`[NodeBLE] Selected device: ${device.name}`);
150
+ this.selectedDevice = device;
151
+ clearTimeout(timeoutId);
152
+ selectFn();
153
+ return true;
154
+ }
155
+ return false;
156
+ },
157
+ });
158
+ bluetooth
159
+ .requestDevice({
160
+ // Always use acceptAllDevices - we filter manually in deviceFound
161
+ // The built-in namePrefix filter doesn't work reliably
162
+ acceptAllDevices: true,
163
+ optionalServices: [this.config.serviceUUID],
164
+ })
165
+ .then((device) => {
166
+ // Device was selected
167
+ this.selectedDevice = device;
168
+ resolve(this.discoveredDevices);
169
+ })
170
+ .catch((error) => {
171
+ clearTimeout(timeoutId);
172
+ if (error.name === 'NotFoundError') {
173
+ // No device selected
174
+ console.log('[NodeBLE] No device selected');
175
+ resolve(this.discoveredDevices);
176
+ }
177
+ else {
178
+ reject(error);
179
+ }
180
+ });
181
+ });
182
+ }
183
+ /**
184
+ * Connect to the selected device.
185
+ *
186
+ * @param deviceId Device ID (should match the selected device)
187
+ * @param options Connection options
188
+ */
189
+ async connect(deviceId, options) {
190
+ // Verify we have the device from scan()
191
+ if (!this.selectedDevice) {
192
+ throw new Error('No device selected. Call scan() first.');
193
+ }
194
+ if (this.selectedDevice.id !== deviceId) {
195
+ console.warn(`[NodeBLE] Device ID mismatch: expected ${this.selectedDevice.id}, got ${deviceId}`);
196
+ }
197
+ // Connect to GATT server
198
+ await this.connectToDevice(this.selectedDevice);
199
+ // Handle immediate write if provided (for authentication)
200
+ if (options?.immediateWrite) {
201
+ console.log('[NodeBLE] Sending immediate auth write...');
202
+ await this.write(options.immediateWrite);
203
+ console.log('[NodeBLE] Immediate auth write sent');
204
+ }
205
+ }
206
+ /**
207
+ * Override disconnect to also clear selected device.
208
+ */
209
+ async disconnect() {
210
+ await super.disconnect();
211
+ this.selectedDevice = null;
212
+ this.discoveredDevices = [];
213
+ }
214
+ /**
215
+ * Get the list of devices discovered during the last scan.
216
+ */
217
+ getDiscoveredDevices() {
218
+ return [...this.discoveredDevices];
219
+ }
220
+ /**
221
+ * Check if running in a Node.js environment.
222
+ */
223
+ static isNodeEnvironment() {
224
+ return (typeof process !== 'undefined' && process.versions != null && process.versions.node != null);
225
+ }
226
+ }
227
+ exports.NodeBLEAdapter = NodeBLEAdapter;
228
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * BLE Abstraction Layer Types
4
+ *
5
+ * Defines interfaces for BLE operations implemented by platform-specific adapters:
6
+ * - Native (iOS/Android): react-native-ble-plx
7
+ * - Browser: Web Bluetooth API
8
+ * - Node.js: webbluetooth npm package
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/types.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG"}
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ /**
3
+ * WebBluetoothBase
4
+ *
5
+ * Abstract base class for W3C Web Bluetooth API adapters.
6
+ * Provides shared GATT operations for both browser and Node.js environments.
7
+ *
8
+ * Subclasses:
9
+ * - WebBLEAdapter: Browser using navigator.bluetooth
10
+ * - NodeBLEAdapter: Node.js using webbluetooth npm package
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.WebBluetoothBase = void 0;
14
+ const base_1 = require("./base");
15
+ /**
16
+ * Abstract base class for Web Bluetooth adapters.
17
+ *
18
+ * Implements shared GATT operations:
19
+ * - Service/characteristic discovery
20
+ * - Write operations
21
+ * - Notification subscription
22
+ * - Disconnect cleanup
23
+ *
24
+ * Subclasses implement platform-specific device selection (scan/connect).
25
+ */
26
+ class WebBluetoothBase extends base_1.BaseBLEAdapter {
27
+ constructor(config) {
28
+ super();
29
+ /** Connected Bluetooth device */
30
+ this.device = null;
31
+ /** GATT server connection */
32
+ this.server = null;
33
+ /** Write characteristic */
34
+ this.writeChar = null;
35
+ /** Notify characteristic */
36
+ this.notifyChar = null;
37
+ /** Bound notification handler for cleanup */
38
+ this.boundNotificationHandler = null;
39
+ // Web Bluetooth API requires lowercase UUIDs
40
+ this.config = {
41
+ ...config.ble,
42
+ serviceUUID: config.ble.serviceUUID.toLowerCase(),
43
+ writeCharUUID: config.ble.writeCharUUID.toLowerCase(),
44
+ notifyCharUUID: config.ble.notifyCharUUID.toLowerCase(),
45
+ };
46
+ }
47
+ // ===========================================================================
48
+ // Shared GATT operations
49
+ // ===========================================================================
50
+ /**
51
+ * Connect to a Bluetooth device's GATT server and set up characteristics.
52
+ * Called by subclasses after device selection.
53
+ */
54
+ async connectToDevice(device) {
55
+ this.device = device;
56
+ // Set up disconnect listener
57
+ device.addEventListener('gattserverdisconnected', () => {
58
+ console.log('[WebBluetooth] Device disconnected');
59
+ this.handleDisconnect();
60
+ });
61
+ // Connect to GATT server
62
+ if (!device.gatt) {
63
+ throw new Error('Device does not support GATT');
64
+ }
65
+ this.setConnectionState('connecting');
66
+ try {
67
+ this.server = await device.gatt.connect();
68
+ await this.setupCharacteristics();
69
+ this.setConnectionState('connected');
70
+ }
71
+ catch (error) {
72
+ console.error('[WebBluetooth] Connect error:', error);
73
+ this.setConnectionState('disconnected');
74
+ throw error;
75
+ }
76
+ }
77
+ /**
78
+ * Discover service and characteristics, set up notifications.
79
+ */
80
+ async setupCharacteristics() {
81
+ if (!this.server) {
82
+ throw new Error('Not connected to GATT server');
83
+ }
84
+ // Get the primary service
85
+ const service = await this.server.getPrimaryService(this.config.serviceUUID);
86
+ // Get write characteristic
87
+ this.writeChar = await service.getCharacteristic(this.config.writeCharUUID);
88
+ // Get notify characteristic and start notifications
89
+ this.notifyChar = await service.getCharacteristic(this.config.notifyCharUUID);
90
+ // Set up notification handler
91
+ this.boundNotificationHandler = this.handleNotification.bind(this);
92
+ this.notifyChar.addEventListener('characteristicvaluechanged', this.boundNotificationHandler);
93
+ await this.notifyChar.startNotifications();
94
+ // Also listen for notifications on write characteristic if it supports it
95
+ if (this.writeChar.properties.notify) {
96
+ this.writeChar.addEventListener('characteristicvaluechanged', this.boundNotificationHandler);
97
+ await this.writeChar.startNotifications();
98
+ }
99
+ console.log('[WebBluetooth] Characteristics set up');
100
+ }
101
+ /**
102
+ * Handle incoming notification data.
103
+ */
104
+ handleNotification(event) {
105
+ const characteristic = event.target;
106
+ if (characteristic.value) {
107
+ const data = new Uint8Array(characteristic.value.buffer);
108
+ this.emitNotification(data);
109
+ }
110
+ }
111
+ /**
112
+ * Handle device disconnection.
113
+ */
114
+ handleDisconnect() {
115
+ this.cleanup();
116
+ this.setConnectionState('disconnected');
117
+ }
118
+ /**
119
+ * Clean up resources.
120
+ */
121
+ cleanup() {
122
+ // Remove notification listeners
123
+ if (this.notifyChar && this.boundNotificationHandler) {
124
+ try {
125
+ this.notifyChar.removeEventListener('characteristicvaluechanged', this.boundNotificationHandler);
126
+ }
127
+ catch {
128
+ // Ignore errors during cleanup
129
+ }
130
+ }
131
+ if (this.writeChar && this.boundNotificationHandler) {
132
+ try {
133
+ this.writeChar.removeEventListener('characteristicvaluechanged', this.boundNotificationHandler);
134
+ }
135
+ catch {
136
+ // Ignore errors during cleanup
137
+ }
138
+ }
139
+ this.boundNotificationHandler = null;
140
+ this.writeChar = null;
141
+ this.notifyChar = null;
142
+ this.server = null;
143
+ this.device = null;
144
+ }
145
+ // ===========================================================================
146
+ // BLEAdapter interface - implemented
147
+ // ===========================================================================
148
+ /**
149
+ * Disconnect from the device.
150
+ */
151
+ async disconnect() {
152
+ this.setConnectionState('disconnecting');
153
+ if (this.device?.gatt?.connected) {
154
+ this.device.gatt.disconnect();
155
+ }
156
+ this.cleanup();
157
+ this.setConnectionState('disconnected');
158
+ }
159
+ /**
160
+ * Write data to the device.
161
+ */
162
+ async write(data) {
163
+ if (!this.writeChar) {
164
+ throw new Error('Not connected to device');
165
+ }
166
+ // Use ArrayBuffer.slice to ensure we have a proper ArrayBuffer
167
+ const buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
168
+ await this.writeChar.writeValueWithResponse(buffer);
169
+ }
170
+ // ===========================================================================
171
+ // Extended methods
172
+ // ===========================================================================
173
+ /**
174
+ * Get info about the currently connected device.
175
+ */
176
+ getConnectedDevice() {
177
+ if (!this.device)
178
+ return null;
179
+ return {
180
+ id: this.device.id,
181
+ name: this.device.name ?? 'Unknown',
182
+ rssi: null, // Not available via Web Bluetooth after connection
183
+ };
184
+ }
185
+ }
186
+ exports.WebBluetoothBase = WebBluetoothBase;
187
+ //# sourceMappingURL=web-bluetooth-base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-bluetooth-base.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/web-bluetooth-base.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * WebBLEAdapter
4
+ *
5
+ * BLE adapter for web browsers using the native Web Bluetooth API.
6
+ * Uses the browser's built-in device picker for device selection.
7
+ *
8
+ * Requirements:
9
+ * - Chrome, Edge, or Opera browser (Safari/Firefox don't support Web Bluetooth)
10
+ * - HTTPS or localhost
11
+ * - User gesture required to trigger device picker
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.WebBLEAdapter = void 0;
15
+ const web_bluetooth_base_1 = require("./web-bluetooth-base");
16
+ /**
17
+ * BLE adapter using the browser's native Web Bluetooth API.
18
+ *
19
+ * Device selection flow:
20
+ * 1. Call scan() - triggers browser's device picker
21
+ * 2. User selects device from browser UI
22
+ * 3. scan() returns with the selected device
23
+ * 4. Call connect() to establish GATT connection
24
+ */
25
+ class WebBLEAdapter extends web_bluetooth_base_1.WebBluetoothBase {
26
+ constructor(config) {
27
+ super(config);
28
+ /** Device selected from browser picker, stored for connect() */
29
+ this.selectedDevice = null;
30
+ }
31
+ /**
32
+ * Scan for devices using the browser's device picker.
33
+ *
34
+ * Note: This triggers the browser's native Bluetooth device picker UI.
35
+ * The user must select a device from the picker. Returns when user
36
+ * selects a device or cancels.
37
+ *
38
+ * @param _timeout Ignored - browser controls the picker timeout
39
+ * @returns Array with single selected device, or empty if cancelled
40
+ */
41
+ async scan(_timeout) {
42
+ try {
43
+ // Request device from browser - this shows the native picker
44
+ const device = await navigator.bluetooth.requestDevice({
45
+ filters: this.config.deviceNamePrefix
46
+ ? [{ namePrefix: this.config.deviceNamePrefix }]
47
+ : undefined,
48
+ acceptAllDevices: !this.config.deviceNamePrefix,
49
+ optionalServices: [this.config.serviceUUID],
50
+ });
51
+ // Store for connect()
52
+ this.selectedDevice = device;
53
+ console.log(`[WebBLE] Device selected: ${device.name}`);
54
+ return [
55
+ {
56
+ id: device.id,
57
+ name: device.name ?? 'Unknown Device',
58
+ rssi: null, // Not available from requestDevice
59
+ },
60
+ ];
61
+ }
62
+ catch (error) {
63
+ // User cancelled or error occurred
64
+ if (error.name === 'NotFoundError') {
65
+ console.log('[WebBLE] User cancelled device selection');
66
+ return [];
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ /**
72
+ * Connect to the selected device.
73
+ *
74
+ * Note: In Web Bluetooth, the device is already "selected" during scan().
75
+ * This method establishes the GATT connection.
76
+ *
77
+ * @param deviceId Device ID (should match the selected device)
78
+ * @param options Connection options
79
+ */
80
+ async connect(deviceId, options) {
81
+ // Verify we have the device from scan()
82
+ if (!this.selectedDevice) {
83
+ throw new Error('No device selected. Call scan() first.');
84
+ }
85
+ if (this.selectedDevice.id !== deviceId) {
86
+ console.warn(`[WebBLE] Device ID mismatch: expected ${this.selectedDevice.id}, got ${deviceId}`);
87
+ }
88
+ // Connect to GATT server
89
+ await this.connectToDevice(this.selectedDevice);
90
+ // Handle immediate write if provided (for authentication)
91
+ if (options?.immediateWrite) {
92
+ console.log('[WebBLE] Sending immediate auth write...');
93
+ await this.write(options.immediateWrite);
94
+ console.log('[WebBLE] Immediate auth write sent');
95
+ }
96
+ }
97
+ /**
98
+ * Override disconnect to also clear selected device.
99
+ */
100
+ async disconnect() {
101
+ await super.disconnect();
102
+ this.selectedDevice = null;
103
+ }
104
+ /**
105
+ * Check if Web Bluetooth is supported in this browser.
106
+ */
107
+ static isSupported() {
108
+ return typeof navigator !== 'undefined' && 'bluetooth' in navigator;
109
+ }
110
+ }
111
+ exports.WebBLEAdapter = WebBLEAdapter;
112
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/web.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,6DAAiF;AAGjF;;;;;;;;GAQG;AACH,MAAa,aAAc,SAAQ,qCAAgB;IAIjD,YAAY,MAA0B;QACpC,KAAK,CAAC,MAAM,CAAC,CAAC;QAJhB,gEAAgE;QACxD,mBAAc,GAA2B,IAAI,CAAC;IAItD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,IAAI,CAAC,QAAgB;QACzB,IAAI,CAAC;YACH,6DAA6D;YAC7D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,aAAa,CAAC;gBACrD,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB;oBACnC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;oBAChD,CAAC,CAAC,SAAS;gBACb,gBAAgB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB;gBAC/C,gBAAgB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;aAC5C,CAAC,CAAC;YAEH,sBAAsB;YACtB,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;YAE7B,OAAO,CAAC,GAAG,CAAC,6BAA6B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAExD,OAAO;gBACL;oBACE,EAAE,EAAE,MAAM,CAAC,EAAE;oBACb,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,gBAAgB;oBACrC,IAAI,EAAE,IAAI,EAAE,mCAAmC;iBAChD;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mCAAmC;YACnC,IAAK,KAAe,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;gBACxD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,OAAwB;QACtD,wCAAwC;QACxC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,IAAI,CAAC,cAAc,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CACV,yCAAyC,IAAI,CAAC,cAAc,CAAC,EAAE,SAAS,QAAQ,EAAE,CACnF,CAAC;QACJ,CAAC;QAED,yBAAyB;QACzB,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAEhD,0DAA0D;QAC1D,IAAI,OAAO,EAAE,cAAc,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YACxD,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED;;OAEG;IACM,KAAK,CAAC,UAAU;QACvB,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,OAAO,OAAO,SAAS,KAAK,WAAW,IAAI,WAAW,IAAI,SAAS,CAAC;IACtE,CAAC;CACF;AAjGD,sCAiGC"}