@bota.dev/react-native-app-sdk 2.0.0-beta.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 (173) hide show
  1. package/BotaDeviceSDK.podspec +55 -0
  2. package/LICENSE +21 -0
  3. package/README.md +101 -0
  4. package/android/build.gradle +76 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidDevices.kt +172 -0
  7. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidLifecycle.kt +100 -0
  8. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidLogs.kt +82 -0
  9. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidModels.kt +476 -0
  10. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidOTA.kt +58 -0
  11. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidRecordingUploads.kt +180 -0
  12. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidRecordings.kt +751 -0
  13. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidSecurity.kt +509 -0
  14. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidWiFi.kt +125 -0
  15. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKEncryptedUploadV2Materials.kt +46 -0
  16. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKModule.kt +723 -0
  17. package/android/src/main/java/dev/bota/sdk/reactnative/BotaDeviceSDKPackage.kt +33 -0
  18. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidDevicesTest.kt +211 -0
  19. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidLifecycleTest.kt +132 -0
  20. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidLogsTest.kt +57 -0
  21. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidOTATest.kt +75 -0
  22. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidRecordingUploadsTest.kt +147 -0
  23. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidRecordingsTest.kt +355 -0
  24. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidSecurityTest.kt +523 -0
  25. package/android/src/test/java/dev/bota/sdk/reactnative/BotaDeviceSDKAndroidWiFiTest.kt +100 -0
  26. package/generated/codegen-contract.json +3593 -0
  27. package/ios/BotaDeviceSDK.mm +1300 -0
  28. package/ios/BotaDeviceSDKAppleBridge.swift +2260 -0
  29. package/ios/BotaDeviceSDKAppleDevices.swift +191 -0
  30. package/ios/BotaDeviceSDKAppleLifecycle.swift +167 -0
  31. package/ios/BotaDeviceSDKAppleLogs.swift +79 -0
  32. package/ios/BotaDeviceSDKAppleOTA.swift +73 -0
  33. package/ios/BotaDeviceSDKAppleRecordingUploads.swift +178 -0
  34. package/ios/BotaDeviceSDKAppleRecordings.swift +670 -0
  35. package/ios/BotaDeviceSDKAppleSecurity.swift +586 -0
  36. package/ios/BotaDeviceSDKAppleWiFi.swift +128 -0
  37. package/ios/BotaDeviceSDKEncryptedUploadV2Materials.swift +99 -0
  38. package/lib/commonjs/BotaClient.js +194 -0
  39. package/lib/commonjs/BotaClient.js.map +1 -0
  40. package/lib/commonjs/ble/constants.js +10 -0
  41. package/lib/commonjs/ble/constants.js.map +1 -0
  42. package/lib/commonjs/ble/deviceLogs.js +50 -0
  43. package/lib/commonjs/ble/deviceLogs.js.map +1 -0
  44. package/lib/commonjs/cache/DeviceStateCache.js +6 -0
  45. package/lib/commonjs/cache/DeviceStateCache.js.map +1 -0
  46. package/lib/commonjs/client.js +746 -0
  47. package/lib/commonjs/client.js.map +1 -0
  48. package/lib/commonjs/compatibility/runtime.js +44 -0
  49. package/lib/commonjs/compatibility/runtime.js.map +1 -0
  50. package/lib/commonjs/index.js +123 -0
  51. package/lib/commonjs/index.js.map +1 -0
  52. package/lib/commonjs/managers/DeviceManager.js +647 -0
  53. package/lib/commonjs/managers/DeviceManager.js.map +1 -0
  54. package/lib/commonjs/managers/OTAManager.js +140 -0
  55. package/lib/commonjs/managers/OTAManager.js.map +1 -0
  56. package/lib/commonjs/managers/RecordingManager.js +444 -0
  57. package/lib/commonjs/managers/RecordingManager.js.map +1 -0
  58. package/lib/commonjs/managers/StreamingSession.js +175 -0
  59. package/lib/commonjs/managers/StreamingSession.js.map +1 -0
  60. package/lib/commonjs/managers/types.js +6 -0
  61. package/lib/commonjs/managers/types.js.map +1 -0
  62. package/lib/commonjs/models/Device.js +2 -0
  63. package/lib/commonjs/models/Device.js.map +1 -0
  64. package/lib/commonjs/models/Recording.js +2 -0
  65. package/lib/commonjs/models/Recording.js.map +1 -0
  66. package/lib/commonjs/models/Status.js +6 -0
  67. package/lib/commonjs/models/Status.js.map +1 -0
  68. package/lib/commonjs/package.json +1 -0
  69. package/lib/commonjs/specs/NativeBotaDeviceSDK.js +9 -0
  70. package/lib/commonjs/specs/NativeBotaDeviceSDK.js.map +1 -0
  71. package/lib/commonjs/sync/syncStatus.js +178 -0
  72. package/lib/commonjs/sync/syncStatus.js.map +1 -0
  73. package/lib/commonjs/utils/errors.js +194 -0
  74. package/lib/commonjs/utils/errors.js.map +1 -0
  75. package/lib/commonjs/utils/logger.js +84 -0
  76. package/lib/commonjs/utils/logger.js.map +1 -0
  77. package/lib/module/BotaClient.js +189 -0
  78. package/lib/module/BotaClient.js.map +1 -0
  79. package/lib/module/ble/constants.js +6 -0
  80. package/lib/module/ble/constants.js.map +1 -0
  81. package/lib/module/ble/deviceLogs.js +45 -0
  82. package/lib/module/ble/deviceLogs.js.map +1 -0
  83. package/lib/module/cache/DeviceStateCache.js +4 -0
  84. package/lib/module/cache/DeviceStateCache.js.map +1 -0
  85. package/lib/module/client.js +740 -0
  86. package/lib/module/client.js.map +1 -0
  87. package/lib/module/compatibility/runtime.js +35 -0
  88. package/lib/module/compatibility/runtime.js.map +1 -0
  89. package/lib/module/index.js +17 -0
  90. package/lib/module/index.js.map +1 -0
  91. package/lib/module/managers/DeviceManager.js +641 -0
  92. package/lib/module/managers/DeviceManager.js.map +1 -0
  93. package/lib/module/managers/OTAManager.js +134 -0
  94. package/lib/module/managers/OTAManager.js.map +1 -0
  95. package/lib/module/managers/RecordingManager.js +438 -0
  96. package/lib/module/managers/RecordingManager.js.map +1 -0
  97. package/lib/module/managers/StreamingSession.js +168 -0
  98. package/lib/module/managers/StreamingSession.js.map +1 -0
  99. package/lib/module/managers/types.js +4 -0
  100. package/lib/module/managers/types.js.map +1 -0
  101. package/lib/module/models/Device.js +2 -0
  102. package/lib/module/models/Device.js.map +1 -0
  103. package/lib/module/models/Recording.js +2 -0
  104. package/lib/module/models/Recording.js.map +1 -0
  105. package/lib/module/models/Status.js +4 -0
  106. package/lib/module/models/Status.js.map +1 -0
  107. package/lib/module/specs/NativeBotaDeviceSDK.js +5 -0
  108. package/lib/module/specs/NativeBotaDeviceSDK.js.map +1 -0
  109. package/lib/module/sync/syncStatus.js +174 -0
  110. package/lib/module/sync/syncStatus.js.map +1 -0
  111. package/lib/module/utils/errors.js +183 -0
  112. package/lib/module/utils/errors.js.map +1 -0
  113. package/lib/module/utils/logger.js +80 -0
  114. package/lib/module/utils/logger.js.map +1 -0
  115. package/lib/typescript/BotaClient.d.ts +40 -0
  116. package/lib/typescript/BotaClient.d.ts.map +1 -0
  117. package/lib/typescript/ble/constants.d.ts +4 -0
  118. package/lib/typescript/ble/constants.d.ts.map +1 -0
  119. package/lib/typescript/ble/deviceLogs.d.ts +10 -0
  120. package/lib/typescript/ble/deviceLogs.d.ts.map +1 -0
  121. package/lib/typescript/cache/DeviceStateCache.d.ts +14 -0
  122. package/lib/typescript/cache/DeviceStateCache.d.ts.map +1 -0
  123. package/lib/typescript/client.d.ts +208 -0
  124. package/lib/typescript/client.d.ts.map +1 -0
  125. package/lib/typescript/compatibility/runtime.d.ts +11 -0
  126. package/lib/typescript/compatibility/runtime.d.ts.map +1 -0
  127. package/lib/typescript/index.d.ts +19 -0
  128. package/lib/typescript/index.d.ts.map +1 -0
  129. package/lib/typescript/managers/DeviceManager.d.ts +117 -0
  130. package/lib/typescript/managers/DeviceManager.d.ts.map +1 -0
  131. package/lib/typescript/managers/OTAManager.d.ts +25 -0
  132. package/lib/typescript/managers/OTAManager.d.ts.map +1 -0
  133. package/lib/typescript/managers/RecordingManager.d.ts +54 -0
  134. package/lib/typescript/managers/RecordingManager.d.ts.map +1 -0
  135. package/lib/typescript/managers/StreamingSession.d.ts +35 -0
  136. package/lib/typescript/managers/StreamingSession.d.ts.map +1 -0
  137. package/lib/typescript/managers/types.d.ts +19 -0
  138. package/lib/typescript/managers/types.d.ts.map +1 -0
  139. package/lib/typescript/models/Device.d.ts +392 -0
  140. package/lib/typescript/models/Device.d.ts.map +1 -0
  141. package/lib/typescript/models/Recording.d.ts +259 -0
  142. package/lib/typescript/models/Recording.d.ts.map +1 -0
  143. package/lib/typescript/models/Status.d.ts +106 -0
  144. package/lib/typescript/models/Status.d.ts.map +1 -0
  145. package/lib/typescript/specs/NativeBotaDeviceSDK.d.ts +393 -0
  146. package/lib/typescript/specs/NativeBotaDeviceSDK.d.ts.map +1 -0
  147. package/lib/typescript/sync/syncStatus.d.ts +123 -0
  148. package/lib/typescript/sync/syncStatus.d.ts.map +1 -0
  149. package/lib/typescript/utils/errors.d.ts +83 -0
  150. package/lib/typescript/utils/errors.d.ts.map +1 -0
  151. package/lib/typescript/utils/logger.d.ts +36 -0
  152. package/lib/typescript/utils/logger.d.ts.map +1 -0
  153. package/package.json +100 -0
  154. package/scripts/bota_device_sdk_spm_workaround.rb +53 -0
  155. package/src/BotaClient.ts +231 -0
  156. package/src/ble/constants.ts +3 -0
  157. package/src/ble/deviceLogs.ts +61 -0
  158. package/src/cache/DeviceStateCache.ts +20 -0
  159. package/src/client.ts +1410 -0
  160. package/src/compatibility/runtime.ts +55 -0
  161. package/src/index.ts +146 -0
  162. package/src/managers/DeviceManager.ts +927 -0
  163. package/src/managers/OTAManager.ts +195 -0
  164. package/src/managers/RecordingManager.ts +578 -0
  165. package/src/managers/StreamingSession.ts +212 -0
  166. package/src/managers/types.ts +36 -0
  167. package/src/models/Device.ts +484 -0
  168. package/src/models/Recording.ts +281 -0
  169. package/src/models/Status.ts +128 -0
  170. package/src/specs/NativeBotaDeviceSDK.ts +542 -0
  171. package/src/sync/syncStatus.ts +243 -0
  172. package/src/utils/errors.ts +327 -0
  173. package/src/utils/logger.ts +122 -0
