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