@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,180 @@
1
+ package dev.bota.sdk.reactnative
2
+
3
+ import android.content.Context
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.bridge.WritableMap
7
+ import java.io.File
8
+ import java.nio.file.AtomicMoveNotSupportedException
9
+ import java.nio.file.Files
10
+ import java.nio.file.StandardCopyOption
11
+ import java.util.concurrent.ConcurrentHashMap
12
+ import kotlinx.coroutines.Dispatchers
13
+ import kotlinx.coroutines.withContext
14
+ import okhttp3.Call
15
+ import okhttp3.MediaType.Companion.toMediaTypeOrNull
16
+ import okhttp3.OkHttpClient
17
+ import okhttp3.Request
18
+ import okhttp3.RequestBody.Companion.asRequestBody
19
+ import okhttp3.RequestBody.Companion.toRequestBody
20
+
21
+ internal data class BotaRecordingUploadRequest(
22
+ val taskId: String,
23
+ val recordingId: String,
24
+ val localPath: String,
25
+ val uploadUrl: String,
26
+ val uploadToken: String?,
27
+ val completeUrl: String?,
28
+ val contentType: String?,
29
+ val contentSha256: String?,
30
+ val relayUrl: String?,
31
+ val relayBearerToken: String?,
32
+ )
33
+
34
+ internal data class BotaRecordingUploadProgress(
35
+ val taskId: String,
36
+ val completedBytes: Long,
37
+ val totalBytes: Long,
38
+ )
39
+
40
+ internal class BotaDeviceSDKAndroidRecordingUploads(
41
+ private val queueFile: File,
42
+ private val httpClient: OkHttpClient = OkHttpClient(),
43
+ ) {
44
+ constructor(
45
+ context: Context,
46
+ httpClient: OkHttpClient = OkHttpClient(),
47
+ ) : this(File(context.filesDir, "bota-sdk/compat-upload-queue.json"), httpClient)
48
+
49
+ private val calls = ConcurrentHashMap<String, Call>()
50
+
51
+ suspend fun upload(
52
+ upload: BotaRecordingUploadRequest,
53
+ onProgress: (BotaRecordingUploadProgress) -> Unit,
54
+ ): Unit = withContext(Dispatchers.IO) {
55
+ val file = File(upload.localPath)
56
+ require(file.isFile) { "recording file does not exist: ${upload.localPath}" }
57
+ val total = file.length()
58
+ onProgress(BotaRecordingUploadProgress(upload.taskId, 0, total))
59
+ val relay = upload.relayUrl != null
60
+ val request = Request.Builder()
61
+ .url(upload.relayUrl ?: upload.uploadUrl)
62
+ .apply {
63
+ if (relay) {
64
+ post(file.asRequestBody("application/octet-stream".toMediaTypeOrNull()))
65
+ upload.relayBearerToken?.let { header("Authorization", "Bearer $it") }
66
+ } else {
67
+ put(file.asRequestBody((upload.contentType ?: "audio/opus").toMediaTypeOrNull()))
68
+ }
69
+ }
70
+ .build()
71
+ val call = httpClient.newCall(request)
72
+ check(calls.putIfAbsent(upload.taskId, call) == null) {
73
+ "recording upload is already active: ${upload.taskId}"
74
+ }
75
+ try {
76
+ call.execute().use { response ->
77
+ check(response.isSuccessful) {
78
+ "recording upload failed with HTTP ${response.code}"
79
+ }
80
+ }
81
+ if (!relay && upload.completeUrl != null && upload.uploadToken != null) {
82
+ val checksum = upload.contentSha256?.let {
83
+ ",\"content_sha256\":\"${it.jsonEscaped()}\""
84
+ }.orEmpty()
85
+ val body = "{\"recording_id\":\"${upload.recordingId.jsonEscaped()}\"$checksum}"
86
+ val complete = Request.Builder()
87
+ .url(upload.completeUrl)
88
+ .header("Authorization", "Bearer ${upload.uploadToken}")
89
+ .post(body.toRequestBody("application/json".toMediaTypeOrNull()))
90
+ .build()
91
+ val completionCall = httpClient.newCall(complete)
92
+ calls[upload.taskId] = completionCall
93
+ completionCall.execute().use { response ->
94
+ check(response.isSuccessful) {
95
+ "recording completion failed with HTTP ${response.code}"
96
+ }
97
+ }
98
+ }
99
+ onProgress(BotaRecordingUploadProgress(upload.taskId, total, total))
100
+ check(file.delete() || !file.exists()) {
101
+ "uploaded recording file could not be removed"
102
+ }
103
+ } finally {
104
+ calls.remove(upload.taskId)
105
+ }
106
+ }
107
+
108
+ suspend fun cancel(taskId: String) = withContext(Dispatchers.IO) {
109
+ calls.remove(taskId)?.cancel()
110
+ }
111
+
112
+ suspend fun cancelAll() = withContext(Dispatchers.IO) {
113
+ calls.values.forEach(Call::cancel)
114
+ calls.clear()
115
+ }
116
+
117
+ suspend fun loadQueue(): String = withContext(Dispatchers.IO) {
118
+ if (queueFile.isFile) queueFile.readText() else "[]"
119
+ }
120
+
121
+ suspend fun saveQueue(serializedTasks: String): Unit = withContext(Dispatchers.IO) {
122
+ queueFile.parentFile?.mkdirs()
123
+ val temporary = File(queueFile.parentFile, "${queueFile.name}.tmp")
124
+ temporary.writeText(serializedTasks)
125
+ try {
126
+ Files.move(
127
+ temporary.toPath(),
128
+ queueFile.toPath(),
129
+ StandardCopyOption.ATOMIC_MOVE,
130
+ StandardCopyOption.REPLACE_EXISTING,
131
+ )
132
+ } catch (_: AtomicMoveNotSupportedException) {
133
+ Files.move(
134
+ temporary.toPath(),
135
+ queueFile.toPath(),
136
+ StandardCopyOption.REPLACE_EXISTING,
137
+ )
138
+ }
139
+ }
140
+ }
141
+
142
+ internal fun ReadableMap.toRecordingUploadRequest(): BotaRecordingUploadRequest =
143
+ BotaRecordingUploadRequest(
144
+ taskId = requiredString("taskId"),
145
+ recordingId = requiredString("recordingId"),
146
+ localPath = requiredString("localPath"),
147
+ uploadUrl = requiredString("uploadUrl"),
148
+ uploadToken = optionalString("uploadToken"),
149
+ completeUrl = optionalString("completeUrl"),
150
+ contentType = optionalString("contentType"),
151
+ contentSha256 = optionalString("contentSha256"),
152
+ relayUrl = optionalString("relayUrl"),
153
+ relayBearerToken = optionalString("relayBearerToken"),
154
+ )
155
+
156
+ internal fun BotaRecordingUploadProgress.toWritableMap(): WritableMap =
157
+ Arguments.createMap().apply {
158
+ putString("taskId", taskId)
159
+ putDouble("completedBytes", completedBytes.toDouble())
160
+ putDouble("totalBytes", totalBytes.toDouble())
161
+ }
162
+
163
+ private fun ReadableMap.requiredString(key: String): String =
164
+ getString(key) ?: error("$key is required")
165
+
166
+ private fun ReadableMap.optionalString(key: String): String? =
167
+ if (hasKey(key) && !isNull(key)) getString(key) else null
168
+
169
+ private fun String.jsonEscaped(): String = buildString(length) {
170
+ for (character in this@jsonEscaped) {
171
+ when (character) {
172
+ '\\' -> append("\\\\")
173
+ '"' -> append("\\\"")
174
+ '\n' -> append("\\n")
175
+ '\r' -> append("\\r")
176
+ '\t' -> append("\\t")
177
+ else -> append(character)
178
+ }
179
+ }
180
+ }