@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Voltra
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,272 @@
1
+ # @voltras/node-sdk
2
+
3
+ SDK for connecting to and controlling Voltra fitness devices.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@voltras/node-sdk.svg)](https://www.npmjs.com/package/@voltras/node-sdk)
6
+ [![CI](https://github.com/voltra/node-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/voltra/node-sdk/actions/workflows/ci.yml)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ ## Features
10
+
11
+ - **Simple API**: `VoltraManager` handles discovery, returns `VoltraClient` for device control
12
+ - **Cross-platform**: Web browsers, Node.js, and React Native
13
+ - **Multi-device**: Connect to multiple devices simultaneously
14
+ - **React hooks**: Clean `useVoltraScanner` and `useVoltraDevice` hooks
15
+ - **TypeScript**: Full type definitions included
16
+ - **Real-time telemetry**: Stream position, velocity, and force data
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @voltras/node-sdk
22
+ ```
23
+
24
+ ### Platform dependencies
25
+
26
+ | Platform | Additional Install |
27
+ |----------|-------------------|
28
+ | React Native | `npm install react-native-ble-plx` |
29
+ | Node.js | `npm install webbluetooth` |
30
+ | Web browsers | None (uses Web Bluetooth API) |
31
+
32
+ ## Quick Start
33
+
34
+ ### Web / Node.js
35
+
36
+ ```typescript
37
+ import { VoltraManager } from '@voltras/node-sdk';
38
+
39
+ // Create manager (auto-detects platform)
40
+ const manager = new VoltraManager();
41
+
42
+ // Scan and connect to first device
43
+ const client = await manager.connectFirst();
44
+
45
+ // Or connect by name
46
+ const client = await manager.connectByName('VTR-123456');
47
+
48
+ // Control the device
49
+ await client.setWeight(50);
50
+
51
+ client.onFrame((frame) => {
52
+ console.log('Position:', frame.position, 'Velocity:', frame.velocity);
53
+ });
54
+
55
+ await client.startRecording();
56
+ // ... workout ...
57
+ await client.stopRecording();
58
+
59
+ // Cleanup
60
+ manager.dispose();
61
+ ```
62
+
63
+ ### React Native
64
+
65
+ ```typescript
66
+ import { VoltraManager } from '@voltras/node-sdk';
67
+
68
+ // Specify native platform
69
+ const manager = VoltraManager.forNative();
70
+ // or: new VoltraManager({ platform: 'native' })
71
+
72
+ // Rest of the API is identical
73
+ const client = await manager.connectFirst();
74
+ ```
75
+
76
+ ### React Hooks
77
+
78
+ ```tsx
79
+ import { VoltraManager } from '@voltras/node-sdk';
80
+ import { useVoltraScanner, useVoltraDevice } from '@voltras/node-sdk/react';
81
+
82
+ function WorkoutScreen() {
83
+ const manager = useMemo(() => VoltraManager.forNative(), []);
84
+ const [client, setClient] = useState<VoltraClient | null>(null);
85
+
86
+ // Scanner state
87
+ const { devices, isScanning, scan } = useVoltraScanner(manager);
88
+
89
+ // Device state
90
+ const { connectionState, currentFrame, isRecording } = useVoltraDevice(client);
91
+
92
+ const handleConnect = async (device: DiscoveredDevice) => {
93
+ const connected = await manager.connect(device);
94
+ setClient(connected);
95
+ };
96
+
97
+ return (
98
+ <View>
99
+ <Button onPress={() => scan()}>
100
+ {isScanning ? 'Scanning...' : 'Scan'}
101
+ </Button>
102
+
103
+ {devices.map((device) => (
104
+ <Button key={device.id} onPress={() => handleConnect(device)}>
105
+ {device.name}
106
+ </Button>
107
+ ))}
108
+
109
+ {connectionState === 'connected' && (
110
+ <Text>Position: {currentFrame?.position}</Text>
111
+ )}
112
+ </View>
113
+ );
114
+ }
115
+ ```
116
+
117
+ ## Multi-Device
118
+
119
+ ```typescript
120
+ const manager = new VoltraManager();
121
+
122
+ // Listen for device events
123
+ manager.onDeviceConnected((client, deviceId, deviceName) => {
124
+ console.log('Connected:', deviceName);
125
+ client.onFrame((frame) => console.log(`[${deviceName}]`, frame.position));
126
+ });
127
+
128
+ // Connect to multiple devices
129
+ const devices = await manager.scan();
130
+ await manager.connect(devices[0]);
131
+ await manager.connect(devices[1]);
132
+
133
+ // Access individual clients
134
+ const client = manager.getClient(devices[0].id);
135
+ await client?.setWeight(50);
136
+
137
+ // Or get all clients
138
+ for (const client of manager.getAllClients()) {
139
+ await client.startRecording();
140
+ }
141
+ ```
142
+
143
+ ## API Reference
144
+
145
+ ### VoltraManager
146
+
147
+ Main entry point for the SDK.
148
+
149
+ ```typescript
150
+ const manager = new VoltraManager(options?);
151
+ // or
152
+ const manager = VoltraManager.forWeb();
153
+ const manager = VoltraManager.forNode();
154
+ const manager = VoltraManager.forNative();
155
+ ```
156
+
157
+ **Methods:**
158
+ - `scan(options?)` - Scan for Voltra devices
159
+ - `connect(device)` - Connect and return a VoltraClient
160
+ - `connectFirst(options?)` - Connect to first available device
161
+ - `connectByName(name, options?)` - Scan + connect by device name
162
+ - `getClient(deviceId)` - Get connected client by ID
163
+ - `getAllClients()` - Get all connected clients
164
+ - `disconnect(deviceId)` - Disconnect specific device
165
+ - `disconnectAll()` - Disconnect all devices
166
+ - `dispose()` - Clean up resources
167
+
168
+ ### VoltraClient
169
+
170
+ Controls a single connected device.
171
+
172
+ **Methods:**
173
+ - `setWeight(lbs)` - Set weight (5-200 in increments of 5)
174
+ - `setChains(lbs)` - Set chains (0-100)
175
+ - `setEccentric(percent)` - Set eccentric adjustment (-195 to +195)
176
+ - `startRecording()` - Start recording
177
+ - `stopRecording()` - Stop recording
178
+ - `onFrame(callback)` - Subscribe to telemetry frames
179
+ - `disconnect()` - Disconnect from device
180
+
181
+ **Properties:**
182
+ - `connectionState` - 'disconnected' | 'connecting' | 'authenticating' | 'connected'
183
+ - `isConnected` - Whether connected
184
+ - `settings` - Current device settings
185
+ - `recordingState` - 'idle' | 'preparing' | 'ready' | 'active' | 'stopping'
186
+ - `isRecording` - Whether recording
187
+
188
+ ### TelemetryFrame
189
+
190
+ ```typescript
191
+ interface TelemetryFrame {
192
+ sequence: number; // Packet sequence number
193
+ timestamp: number; // Unix ms when received
194
+ phase: number; // Movement phase (see MovementPhase)
195
+ position: number; // Position (0-600 raw)
196
+ velocity: number; // Velocity (raw value)
197
+ force: number; // Force (signed value)
198
+ }
199
+ ```
200
+
201
+ ### React Hooks
202
+
203
+ ```typescript
204
+ import { useVoltraScanner, useVoltraDevice } from '@voltras/node-sdk/react';
205
+
206
+ // Scanner state
207
+ const { devices, isScanning, scan, error, clear } = useVoltraScanner(manager);
208
+
209
+ // Device state
210
+ const {
211
+ connectionState,
212
+ isConnected,
213
+ recordingState,
214
+ isRecording,
215
+ currentFrame,
216
+ settings,
217
+ error,
218
+ } = useVoltraDevice(client);
219
+ ```
220
+
221
+ ## Error Handling
222
+
223
+ ```typescript
224
+ import {
225
+ VoltraSDKError,
226
+ ConnectionError,
227
+ AuthenticationError,
228
+ NotConnectedError,
229
+ } from '@voltras/node-sdk';
230
+
231
+ try {
232
+ await manager.connectByName('VTR-123');
233
+ } catch (error) {
234
+ if (error instanceof ConnectionError) {
235
+ console.log('Connection failed:', error.code);
236
+ }
237
+ }
238
+ ```
239
+
240
+ ## Examples
241
+
242
+ See the [examples](./examples) directory:
243
+
244
+ - [Node.js](./examples/node) - CLI examples
245
+ - [Web Browser](./examples/web) - Interactive demo
246
+ - [React Native](./examples/react-native) - Expo app
247
+
248
+ ## Documentation
249
+
250
+ ### Getting Started
251
+
252
+ Step-by-step setup guides for each platform:
253
+
254
+ - [Node.js](./docs/getting-started/node.md) - Prerequisites, setup, running examples
255
+ - [Web Browser](./docs/getting-started/web.md) - Browser requirements, HTTPS, Vite setup
256
+ - [React Native](./docs/getting-started/react-native.md) - Expo, permissions, development builds
257
+
258
+ ### Concepts
259
+
260
+ Technical deep-dives:
261
+
262
+ - [Bluetooth Protocol](./docs/concepts/bluetooth-protocol.md) - Voltra BLE protocol, commands, telemetry format
263
+ - [Platform Adapters](./docs/concepts/platform-adapters.md) - Native vs Web vs Node.js differences
264
+
265
+ ### Other
266
+
267
+ - [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
268
+ - [Roadmap](./docs/roadmap/) - Planned features (ReplayBLEAdapter, etc.)
269
+
270
+ ## License
271
+
272
+ MIT - see [LICENSE](./LICENSE)
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * BaseBLEAdapter
4
+ *
5
+ * Abstract base class for all BLE adapters. Provides shared implementation
6
+ * for connection state management and callback registration/notification.
7
+ *
8
+ * Subclasses implement the platform-specific BLE operations:
9
+ * - NativeBLEAdapter: react-native-ble-plx for iOS/Android
10
+ * - WebBLEAdapter: Web Bluetooth API for browsers
11
+ * - NodeBLEAdapter: webbluetooth npm for Node.js
12
+ * - ReplayBLEAdapter: Playback for testing/demos
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BaseBLEAdapter = void 0;
16
+ /**
17
+ * Abstract base class implementing shared BLE adapter functionality.
18
+ *
19
+ * Provides:
20
+ * - Connection state management with change notifications
21
+ * - Notification callback registration (supports multiple listeners)
22
+ * - State callback registration (supports multiple listeners)
23
+ * - Protected utilities for subclasses to emit events
24
+ */
25
+ class BaseBLEAdapter {
26
+ constructor() {
27
+ /** Current connection state */
28
+ this.connectionState = 'disconnected';
29
+ /** Registered notification callbacks */
30
+ this.notificationCallbacks = [];
31
+ /** Registered connection state callbacks */
32
+ this.stateCallbacks = [];
33
+ }
34
+ // ===========================================================================
35
+ // BLEAdapter interface - implemented
36
+ // ===========================================================================
37
+ /**
38
+ * Get the current connection state.
39
+ */
40
+ getConnectionState() {
41
+ return this.connectionState;
42
+ }
43
+ /**
44
+ * Check if currently connected to a device.
45
+ */
46
+ isConnected() {
47
+ return this.connectionState === 'connected';
48
+ }
49
+ /**
50
+ * Register a callback for notifications from the device.
51
+ * @param callback Function called with notification data
52
+ * @returns Unsubscribe function
53
+ */
54
+ onNotification(callback) {
55
+ this.notificationCallbacks.push(callback);
56
+ return () => {
57
+ const index = this.notificationCallbacks.indexOf(callback);
58
+ if (index >= 0) {
59
+ this.notificationCallbacks.splice(index, 1);
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * Register a callback for connection state changes.
65
+ * @param callback Function called when state changes
66
+ * @returns Unsubscribe function
67
+ */
68
+ onConnectionStateChange(callback) {
69
+ this.stateCallbacks.push(callback);
70
+ return () => {
71
+ const index = this.stateCallbacks.indexOf(callback);
72
+ if (index >= 0) {
73
+ this.stateCallbacks.splice(index, 1);
74
+ }
75
+ };
76
+ }
77
+ // ===========================================================================
78
+ // Protected utilities for subclasses
79
+ // ===========================================================================
80
+ /**
81
+ * Set connection state and notify all registered callbacks.
82
+ * Only notifies if state actually changed.
83
+ *
84
+ * @param state New connection state
85
+ */
86
+ setConnectionState(state) {
87
+ if (this.connectionState !== state) {
88
+ this.connectionState = state;
89
+ for (const callback of this.stateCallbacks) {
90
+ try {
91
+ callback(state);
92
+ }
93
+ catch (e) {
94
+ console.error('[BaseBLEAdapter] State callback error:', e);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ /**
100
+ * Emit notification data to all registered callbacks.
101
+ *
102
+ * @param data Notification data to emit
103
+ */
104
+ emitNotification(data) {
105
+ for (const callback of this.notificationCallbacks) {
106
+ try {
107
+ callback(data);
108
+ }
109
+ catch (e) {
110
+ console.error('[BaseBLEAdapter] Notification callback error:', e);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ exports.BaseBLEAdapter = BaseBLEAdapter;
116
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/base.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAWH;;;;;;;;GAQG;AACH,MAAsB,cAAc;IAApC;QACE,+BAA+B;QACrB,oBAAe,GAAoB,cAAc,CAAC;QAE5D,wCAAwC;QAC9B,0BAAqB,GAA2B,EAAE,CAAC;QAE7D,4CAA4C;QAClC,mBAAc,GAA8B,EAAE,CAAC;IAoH3D,CAAC;IAlHC,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAE9E;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,eAAe,KAAK,WAAW,CAAC;IAC9C,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,QAA8B;QAC3C,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,OAAO,GAAG,EAAE;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC3D,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACf,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,uBAAuB,CAAC,QAAiC;QACvD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,OAAO,GAAG,EAAE;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACpD,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;gBACf,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CAAC;IACJ,CAAC;IA+BD,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAE9E;;;;;OAKG;IACO,kBAAkB,CAAC,KAAsB;QACjD,IAAI,IAAI,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;YACnC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3C,IAAI,CAAC;oBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAClB,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,CAAC,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACO,gBAAgB,CAAC,IAAgB;QACzC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA5HD,wCA4HC"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ /**
3
+ * BLE Abstraction Layer
4
+ *
5
+ * Provides a unified interface for BLE communication across platforms:
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
+ exports.NativeBLEAdapter = exports.NodeBLEAdapter = exports.WebBLEAdapter = void 0;
12
+ exports.createBLEAdapter = createBLEAdapter;
13
+ // Platform adapters
14
+ var web_1 = require("./web");
15
+ Object.defineProperty(exports, "WebBLEAdapter", { enumerable: true, get: function () { return web_1.WebBLEAdapter; } });
16
+ var node_1 = require("./node");
17
+ Object.defineProperty(exports, "NodeBLEAdapter", { enumerable: true, get: function () { return node_1.NodeBLEAdapter; } });
18
+ var native_1 = require("./native");
19
+ Object.defineProperty(exports, "NativeBLEAdapter", { enumerable: true, get: function () { return native_1.NativeBLEAdapter; } });
20
+ const web_2 = require("./web");
21
+ const node_2 = require("./node");
22
+ /**
23
+ * Detect if running in Node.js environment.
24
+ */
25
+ function isNodeEnvironment() {
26
+ return (typeof process !== 'undefined' && process.versions != null && process.versions.node != null);
27
+ }
28
+ /**
29
+ * Detect if running in browser environment.
30
+ */
31
+ function isBrowserEnvironment() {
32
+ return (typeof window !== 'undefined' &&
33
+ typeof document !== 'undefined' &&
34
+ typeof navigator !== 'undefined');
35
+ }
36
+ /**
37
+ * Create a BLE adapter based on the current environment.
38
+ *
39
+ * Environment detection:
40
+ * - Web browser: WebBLEAdapter (Web Bluetooth API)
41
+ * - Node.js: NodeBLEAdapter (webbluetooth package)
42
+ *
43
+ * NOTE: For React Native, import and instantiate NativeBLEAdapter directly.
44
+ * This factory is for web/Node.js environments only.
45
+ *
46
+ * @param config Adapter configuration including BLE service UUIDs
47
+ * @returns BLEAdapter instance appropriate for the current environment
48
+ */
49
+ function createBLEAdapter(config) {
50
+ if (isNodeEnvironment() && !isBrowserEnvironment()) {
51
+ return new node_2.NodeBLEAdapter({ ble: config.ble });
52
+ }
53
+ if (isBrowserEnvironment()) {
54
+ return new web_2.WebBLEAdapter({ ble: config.ble });
55
+ }
56
+ throw new Error('Unknown environment. For React Native, import NativeBLEAdapter directly from @voltras/node-sdk/react-native');
57
+ }
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/bluetooth/adapters/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAkEH,4CAYC;AAjED,oBAAoB;AACpB,6BAAsC;AAA7B,oGAAA,aAAa,OAAA;AACtB,+BAAgF;AAAvE,sGAAA,cAAc,OAAA;AACvB,mCAAsE;AAA7D,0GAAA,gBAAgB,OAAA;AAMzB,+BAAsC;AACtC,iCAAwC;AAUxC;;GAEG;AACH,SAAS,iBAAiB;IACxB,OAAO,CACL,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAC5F,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB;IAC3B,OAAO,CACL,OAAO,MAAM,KAAK,WAAW;QAC7B,OAAO,QAAQ,KAAK,WAAW;QAC/B,OAAO,SAAS,KAAK,WAAW,CACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,gBAAgB,CAAC,MAA8B;IAC7D,IAAI,iBAAiB,EAAE,IAAI,CAAC,oBAAoB,EAAE,EAAE,CAAC;QACnD,OAAO,IAAI,qBAAc,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC3B,OAAO,IAAI,mBAAa,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,KAAK,CACb,6GAA6G,CAC9G,CAAC;AACJ,CAAC"}