@@ -0,0 +1,740 @@
1
+ "use strict";
2
+
3
+ import { reportCompatibilityDisconnection } from './compatibility/runtime';
4
+ export class BotaNativeModuleError extends Error {
5
+ code = 'native_module_unavailable';
6
+ constructor() {
7
+ super('BotaDeviceSDK native module is unavailable. Rebuild the native application after installing the SDK.');
8
+ this.name = 'BotaNativeModuleError';
9
+ }
10
+ }
11
+ const mapDiscoveredDevice = device => ({
12
+ id: device.id,
13
+ name: device.name ?? '',
14
+ deviceType: device.deviceType ?? 'bota_pin',
15
+ firmwareVersion: device.firmwareVersion ?? '',
16
+ macAddress: device.macAddress ?? null,
17
+ pairingState: device.pairingState ?? 'unpaired',
18
+ rssi: device.rssi,
19
+ discoveredAt: new Date(device.discoveredAtMs)
20
+ });
21
+ const toNativeDiscoveredDevice = device => ({
22
+ id: device.id,
23
+ name: device.name,
24
+ deviceType: device.deviceType,
25
+ firmwareVersion: device.firmwareVersion,
26
+ ...(device.macAddress ? {
27
+ macAddress: device.macAddress
28
+ } : {}),
29
+ pairingState: device.pairingState,
30
+ rssi: device.rssi,
31
+ discoveredAtMs: device.discoveredAt.getTime()
32
+ });
33
+ const mapConnectedDevice = device => ({
34
+ ...device,
35
+ deviceType: device.deviceType,
36
+ connectionState: device.connectionState
37
+ });
38
+ const toNativeConnectedDevice = device => ({
39
+ id: device.id,
40
+ serialNumber: device.serialNumber,
41
+ deviceType: device.deviceType,
42
+ firmwareVersion: device.firmwareVersion,
43
+ ...(device.hardwareRevision === undefined ? {} : {
44
+ hardwareRevision: device.hardwareRevision
45
+ }),
46
+ isProvisioned: device.isProvisioned,
47
+ connectionState: device.connectionState,
48
+ mtu: device.mtu
49
+ });
50
+ const errorMessage = error => error instanceof Error ? error.message : String(error);
51
+ const createOpaqueId = () => 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, value => {
52
+ const random = Math.floor(Math.random() * 16);
53
+ const nibble = value === 'x' ? random : random & 0x3 | 0x8;
54
+ return nibble.toString(16);
55
+ });
56
+ const bytesToHex = value => Array.from(value, byte => byte.toString(16).padStart(2, '0')).join('');
57
+ const toNativeConnectionSettings = settings => ({
58
+ enabledConnections: settings.enabled_connections,
59
+ heartbeatEnabledConnections: settings.heartbeat_enabled_connections ?? {
60
+ wifi: true,
61
+ cellular: true
62
+ },
63
+ uploadNetworkPreference: settings.upload_network_preference,
64
+ powerManagement: {
65
+ wifiIdleTimeoutSeconds: settings.power_management?.wifi_idle_timeout_seconds ?? 180,
66
+ cellularIdleTimeoutSeconds: settings.power_management?.cellular_idle_timeout_seconds ?? 180
67
+ },
68
+ streamingEnabled: settings.streaming_enabled ?? true,
69
+ streamingFlushIntervalSeconds: settings.streaming_flush_interval_seconds ?? 60
70
+ });
71
+ const isConnectionType = value => value === 'wifi' || value === 'ble' || value === 'cellular';
72
+ const mapNativeConnectionSettings = settings => ({
73
+ enabled_connections: settings.enabledConnections,
74
+ heartbeat_enabled_connections: settings.heartbeatEnabledConnections,
75
+ upload_network_preference: settings.uploadNetworkPreference.filter(isConnectionType),
76
+ power_management: {
77
+ wifi_idle_timeout_seconds: settings.powerManagement.wifiIdleTimeoutSeconds,
78
+ cellular_idle_timeout_seconds: settings.powerManagement.cellularIdleTimeoutSeconds
79
+ },
80
+ streaming_enabled: settings.streamingEnabled,
81
+ streaming_flush_interval_seconds: settings.streamingFlushIntervalSeconds
82
+ });
83
+ const matchesScanOptions = (device, options) => {
84
+ if (options?.deviceTypes && !options.deviceTypes.includes(device.deviceType)) {
85
+ return false;
86
+ }
87
+ if (options?.pairingState && device.pairingState !== options.pairingState) {
88
+ return false;
89
+ }
90
+ if (options?.minRssi !== undefined && device.rssi < options.minRssi) {
91
+ return false;
92
+ }
93
+ return true;
94
+ };
95
+ const mapDeviceStatus = status => ({
96
+ batteryLevel: status.batteryLevel,
97
+ ...(status.batteryMv === undefined ? {} : {
98
+ batteryMv: status.batteryMv
99
+ }),
100
+ storageTotalMb: status.storageTotalMb,
101
+ storageUsedMb: status.storageUsedMb,
102
+ state: status.state,
103
+ pendingRecordings: status.pendingRecordings,
104
+ lastTimeSyncAt: status.lastTimeSyncAtMs === undefined ? null : new Date(status.lastTimeSyncAtMs),
105
+ signalStrength: status.signalStrength,
106
+ flags: status.flags,
107
+ timestamp: status.timestamp,
108
+ lteStatus: status.lteStatus,
109
+ ...(status.lteSignalQuality === undefined ? {} : {
110
+ lteSignalQuality: status.lteSignalQuality
111
+ }),
112
+ ...(status.wifiStatus === undefined ? {} : {
113
+ wifiStatus: status.wifiStatus
114
+ }),
115
+ ...(status.modemInfo === undefined ? {} : {
116
+ modemInfo: status.modemInfo
117
+ })
118
+ });
119
+ const mapRecording = recording => ({
120
+ uuid: recording.uuid,
121
+ startedAt: new Date(recording.startedAtMs),
122
+ durationMs: recording.durationMs,
123
+ fileSizeBytes: recording.fileSize,
124
+ codec: recording.codec,
125
+ isEncrypted: recording.isEncrypted
126
+ });
127
+ const toNativeRecording = recording => ({
128
+ uuid: recording.uuid,
129
+ startedAtMs: recording.startedAt.getTime(),
130
+ durationMs: recording.durationMs,
131
+ fileSize: recording.fileSizeBytes,
132
+ codec: recording.codec,
133
+ isEncrypted: recording.isEncrypted ?? false
134
+ });
135
+ const mapRecordingProgress = progress => ({
136
+ completedBytes: progress.completedUnits,
137
+ totalBytes: progress.totalUnits
138
+ });
139
+ const mapEncryptedUploadV2Progress = progress => ({
140
+ recordingUuid: progress.recordingUuid,
141
+ phase: progress.phase,
142
+ completedBytes: progress.completedBytes,
143
+ totalBytes: progress.totalBytes,
144
+ ...(progress.checkpointRevision === undefined ? {} : {
145
+ checkpointRevision: progress.checkpointRevision
146
+ }),
147
+ ...(progress.errorCode === undefined ? {} : {
148
+ errorCode: progress.errorCode
149
+ }),
150
+ ...(progress.retryable === undefined ? {} : {
151
+ retryable: progress.retryable
152
+ }),
153
+ ...(progress.protocolStatus === undefined ? {} : {
154
+ protocolStatus: progress.protocolStatus
155
+ })
156
+ });
157
+ const mapFirmwareProgress = progress => ({
158
+ phase: progress.phase,
159
+ completedBytes: progress.completedUnits,
160
+ totalBytes: progress.totalUnits
161
+ });
162
+ const isWiFiStatus = value => value === 'idle' || value === 'connecting' || value === 'connected' || value === 'failed' || value === 'disconnected';
163
+ const mapWiFiStatus = status => ({
164
+ status: isWiFiStatus(status.status) ? status.status : 'idle',
165
+ ...(status.signalStrength === undefined ? {} : {
166
+ signalStrength: status.signalStrength
167
+ }),
168
+ ...(status.ssid === undefined ? {} : {
169
+ ssid: status.ssid
170
+ }),
171
+ ...(status.lastError === undefined ? {} : {
172
+ lastError: status.lastError
173
+ })
174
+ });
175
+ const mapRecordingControlResult = result => ({
176
+ success: result.success,
177
+ ...(result.error === undefined ? {} : {
178
+ error: result.error
179
+ })
180
+ });
181
+ const mapRecordingState = state => ({
182
+ active: state.active,
183
+ ...(state.recordingId === undefined ? {} : {
184
+ recordingId: state.recordingId
185
+ }),
186
+ initiatedBy: state.initiatedBy === 'remote' ? 'remote' : 'local'
187
+ });
188
+ const mapWiFiConfigResult = result => {
189
+ if (result.success) return {
190
+ success: true
191
+ };
192
+ switch (result.error) {
193
+ case 'invalid_grant':
194
+ case 'grant_expired':
195
+ case 'decryption_error':
196
+ case 'storage_error':
197
+ return {
198
+ success: false,
199
+ error: result.error
200
+ };
201
+ default:
202
+ return {
203
+ success: false,
204
+ error: 'unknown'
205
+ };
206
+ }
207
+ };
208
+ const mapWiFiScanResult = result => ({
209
+ networks: result.networks.map(network => ({
210
+ ...network
211
+ })),
212
+ currentSsid: result.currentSsid ?? null
213
+ });
214
+ const requiredUploadOwnershipField = (value, field) => {
215
+ if (value === undefined) {
216
+ throw new Error(`native upload ownership result is missing ${field}`);
217
+ }
218
+ return value;
219
+ };
220
+ const mapUploadOwnershipResult = result => {
221
+ switch (result.kind) {
222
+ case 'device_upload_completed':
223
+ return {
224
+ kind: 'device_upload_completed'
225
+ };
226
+ case 'device_upload_preserved':
227
+ return {
228
+ kind: 'device_upload_preserved',
229
+ uploadId: requiredUploadOwnershipField(result.uploadId, 'uploadId')
230
+ };
231
+ case 'bluetooth_fallback':
232
+ return {
233
+ kind: 'bluetooth_fallback',
234
+ recordingUuid: requiredUploadOwnershipField(result.recordingUuid, 'recordingUuid'),
235
+ uploadId: requiredUploadOwnershipField(result.uploadId, 'uploadId'),
236
+ destinationId: requiredUploadOwnershipField(result.destinationId, 'destinationId')
237
+ };
238
+ default:
239
+ throw new Error(`unsupported native upload ownership result: ${result.kind}`);
240
+ }
241
+ };
242
+ const toNativeRecordingUploadRequest = task => ({
243
+ taskId: task.id,
244
+ recordingId: task.recordingId,
245
+ deviceId: task.deviceId,
246
+ localPath: task.localPath,
247
+ uploadUrl: task.uploadUrl,
248
+ ...(task.uploadToken ? {
249
+ uploadToken: task.uploadToken
250
+ } : {}),
251
+ ...(task.completeUrl ? {
252
+ completeUrl: task.completeUrl
253
+ } : {}),
254
+ ...(task.contentType ? {
255
+ contentType: task.contentType
256
+ } : {}),
257
+ ...(task.contentSha256 ? {
258
+ contentSha256: task.contentSha256
259
+ } : {}),
260
+ ...(task.relay ? {
261
+ relayUrl: task.relay.url,
262
+ relayBearerToken: task.relay.bearerToken
263
+ } : {})
264
+ });
265
+ const parseUploadQueue = serialized => {
266
+ const value = JSON.parse(serialized || '[]');
267
+ if (!Array.isArray(value)) return [];
268
+ return value.map(task => {
269
+ const candidate = task;
270
+ return {
271
+ ...candidate,
272
+ createdAt: new Date(candidate.createdAt),
273
+ updatedAt: new Date(candidate.updatedAt)
274
+ };
275
+ });
276
+ };
277
+ export const createBotaDeviceSDK = nativeModule => {
278
+ const requireNativeModule = () => {
279
+ if (!nativeModule) throw new BotaNativeModuleError();
280
+ return nativeModule;
281
+ };
282
+ const devices = {
283
+ async startScan(options, onDevice) {
284
+ const module = requireNativeModule();
285
+ const subscription = module.onDeviceDiscovered(device => {
286
+ const discovered = mapDiscoveredDevice(device);
287
+ if (matchesScanOptions(discovered, options)) onDevice(discovered);
288
+ });
289
+ try {
290
+ await module.startScan(options?.timeout ?? 30_000, options?.allowDuplicates ?? false);
291
+ } catch (error) {
292
+ subscription.remove();
293
+ throw error;
294
+ }
295
+ return subscription;
296
+ },
297
+ async stopScan() {
298
+ await requireNativeModule().stopScan();
299
+ },
300
+ async connect(device) {
301
+ return mapConnectedDevice(await requireNativeModule().connectSelected(toNativeDiscoveredDevice(device)));
302
+ },
303
+ async reconnect(serialNumber, options = {}) {
304
+ return mapConnectedDevice(await requireNativeModule().reconnect(serialNumber, {
305
+ scanTimeoutMs: options.scanTimeout ?? 10_000,
306
+ connectionTimeoutMs: 10_000
307
+ }));
308
+ },
309
+ async disconnect() {
310
+ await requireNativeModule().disconnect();
311
+ },
312
+ async readStatus() {
313
+ return mapDeviceStatus(await requireNativeModule().readStatus());
314
+ },
315
+ async subscribeToStatus(onStatus) {
316
+ const module = requireNativeModule();
317
+ const eventSubscription = module.onDeviceStatusUpdated(status => {
318
+ onStatus(mapDeviceStatus(status));
319
+ });
320
+ try {
321
+ await module.startStatusUpdates();
322
+ } catch (error) {
323
+ eventSubscription.remove();
324
+ throw error;
325
+ }
326
+ let removed = false;
327
+ return {
328
+ async remove() {
329
+ if (removed) return;
330
+ removed = true;
331
+ eventSubscription.remove();
332
+ await module.stopStatusUpdates();
333
+ }
334
+ };
335
+ }
336
+ };
337
+ const provisioning = {
338
+ async provision(device, provider) {
339
+ const module = requireNativeModule();
340
+ const subscription = module.onProvisioningMaterialRequested(request => {
341
+ void (async () => {
342
+ try {
343
+ const material = await provider({
344
+ serialNumber: request.serialNumber,
345
+ nonce: request.nonce,
346
+ devicePublicKey: request.devicePublicKey
347
+ });
348
+ await module.resolveProvisioningMaterial(request.requestId, material);
349
+ } catch (error) {
350
+ await module.rejectApplicationMaterial(request.requestId, errorMessage(error));
351
+ }
352
+ })().catch(() => {});
353
+ });
354
+ try {
355
+ await module.provision(toNativeConnectedDevice(device));
356
+ } finally {
357
+ subscription.remove();
358
+ }
359
+ },
360
+ async deprovision(device, grantBlob) {
361
+ const result = await requireNativeModule().deprovision(toNativeConnectedDevice(device), grantBlob);
362
+ return result.error === undefined ? {
363
+ success: result.success
364
+ } : {
365
+ success: result.success,
366
+ error: result.error
367
+ };
368
+ },
369
+ async readConnectionSettings(device) {
370
+ return mapNativeConnectionSettings(await requireNativeModule().readConnectionSettings(toNativeConnectedDevice(device)));
371
+ },
372
+ async writeConnectionSettings(device, settings) {
373
+ await requireNativeModule().writeConnectionSettings(toNativeConnectedDevice(device), toNativeConnectionSettings(settings));
374
+ }
375
+ };
376
+ const controls = {
377
+ async isProvisioned(device) {
378
+ return requireNativeModule().isProvisioned(toNativeConnectedDevice(device));
379
+ },
380
+ async readPublicKey(device) {
381
+ return requireNativeModule().readPublicKey(toNativeConnectedDevice(device));
382
+ },
383
+ async readAuthNonce(device) {
384
+ return requireNativeModule().readAuthNonce(toNativeConnectedDevice(device));
385
+ },
386
+ async setApiEndpoint(device, environment) {
387
+ await requireNativeModule().setApiEndpoint(toNativeConnectedDevice(device), environment);
388
+ },
389
+ async deliverCertificate(device, certificatePem, privateKeyPem) {
390
+ await requireNativeModule().deliverCertificate(toNativeConnectedDevice(device), certificatePem, privateKeyPem);
391
+ },
392
+ async deliverBackendPublicKey(device, publicKey) {
393
+ await requireNativeModule().deliverBackendPublicKey(toNativeConnectedDevice(device), bytesToHex(publicKey));
394
+ },
395
+ async writeGrant(device, grantBlob) {
396
+ await requireNativeModule().writeGrant(toNativeConnectedDevice(device), grantBlob);
397
+ },
398
+ async syncTime(device) {
399
+ await requireNativeModule().syncTime(toNativeConnectedDevice(device));
400
+ },
401
+ async requestStartRecording(device, grantBlob) {
402
+ return mapRecordingControlResult(await requireNativeModule().requestStartRecording(toNativeConnectedDevice(device), grantBlob));
403
+ },
404
+ async requestStopRecording(device, grantBlob) {
405
+ return mapRecordingControlResult(await requireNativeModule().requestStopRecording(toNativeConnectedDevice(device), grantBlob));
406
+ },
407
+ async readRecordingState(device) {
408
+ return mapRecordingState(await requireNativeModule().readRecordingState(toNativeConnectedDevice(device)));
409
+ },
410
+ async subscribeToRecordingState(device, onState) {
411
+ const module = requireNativeModule();
412
+ const eventSubscription = module.onRecordingStateUpdated(state => {
413
+ onState(mapRecordingState(state));
414
+ });
415
+ try {
416
+ await module.startRecordingStateUpdates(toNativeConnectedDevice(device));
417
+ } catch (error) {
418
+ eventSubscription.remove();
419
+ throw error;
420
+ }
421
+ let removed = false;
422
+ return {
423
+ async remove() {
424
+ if (removed) return;
425
+ removed = true;
426
+ eventSubscription.remove();
427
+ await module.stopRecordingStateUpdates();
428
+ }
429
+ };
430
+ }
431
+ };
432
+ const factoryReset = {
433
+ async factoryReset(device, options, provider, persistResult) {
434
+ const module = requireNativeModule();
435
+ const grantSubscription = module.onFactoryResetGrantRequested(request => {
436
+ void (async () => {
437
+ try {
438
+ const grantBlob = await provider({
439
+ serialNumber: request.serialNumber,
440
+ nonce: request.nonce,
441
+ commandId: request.commandId,
442
+ bindingGeneration: request.bindingGeneration
443
+ });
444
+ await module.resolveFactoryResetGrant(request.requestId, grantBlob);
445
+ } catch (error) {
446
+ await module.rejectApplicationMaterial(request.requestId, errorMessage(error));
447
+ }
448
+ })().catch(() => {});
449
+ });
450
+ const persistenceSubscription = persistResult ? module.onFactoryResetResultPersistenceRequested(request => {
451
+ void (async () => {
452
+ try {
453
+ await persistResult({
454
+ success: true,
455
+ localRecordingsDeleted: request.localRecordingsDeleted
456
+ });
457
+ await module.resolveFactoryResetResultPersistence(request.requestId);
458
+ } catch (error) {
459
+ await module.rejectApplicationMaterial(request.requestId, errorMessage(error));
460
+ }
461
+ })().catch(() => {});
462
+ }) : null;
463
+ try {
464
+ return await module.factoryReset(toNativeConnectedDevice(device), options.commandId, options.bindingGeneration, persistResult !== undefined);
465
+ } finally {
466
+ grantSubscription.remove();
467
+ persistenceSubscription?.remove();
468
+ }
469
+ },
470
+ async resumePendingFactoryReset(device, currentBindingGeneration, persistResult) {
471
+ const module = requireNativeModule();
472
+ const subscription = persistResult ? module.onFactoryResetResultPersistenceRequested(request => {
473
+ void (async () => {
474
+ try {
475
+ await persistResult({
476
+ success: true,
477
+ localRecordingsDeleted: request.localRecordingsDeleted
478
+ });
479
+ await module.resolveFactoryResetResultPersistence(request.requestId);
480
+ } catch (error) {
481
+ await module.rejectApplicationMaterial(request.requestId, errorMessage(error));
482
+ }
483
+ })().catch(() => {});
484
+ }) : null;
485
+ try {
486
+ return await module.resumePendingFactoryReset(toNativeConnectedDevice(device), currentBindingGeneration, persistResult !== undefined);
487
+ } finally {
488
+ subscription?.remove();
489
+ }
490
+ }
491
+ };
492
+ const recordings = {
493
+ async listRecordings(device) {
494
+ const values = await requireNativeModule().listRecordings(toNativeConnectedDevice(device));
495
+ return values.map(mapRecording);
496
+ },
497
+ async syncRecording(device, recording, onProgress, sinkId) {
498
+ const module = requireNativeModule();
499
+ const subscription = module.onRecordingTransferProgress(progress => {
500
+ onProgress?.(mapRecordingProgress(progress));
501
+ });
502
+ try {
503
+ return await module.syncRecording(toNativeConnectedDevice(device), toNativeRecording(recording), sinkId ?? createOpaqueId());
504
+ } finally {
505
+ subscription.remove();
506
+ }
507
+ },
508
+ async syncEncryptedRecordingV2(device, recording, provider, onProgress) {
509
+ const module = requireNativeModule();
510
+ const operationId = createOpaqueId();
511
+ const profileSubscription = module.onEncryptedUploadV2ProfileRequested(request => {
512
+ if (request.operationId !== operationId) return;
513
+ void (async () => {
514
+ try {
515
+ const decision = await provider({
516
+ recording: request.recording,
517
+ capability: request.capability,
518
+ ...(request.checkpoint === undefined ? {} : {
519
+ checkpoint: request.checkpoint
520
+ })
521
+ });
522
+ if (decision.profile !== 'encrypted_upload_v2') {
523
+ throw new Error('encrypted upload v2 requires an explicit v2 profile');
524
+ }
525
+ await module.resolveEncryptedUploadV2Profile(request.requestId, decision);
526
+ } catch (error) {
527
+ await module.rejectEncryptedUploadV2Profile(request.requestId, 'application_material_rejected');
528
+ }
529
+ })().catch(() => {});
530
+ });
531
+ const progressSubscription = module.onEncryptedUploadV2Progress(progress => {
532
+ if (progress.operationId !== operationId) return;
533
+ onProgress?.(mapEncryptedUploadV2Progress(progress));
534
+ });
535
+ try {
536
+ await module.syncEncryptedRecordingV2(toNativeConnectedDevice(device), recording, operationId);
537
+ } finally {
538
+ profileSubscription.remove();
539
+ progressSubscription.remove();
540
+ }
541
+ },
542
+ async uploadRecordingFile(task, onProgress) {
543
+ const module = requireNativeModule();
544
+ const subscription = module.onRecordingUploadProgress(progress => {
545
+ if (progress.taskId !== task.id) return;
546
+ onProgress?.({
547
+ completedBytes: progress.completedBytes,
548
+ totalBytes: progress.totalBytes
549
+ });
550
+ });
551
+ try {
552
+ await module.uploadRecordingFile(toNativeRecordingUploadRequest(task));
553
+ } finally {
554
+ subscription.remove();
555
+ }
556
+ },
557
+ async confirmRecording(device, recordingUuid) {
558
+ await requireNativeModule().confirmRecording(toNativeConnectedDevice(device), recordingUuid);
559
+ },
560
+ async cancelRecordingUpload(taskId) {
561
+ await requireNativeModule().cancelRecordingUpload(taskId);
562
+ },
563
+ async loadUploadQueue() {
564
+ return parseUploadQueue(await requireNativeModule().loadCompatibilityUploadQueue());
565
+ },
566
+ async saveUploadQueue(tasks) {
567
+ await requireNativeModule().saveCompatibilityUploadQueue(JSON.stringify(tasks));
568
+ },
569
+ async destroyCompatibilityOperations() {
570
+ await requireNativeModule().stopAllRecordingOperations();
571
+ },
572
+ async observeUploadOwnership(device, request, onProgress) {
573
+ const module = requireNativeModule();
574
+ const subscription = module.onUploadOwnershipProgress(progress => {
575
+ onProgress?.(mapRecordingProgress(progress));
576
+ });
577
+ try {
578
+ return mapUploadOwnershipResult(await module.observeUploadOwnership(toNativeConnectedDevice(device), request));
579
+ } finally {
580
+ subscription.remove();
581
+ }
582
+ }
583
+ };
584
+ const ota = {
585
+ async updateFirmware(device, image, onProgress) {
586
+ const module = requireNativeModule();
587
+ const subscription = module.onFirmwareUpdateProgress(progress => {
588
+ onProgress?.(mapFirmwareProgress(progress));
589
+ });
590
+ try {
591
+ await module.updateFirmware(toNativeConnectedDevice(device), {
592
+ version: image.version,
593
+ sizeUnits: image.sizeBytes,
594
+ crc32: image.crc32,
595
+ url: image.url
596
+ });
597
+ } finally {
598
+ subscription.remove();
599
+ }
600
+ },
601
+ async cancelFirmwareUpdate() {
602
+ await requireNativeModule().cancelFirmwareUpdate();
603
+ }
604
+ };
605
+ const streaming = {
606
+ async startStreaming(device, request, handlers) {
607
+ const module = requireNativeModule();
608
+ const progressSubscription = module.onStreamingProgress(progress => {
609
+ if (progress.sessionId !== request.sessionId) return;
610
+ handlers.onProgress({
611
+ state: progress.state,
612
+ bytesReceived: progress.bytesReceived,
613
+ chunksUploaded: progress.chunksUploaded
614
+ });
615
+ });
616
+ const destinationSubscription = module.onStreamingChunkDestinationRequested(nativeRequest => {
617
+ if (nativeRequest.sessionId !== request.sessionId) return;
618
+ void handlers.resolveChunkDestination({
619
+ sequence: nativeRequest.sequence,
620
+ encrypted: nativeRequest.encrypted
621
+ }).then(destination => module.resolveStreamingChunkDestination(nativeRequest.requestId, destination), error => module.rejectStreamingChunkDestination(nativeRequest.requestId, errorMessage(error))).catch(() => {});
622
+ });
623
+ const finalizeSubscription = module.onStreamingFinalizeRequested(nativeRequest => {
624
+ if (nativeRequest.sessionId !== request.sessionId) return;
625
+ void handlers.finalize({
626
+ totalChunks: nativeRequest.totalChunks,
627
+ durationMs: nativeRequest.durationMs,
628
+ fileSizeBytes: nativeRequest.fileSizeBytes,
629
+ encrypted: nativeRequest.encrypted
630
+ }).then(() => module.resolveStreamingFinalize(nativeRequest.requestId), error => module.rejectStreamingFinalize(nativeRequest.requestId, errorMessage(error))).catch(() => {});
631
+ });
632
+ try {
633
+ return await module.startStreaming(toNativeConnectedDevice(device), request);
634
+ } finally {
635
+ progressSubscription.remove();
636
+ destinationSubscription.remove();
637
+ finalizeSubscription.remove();
638
+ }
639
+ },
640
+ async abortStreaming(sessionId) {
641
+ await requireNativeModule().abortStreaming(sessionId);
642
+ }
643
+ };
644
+ const logs = {
645
+ async subscribe(device, onLine) {
646
+ const module = requireNativeModule();
647
+ const eventSubscription = module.onDeviceLog(line => {
648
+ onLine({
649
+ level: 'debug',
650
+ message: line.message,
651
+ isBacklog: line.isBacklog
652
+ });
653
+ });
654
+ try {
655
+ await module.startDeviceLogs(toNativeConnectedDevice(device));
656
+ } catch (error) {
657
+ eventSubscription.remove();
658
+ throw error;
659
+ }
660
+ let removed = false;
661
+ return {
662
+ async remove() {
663
+ if (removed) return;
664
+ removed = true;
665
+ eventSubscription.remove();
666
+ await module.stopDeviceLogs();
667
+ }
668
+ };
669
+ }
670
+ };
671
+ const wifi = {
672
+ async configure(device, credentials, grant) {
673
+ return mapWiFiConfigResult(await requireNativeModule().configureWiFi(toNativeConnectedDevice(device), credentials.ssid, credentials.password, grant.grantBlob));
674
+ },
675
+ async disconnect(device) {
676
+ return mapWiFiConfigResult(await requireNativeModule().disconnectWiFi(toNativeConnectedDevice(device)));
677
+ },
678
+ async readStatus(device) {
679
+ return mapWiFiStatus(await requireNativeModule().readWiFiStatus(toNativeConnectedDevice(device)));
680
+ },
681
+ async subscribeToStatus(device, onStatus) {
682
+ const module = requireNativeModule();
683
+ const eventSubscription = module.onWiFiStatusUpdated(status => {
684
+ onStatus(mapWiFiStatus(status));
685
+ });
686
+ try {
687
+ await module.startWiFiStatusUpdates(toNativeConnectedDevice(device));
688
+ } catch (error) {
689
+ eventSubscription.remove();
690
+ throw error;
691
+ }
692
+ let removed = false;
693
+ return {
694
+ async remove() {
695
+ if (removed) return;
696
+ removed = true;
697
+ eventSubscription.remove();
698
+ await module.stopWiFiStatusUpdates();
699
+ }
700
+ };
701
+ },
702
+ async scanNetworks(device) {
703
+ return mapWiFiScanResult(await requireNativeModule().scanWiFiNetworks(toNativeConnectedDevice(device)));
704
+ }
705
+ };
706
+ const client = {
707
+ controls,
708
+ devices,
709
+ factoryReset,
710
+ logs,
711
+ ota,
712
+ provisioning,
713
+ recordings,
714
+ streaming,
715
+ wifi,
716
+ async configure(configuration = {}) {
717
+ const nativeConfiguration = {
718
+ logLevel: configuration.logLevel ?? 'warn',
719
+ ...(configuration.applicationSupportDirectory ? {
720
+ applicationSupportDirectory: configuration.applicationSupportDirectory
721
+ } : {})
722
+ };
723
+ await requireNativeModule().configure(nativeConfiguration);
724
+ },
725
+ async destroy() {
726
+ await requireNativeModule().destroy();
727
+ },
728
+ async getCapabilities() {
729
+ return requireNativeModule().getCapabilities();
730
+ },
731
+ async getState() {
732
+ return await requireNativeModule().getState();
733
+ }
734
+ };
735
+ nativeModule?.onDeviceDisconnected?.(event => {
736
+ reportCompatibilityDisconnection(client, event.error ? new Error(event.error) : undefined);
737
+ });
738
+ return client;
739
+ };
740
+ //# sourceMappingURL=client.js.map