@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,476 @@
1
+ package dev.bota.sdk.reactnative
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.bridge.WritableMap
6
+ import dev.bota.sdk.UploadOwnershipResult
7
+ import dev.bota.sdk.model.ConnectedDevice
8
+ import dev.bota.sdk.model.ConnectionState
9
+ import dev.bota.sdk.model.AudioCodec
10
+ import dev.bota.sdk.model.DeviceFlags
11
+ import dev.bota.sdk.model.DeviceLogLine
12
+ import dev.bota.sdk.model.DeviceConnectionSettings
13
+ import dev.bota.sdk.model.DeprovisionResult
14
+ import dev.bota.sdk.model.DeviceRecording
15
+ import dev.bota.sdk.model.DeviceState
16
+ import dev.bota.sdk.model.DeviceStatus
17
+ import dev.bota.sdk.model.DeviceType
18
+ import dev.bota.sdk.model.DiscoveredDevice
19
+ import dev.bota.sdk.model.FactoryResetCompletion
20
+ import dev.bota.sdk.model.FirmwareUpdatePhase
21
+ import dev.bota.sdk.model.FirmwareUpdateProgress
22
+ import dev.bota.sdk.model.LteStatus
23
+ import dev.bota.sdk.model.ModemInfo
24
+ import dev.bota.sdk.model.PairingState
25
+ import dev.bota.sdk.model.RecordingTransferProgress
26
+ import dev.bota.sdk.model.RecordingControlResult
27
+ import dev.bota.sdk.model.RecordingInitiator
28
+ import dev.bota.sdk.model.RecordingState
29
+ import dev.bota.sdk.model.WifiRadioStatus
30
+ import dev.bota.sdk.model.DeviceWiFiScanResult
31
+ import dev.bota.sdk.model.WiFiConfigResult
32
+ import dev.bota.sdk.model.WiFiConnectionStatus
33
+ import dev.bota.sdk.model.WiFiStatusInfo
34
+ import dev.bota.sdk.model.WireValue
35
+ import java.time.Instant
36
+
37
+ internal fun ReadableMap.toDiscoveredDevice(): DiscoveredDevice = DiscoveredDevice(
38
+ id = getString("id") ?: error("selected device id is required"),
39
+ name = optionalString("name"),
40
+ deviceType = optionalString("deviceType")?.toDeviceType(),
41
+ firmwareVersion = optionalString("firmwareVersion"),
42
+ macAddress = optionalString("macAddress"),
43
+ pairingState = optionalString("pairingState")?.toPairingState(),
44
+ rssi = getDouble("rssi").toInt(),
45
+ discoveredAt = Instant.ofEpochMilli(getDouble("discoveredAtMs").toLong()),
46
+ )
47
+
48
+ internal fun ReadableMap.toConnectedDevice(): ConnectedDevice = ConnectedDevice(
49
+ id = getString("id") ?: error("connected device id is required"),
50
+ serialNumber = getString("serialNumber") ?: error("connected device serial number is required"),
51
+ deviceType = getString("deviceType")?.toDeviceType()
52
+ ?: error("connected device type is required"),
53
+ firmwareVersion = getString("firmwareVersion")
54
+ ?: error("connected device firmware version is required"),
55
+ hardwareRevision = optionalString("hardwareRevision"),
56
+ isProvisioned = getBoolean("isProvisioned"),
57
+ connectionState = getString("connectionState")?.toConnectionState()
58
+ ?: error("connected device connection state is required"),
59
+ mtu = requiredInt("mtu"),
60
+ )
61
+
62
+ internal fun ReadableMap.toDeviceRecording(): DeviceRecording = DeviceRecording(
63
+ uuid = getString("uuid") ?: error("recording UUID is required"),
64
+ startedAt = Instant.ofEpochMilli(requiredSafeUnsigned("startedAtMs").toLong()),
65
+ durationMs = requiredSafeUnsigned("durationMs"),
66
+ fileSizeBytes = requiredSafeUnsigned("fileSize"),
67
+ codec = WireValue.Known(
68
+ when (getString("codec")) {
69
+ "pcm_16k" -> AudioCodec.Pcm16k
70
+ "pcm_8k" -> AudioCodec.Pcm8k
71
+ "opus_8k" -> AudioCodec.Opus8k
72
+ else -> AudioCodec.Opus16k
73
+ },
74
+ ),
75
+ isEncrypted = getBoolean("isEncrypted"),
76
+ )
77
+
78
+ internal fun ReadableMap.toDeviceConnectionSettings(): DeviceConnectionSettings {
79
+ val enabled = getMap("enabledConnections") ?: error("enabled connections are required")
80
+ val heartbeat = getMap("heartbeatEnabledConnections")
81
+ ?: error("heartbeat enabled connections are required")
82
+ val preference = getArray("uploadNetworkPreference")
83
+ ?: error("upload network preference is required")
84
+ val power = getMap("powerManagement") ?: error("power management is required")
85
+ return DeviceConnectionSettings(
86
+ enabledConnections = DeviceConnectionSettings.EnabledConnections(
87
+ wifi = enabled.getBoolean("wifi"),
88
+ cellular = enabled.getBoolean("cellular"),
89
+ ),
90
+ heartbeatEnabledConnections = DeviceConnectionSettings.EnabledConnections(
91
+ wifi = heartbeat.getBoolean("wifi"),
92
+ cellular = heartbeat.getBoolean("cellular"),
93
+ ),
94
+ uploadNetworkPreference = (0 until preference.size()).map { index ->
95
+ when (preference.getString(index)) {
96
+ "wifi" -> DeviceConnectionSettings.ConnectionType.Wifi
97
+ "ble" -> DeviceConnectionSettings.ConnectionType.Ble
98
+ "cellular" -> DeviceConnectionSettings.ConnectionType.Cellular
99
+ else -> error("upload network preference contains an unsupported value")
100
+ }
101
+ },
102
+ powerManagement = DeviceConnectionSettings.PowerManagement(
103
+ wifiIdleTimeoutSeconds = power.requiredInt("wifiIdleTimeoutSeconds"),
104
+ cellularIdleTimeoutSeconds = power.requiredInt("cellularIdleTimeoutSeconds"),
105
+ ),
106
+ streamingEnabled = getBoolean("streamingEnabled"),
107
+ streamingFlushIntervalSeconds = requiredInt("streamingFlushIntervalSeconds"),
108
+ )
109
+ }
110
+
111
+ internal fun DeviceConnectionSettings.toWritableMap(): WritableMap = Arguments.createMap().apply {
112
+ putMap("enabledConnections", Arguments.createMap().apply {
113
+ putBoolean("wifi", enabledConnections.wifi)
114
+ putBoolean("cellular", enabledConnections.cellular)
115
+ })
116
+ putMap("heartbeatEnabledConnections", Arguments.createMap().apply {
117
+ putBoolean("wifi", heartbeatEnabledConnections.wifi)
118
+ putBoolean("cellular", heartbeatEnabledConnections.cellular)
119
+ })
120
+ putArray("uploadNetworkPreference", Arguments.createArray().apply {
121
+ uploadNetworkPreference.forEach { connection ->
122
+ when (connection) {
123
+ DeviceConnectionSettings.ConnectionType.Wifi -> pushString("wifi")
124
+ DeviceConnectionSettings.ConnectionType.Ble -> pushString("ble")
125
+ DeviceConnectionSettings.ConnectionType.Cellular -> pushString("cellular")
126
+ is DeviceConnectionSettings.ConnectionType.Unknown -> Unit
127
+ }
128
+ }
129
+ })
130
+ putMap("powerManagement", Arguments.createMap().apply {
131
+ putInt("wifiIdleTimeoutSeconds", powerManagement.wifiIdleTimeoutSeconds)
132
+ putInt("cellularIdleTimeoutSeconds", powerManagement.cellularIdleTimeoutSeconds)
133
+ })
134
+ putBoolean("streamingEnabled", streamingEnabled)
135
+ putInt("streamingFlushIntervalSeconds", streamingFlushIntervalSeconds)
136
+ }
137
+
138
+ internal fun DiscoveredDevice.toWritableMap(): WritableMap = Arguments.createMap().apply {
139
+ putString("id", id)
140
+ name?.let { putString("name", it) }
141
+ deviceType?.let { putString("deviceType", it.toBridgeValue()) }
142
+ firmwareVersion?.let { putString("firmwareVersion", it) }
143
+ macAddress?.let { putString("macAddress", it) }
144
+ pairingState?.let { putString("pairingState", it.toBridgeValue()) }
145
+ putDouble("rssi", rssi.toDouble())
146
+ putDouble("discoveredAtMs", discoveredAt.toEpochMilli().toDouble())
147
+ }
148
+
149
+ internal fun ConnectedDevice.toWritableMap(): WritableMap = Arguments.createMap().apply {
150
+ putString("id", id)
151
+ putString("serialNumber", serialNumber)
152
+ putString("deviceType", deviceType.toBridgeValue())
153
+ putString("firmwareVersion", firmwareVersion)
154
+ hardwareRevision?.let { putString("hardwareRevision", it) }
155
+ putBoolean("isProvisioned", isProvisioned)
156
+ putString("connectionState", connectionState.toBridgeValue())
157
+ putInt("mtu", mtu)
158
+ }
159
+
160
+ internal fun DeviceRecording.toWritableMap(): WritableMap = Arguments.createMap().apply {
161
+ putString("uuid", uuid)
162
+ putDouble("startedAtMs", startedAt.toEpochMilli().toDouble())
163
+ putDouble("durationMs", durationMs.toDouble())
164
+ putDouble("fileSize", fileSizeBytes.toDouble())
165
+ putString("codec", codec.toAudioCodecBridgeValue())
166
+ putBoolean("isEncrypted", isEncrypted)
167
+ }
168
+
169
+ internal fun RecordingTransferProgress.toWritableMap(): WritableMap = Arguments.createMap().apply {
170
+ putDouble("completedUnits", completedBytes.toDouble())
171
+ putDouble("totalUnits", totalBytes.toDouble())
172
+ }
173
+
174
+ internal fun RecordingControlResult.toWritableMap(): WritableMap = Arguments.createMap().apply {
175
+ putBoolean("success", success)
176
+ error?.let { putString("error", it.wireValue) }
177
+ }
178
+
179
+ internal fun DeprovisionResult.toWritableMap(): WritableMap = Arguments.createMap().apply {
180
+ putBoolean("success", success)
181
+ error?.let { putString("error", it.wireValue) }
182
+ }
183
+
184
+ internal fun RecordingState.toWritableMap(): WritableMap = Arguments.createMap().apply {
185
+ putBoolean("active", active)
186
+ recordingId?.let { putString("recordingId", it) }
187
+ putString(
188
+ "initiatedBy",
189
+ if (initiatedBy == RecordingInitiator.Remote) "remote" else "local",
190
+ )
191
+ }
192
+
193
+ internal fun UploadOwnershipResult.toWritableMap(): WritableMap = Arguments.createMap().apply {
194
+ when (this@toWritableMap) {
195
+ UploadOwnershipResult.DeviceUploadCompleted -> {
196
+ putString("kind", "device_upload_completed")
197
+ }
198
+ is UploadOwnershipResult.DeviceUploadPreserved -> {
199
+ putString("kind", "device_upload_preserved")
200
+ putString("uploadId", uploadId)
201
+ }
202
+ is UploadOwnershipResult.BluetoothFallback -> {
203
+ putString("kind", "bluetooth_fallback")
204
+ putString("recordingUuid", recordingUuid)
205
+ putString("uploadId", uploadId)
206
+ putString("destinationId", destinationId)
207
+ }
208
+ }
209
+ }
210
+
211
+ internal fun FirmwareUpdateProgress.toWritableMap(): WritableMap = Arguments.createMap().apply {
212
+ putString("phase", phase.toBridgeValue())
213
+ putDouble("completedUnits", completedBytes.toDouble())
214
+ putDouble("totalUnits", totalBytes.toDouble())
215
+ }
216
+
217
+ internal fun DeviceLogLine.toWritableMap(): WritableMap = Arguments.createMap().apply {
218
+ putString("message", message)
219
+ putBoolean("isBacklog", isBacklog)
220
+ }
221
+
222
+ internal fun WiFiConfigResult.toWritableMap(): WritableMap = Arguments.createMap().apply {
223
+ when (this@toWritableMap) {
224
+ WiFiConfigResult.Success -> putBoolean("success", true)
225
+ WiFiConfigResult.InvalidGrant -> {
226
+ putBoolean("success", false)
227
+ putString("error", "invalid_grant")
228
+ }
229
+ WiFiConfigResult.GrantExpired -> {
230
+ putBoolean("success", false)
231
+ putString("error", "grant_expired")
232
+ }
233
+ WiFiConfigResult.DecryptionError -> {
234
+ putBoolean("success", false)
235
+ putString("error", "decryption_error")
236
+ }
237
+ WiFiConfigResult.StorageError -> {
238
+ putBoolean("success", false)
239
+ putString("error", "storage_error")
240
+ }
241
+ is WiFiConfigResult.Unknown -> {
242
+ putBoolean("success", false)
243
+ putString("error", "unknown")
244
+ }
245
+ }
246
+ }
247
+
248
+ internal fun WiFiStatusInfo.toWritableMap(): WritableMap = Arguments.createMap().apply {
249
+ putString("status", status.toBridgeValue())
250
+ signalStrength?.let { putInt("signalStrength", it.toInt()) }
251
+ ssid?.let { putString("ssid", it) }
252
+ lastError?.let { putString("lastError", it) }
253
+ }
254
+
255
+ internal fun DeviceWiFiScanResult.toWritableMap(): WritableMap = Arguments.createMap().apply {
256
+ putArray("networks", Arguments.createArray().apply {
257
+ networks.forEach { network ->
258
+ pushMap(Arguments.createMap().apply {
259
+ putString("ssid", network.ssid)
260
+ putInt("quality", network.quality.toInt())
261
+ putBoolean("isCurrent", network.isCurrent)
262
+ putBoolean("isOpen", network.isOpen)
263
+ })
264
+ }
265
+ })
266
+ currentSsid?.let { putString("currentSsid", it) }
267
+ }
268
+
269
+ internal fun DeviceStatus.toWritableMap(): WritableMap = Arguments.createMap().apply {
270
+ putInt("batteryLevel", batteryLevel)
271
+ batteryMv?.let { putInt("batteryMv", it) }
272
+ putInt("storageTotalMb", storageTotalMb)
273
+ putInt("storageUsedMb", storageUsedMb)
274
+ putString("state", state.toDeviceStateBridgeValue())
275
+ putInt("pendingRecordings", pendingRecordings)
276
+ lastTimeSyncAt?.let { putDouble("lastTimeSyncAtMs", it.toEpochMilli().toDouble()) }
277
+ putInt("signalStrength", signalStrength)
278
+ putMap("flags", flags.toWritableMap())
279
+ putDouble("timestamp", timestamp.toLong().toDouble())
280
+ putString("lteStatus", lteStatus.toLteStatusBridgeValue())
281
+ lteSignalQuality?.let { putInt("lteSignalQuality", it) }
282
+ wifiStatus?.let { putString("wifiStatus", it.toWifiStatusBridgeValue()) }
283
+ modemInfo?.let { putMap("modemInfo", it.toWritableMap()) }
284
+ }
285
+
286
+ internal fun BotaDeviceSDKAndroidProvisioningRequest.toWritableMap(): WritableMap =
287
+ Arguments.createMap().apply {
288
+ putString("requestId", requestId)
289
+ putString("serialNumber", serialNumber)
290
+ putString("nonce", nonce)
291
+ putString("devicePublicKey", devicePublicKey)
292
+ }
293
+
294
+ internal fun BotaDeviceSDKAndroidFactoryResetRequest.toWritableMap(): WritableMap =
295
+ Arguments.createMap().apply {
296
+ putString("requestId", requestId)
297
+ putString("serialNumber", serialNumber)
298
+ putString("nonce", nonce)
299
+ putString("commandId", commandId)
300
+ putDouble("bindingGeneration", bindingGeneration.toDouble())
301
+ }
302
+
303
+ internal fun BotaDeviceSDKAndroidFactoryResetPersistenceRequest.toWritableMap(): WritableMap =
304
+ Arguments.createMap().apply {
305
+ putString("requestId", requestId)
306
+ putDouble("localRecordingsDeleted", localRecordingsDeleted.toDouble())
307
+ }
308
+
309
+ internal fun FactoryResetCompletion.toWritableMap(): WritableMap = Arguments.createMap().apply {
310
+ putString("commandId", commandId)
311
+ putDouble("bindingGeneration", bindingGeneration.toDouble())
312
+ }
313
+
314
+ private fun DeviceFlags.toWritableMap(): WritableMap = Arguments.createMap().apply {
315
+ putBoolean("charging", charging)
316
+ putBoolean("lowBattery", lowBattery)
317
+ putBoolean("storageFull", storageFull)
318
+ putBoolean("wifiConnected", wifiConnected)
319
+ putBoolean("lteConnected", lteConnected)
320
+ putBoolean("syncActive", syncActive)
321
+ }
322
+
323
+ private fun ModemInfo.toWritableMap(): WritableMap = Arguments.createMap().apply {
324
+ imei?.let { putString("imei", it) }
325
+ iccid?.let { putString("iccid", it) }
326
+ operator?.let { putString("operator", it) }
327
+ rat?.let { putString("rat", it) }
328
+ band?.let { putString("band", it) }
329
+ apn?.let { putString("apn", it) }
330
+ simStatus?.let { putString("simStatus", it) }
331
+ csq?.let { putInt("csq", it) }
332
+ ipAddress?.let { putString("ipAddress", it) }
333
+ modemVoltage?.let { putInt("modemVoltage", it) }
334
+ modemFirmware?.let { putString("modemFirmware", it) }
335
+ roaming?.let { putBoolean("roaming", it) }
336
+ }
337
+
338
+ private fun ReadableMap.optionalString(key: String): String? =
339
+ if (hasKey(key) && !isNull(key)) getString(key) else null
340
+
341
+ private fun ReadableMap.requiredInt(key: String): Int {
342
+ val value = getDouble(key)
343
+ require(value.isFinite() && value % 1.0 == 0.0 && value in Int.MIN_VALUE.toDouble()..Int.MAX_VALUE.toDouble()) {
344
+ "$key must be a finite integer"
345
+ }
346
+ return value.toInt()
347
+ }
348
+
349
+ private fun ReadableMap.requiredSafeUnsigned(key: String): ULong {
350
+ val value = getDouble(key)
351
+ require(value.isFinite() && value >= 0 && value <= 9_007_199_254_740_991.0 && value % 1.0 == 0.0) {
352
+ "$key must be a finite non-negative integer"
353
+ }
354
+ return value.toLong().toULong()
355
+ }
356
+
357
+ private fun WireValue<AudioCodec>.toAudioCodecBridgeValue(): String = when (this) {
358
+ is WireValue.Known -> when (value) {
359
+ AudioCodec.Pcm16k -> "pcm_16k"
360
+ AudioCodec.Pcm8k -> "pcm_8k"
361
+ AudioCodec.Opus16k -> "opus_16k"
362
+ AudioCodec.Opus8k -> "opus_8k"
363
+ }
364
+ is WireValue.Unknown -> "opus_16k"
365
+ }
366
+
367
+ private fun FirmwareUpdatePhase.toBridgeValue(): String = when (this) {
368
+ FirmwareUpdatePhase.Downloading -> "downloading"
369
+ FirmwareUpdatePhase.AwaitingDevice -> "awaiting_device"
370
+ FirmwareUpdatePhase.Transferring -> "transferring"
371
+ FirmwareUpdatePhase.Verifying -> "verifying"
372
+ FirmwareUpdatePhase.Rebooting -> "rebooting"
373
+ FirmwareUpdatePhase.Reconnecting -> "reconnecting"
374
+ FirmwareUpdatePhase.Complete -> "complete"
375
+ }
376
+
377
+ private fun String.toDeviceType(): DeviceType? = when (this) {
378
+ "bota_pin" -> DeviceType.BotaPin
379
+ "bota_pin_4g" -> DeviceType.BotaPin4G
380
+ "bota_note" -> DeviceType.BotaNote
381
+ else -> null
382
+ }
383
+
384
+ private fun DeviceType.toBridgeValue(): String = when (this) {
385
+ DeviceType.BotaPin -> "bota_pin"
386
+ DeviceType.BotaPin4G -> "bota_pin_4g"
387
+ DeviceType.BotaNote -> "bota_note"
388
+ is DeviceType.Unknown -> "bota_pin"
389
+ }
390
+
391
+ private fun String.toPairingState(): PairingState? = when (this) {
392
+ "unpaired" -> PairingState.Unpaired
393
+ "pairing" -> PairingState.Pairing
394
+ "paired" -> PairingState.Paired
395
+ "error" -> PairingState.Error
396
+ else -> null
397
+ }
398
+
399
+ internal fun PairingState.toBridgeValue(): String = when (this) {
400
+ PairingState.Unpaired -> "unpaired"
401
+ PairingState.Pairing -> "pairing"
402
+ PairingState.Paired -> "paired"
403
+ PairingState.Error -> "error"
404
+ is PairingState.Unknown -> "unpaired"
405
+ }
406
+
407
+ private fun ConnectionState.toBridgeValue(): String = when (this) {
408
+ ConnectionState.Disconnected -> "disconnected"
409
+ ConnectionState.Connecting -> "connecting"
410
+ ConnectionState.Bonding -> "bonding"
411
+ ConnectionState.Discovering -> "discovering"
412
+ ConnectionState.Connected -> "connected"
413
+ ConnectionState.Disconnecting -> "disconnecting"
414
+ }
415
+
416
+ private fun String.toConnectionState(): ConnectionState? = when (this) {
417
+ "disconnected" -> ConnectionState.Disconnected
418
+ "connecting" -> ConnectionState.Connecting
419
+ "bonding" -> ConnectionState.Bonding
420
+ "discovering" -> ConnectionState.Discovering
421
+ "connected" -> ConnectionState.Connected
422
+ "disconnecting" -> ConnectionState.Disconnecting
423
+ else -> null
424
+ }
425
+
426
+ private fun WireValue<DeviceState>.toDeviceStateBridgeValue(): String = when (this) {
427
+ is WireValue.Known -> when (value) {
428
+ DeviceState.Idle -> "idle"
429
+ DeviceState.Recording -> "recording"
430
+ DeviceState.Syncing -> "syncing"
431
+ DeviceState.Uploading -> "uploading"
432
+ DeviceState.Charging -> "charging"
433
+ DeviceState.LowBattery -> "lowBattery"
434
+ DeviceState.StorageFull -> "storageFull"
435
+ DeviceState.Error -> "error"
436
+ }
437
+ is WireValue.Unknown -> "idle"
438
+ }
439
+
440
+ private fun WireValue<LteStatus>.toLteStatusBridgeValue(): String = when (this) {
441
+ is WireValue.Known -> when (value) {
442
+ LteStatus.Off -> "off"
443
+ LteStatus.Searching -> "searching"
444
+ LteStatus.Registered -> "registered"
445
+ LteStatus.Connected -> "connected"
446
+ LteStatus.Denied -> "denied"
447
+ LteStatus.NoSim -> "noSim"
448
+ LteStatus.Error -> "error"
449
+ LteStatus.LowVoltage -> "lowVoltage"
450
+ LteStatus.Disabled -> "disabled"
451
+ }
452
+ is WireValue.Unknown -> "off"
453
+ }
454
+
455
+ private fun WireValue<WifiRadioStatus>.toWifiStatusBridgeValue(): String = when (this) {
456
+ is WireValue.Known -> when (value) {
457
+ WifiRadioStatus.Off -> "off"
458
+ WifiRadioStatus.Scanning -> "scanning"
459
+ WifiRadioStatus.Connecting -> "connecting"
460
+ WifiRadioStatus.Connected -> "connected"
461
+ WifiRadioStatus.ConnectFailed -> "connectFailed"
462
+ WifiRadioStatus.NoCredentials -> "noCredentials"
463
+ WifiRadioStatus.Disabled -> "disabled"
464
+ WifiRadioStatus.Error -> "error"
465
+ }
466
+ is WireValue.Unknown -> "off"
467
+ }
468
+
469
+ private fun WiFiConnectionStatus.toBridgeValue(): String = when (this) {
470
+ WiFiConnectionStatus.Idle -> "idle"
471
+ WiFiConnectionStatus.Connecting -> "connecting"
472
+ WiFiConnectionStatus.Connected -> "connected"
473
+ WiFiConnectionStatus.Failed -> "failed"
474
+ WiFiConnectionStatus.Disconnected -> "disconnected"
475
+ is WiFiConnectionStatus.Unknown -> "idle"
476
+ }
@@ -0,0 +1,58 @@
1
+ package dev.bota.sdk.reactnative
2
+
3
+ import dev.bota.sdk.BotaDeviceClient
4
+ import dev.bota.sdk.FirmwareImage
5
+ import dev.bota.sdk.model.ConnectedDevice
6
+ import dev.bota.sdk.model.FirmwareUpdateProgress
7
+ import java.util.UUID
8
+ import kotlinx.coroutines.flow.Flow
9
+ import kotlinx.coroutines.flow.collect
10
+ import okhttp3.Request
11
+
12
+ internal interface BotaDeviceSDKAndroidOTAClient {
13
+ fun updateFirmware(
14
+ device: ConnectedDevice,
15
+ image: FirmwareImage,
16
+ ): Flow<FirmwareUpdateProgress>
17
+
18
+ suspend fun cancelCurrentOperation()
19
+ }
20
+
21
+ internal class BotaDeviceSDKSharedAndroidOTAClient(
22
+ private val client: BotaDeviceClient = BotaDeviceClient.shared,
23
+ ) : BotaDeviceSDKAndroidOTAClient {
24
+ override fun updateFirmware(
25
+ device: ConnectedDevice,
26
+ image: FirmwareImage,
27
+ ): Flow<FirmwareUpdateProgress> = client.ota.updateFirmware(device, image)
28
+
29
+ override suspend fun cancelCurrentOperation() {
30
+ client.ota.cancelCurrentOperation()
31
+ }
32
+ }
33
+
34
+ internal class BotaDeviceSDKAndroidOTA(
35
+ private val client: BotaDeviceSDKAndroidOTAClient = BotaDeviceSDKSharedAndroidOTAClient(),
36
+ ) {
37
+ suspend fun updateFirmware(
38
+ device: ConnectedDevice,
39
+ version: String,
40
+ sizeBytes: UInt,
41
+ crc32: UInt,
42
+ url: String,
43
+ onProgress: (FirmwareUpdateProgress) -> Unit,
44
+ ) {
45
+ val image = FirmwareImage(
46
+ version = version,
47
+ sizeBytes = sizeBytes,
48
+ crc32 = crc32,
49
+ downloadId = UUID.randomUUID().leastSignificantBits.toULong(),
50
+ request = Request.Builder().url(url).get().build(),
51
+ )
52
+ client.updateFirmware(device, image).collect(onProgress)
53
+ }
54
+
55
+ suspend fun cancelAll() {
56
+ runCatching { client.cancelCurrentOperation() }
57
+ }
58
+ }