@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,212 @@
1
+ import EventEmitter from 'eventemitter3';
2
+
3
+ import type {
4
+ BotaStreamingFinalizeRequest,
5
+ BotaStreamingProgress,
6
+ } from '../client';
7
+ import { getCompatibilityClient } from '../compatibility/runtime';
8
+ import type { ConnectedDevice } from '../models/Device';
9
+ import type {
10
+ StreamingSessionEvents,
11
+ StreamingState,
12
+ StreamingUploadProvider,
13
+ } from '../models/Recording';
14
+
15
+ type ProtocolHandler = unknown;
16
+ type StorageManager = unknown;
17
+
18
+ const terminalHandlers = new WeakMap<StreamingSession, () => void>();
19
+
20
+ export const setStreamingSessionTerminalHandler = (
21
+ session: StreamingSession,
22
+ handler: () => void
23
+ ): void => {
24
+ terminalHandlers.set(session, handler);
25
+ };
26
+
27
+ const createOpaqueId = (): string =>
28
+ 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (value) => {
29
+ const random = Math.floor(Math.random() * 16);
30
+ const nibble = value === 'x' ? random : (random & 0x3) | 0x8;
31
+ return nibble.toString(16);
32
+ });
33
+
34
+ export class StreamingSession extends EventEmitter<StreamingSessionEvents> {
35
+ private readonly client = getCompatibilityClient();
36
+ private readonly sessionId = createOpaqueId();
37
+ private currentState: StreamingState = 'idle';
38
+ private receivedBytes = 0;
39
+ private uploadedChunks = 0;
40
+ private backendRecordingId?: string;
41
+ private relay?: Awaited<
42
+ ReturnType<StreamingUploadProvider['createRecording']>
43
+ >['relay'];
44
+ private started = false;
45
+ private terminal = false;
46
+
47
+ constructor(
48
+ protocolHandler: ProtocolHandler,
49
+ _storageManager: StorageManager,
50
+ private readonly device: ConnectedDevice,
51
+ private readonly recordingUuid: string,
52
+ private readonly uploadProvider: StreamingUploadProvider,
53
+ private readonly chunkSizeKb = 256,
54
+ private readonly flushIntervalMs = 60_000
55
+ ) {
56
+ super();
57
+ void protocolHandler;
58
+ }
59
+
60
+ get state(): StreamingState {
61
+ return this.currentState;
62
+ }
63
+
64
+ get bytesReceived(): number {
65
+ return this.receivedBytes;
66
+ }
67
+
68
+ get chunksUploaded(): number {
69
+ return this.uploadedChunks;
70
+ }
71
+
72
+ get recordingId(): string | undefined {
73
+ return this.backendRecordingId;
74
+ }
75
+
76
+ get isActive(): boolean {
77
+ return this.started && !this.terminal;
78
+ }
79
+
80
+ async start(): Promise<void> {
81
+ if (this.started) throw new Error('StreamingSession has already started');
82
+ this.started = true;
83
+ try {
84
+ const created = await this.uploadProvider.createRecording({
85
+ startedAt: new Date(),
86
+ });
87
+ this.backendRecordingId = created.recordingId;
88
+ this.relay = created.relay;
89
+ const result = await this.client.streaming.startStreaming(
90
+ this.device,
91
+ {
92
+ sessionId: this.sessionId,
93
+ recordingUuid: this.recordingUuid,
94
+ recordingId: created.recordingId,
95
+ chunkSizeBytes:
96
+ Math.min(1024, Math.max(64, this.chunkSizeKb)) * 1024,
97
+ flushIntervalMs: Math.max(0, this.flushIntervalMs),
98
+ },
99
+ {
100
+ onProgress: (progress) => this.handleProgress(progress),
101
+ resolveChunkDestination: async ({ sequence, encrypted }) => {
102
+ if (encrypted) {
103
+ if (!this.relay) {
104
+ throw new Error(
105
+ 'Device delivered encrypted streaming data without an upload relay'
106
+ );
107
+ }
108
+ return {
109
+ url: this.relay.chunkUrl(sequence),
110
+ method: 'POST',
111
+ contentType: 'application/octet-stream',
112
+ bearerToken: this.relay.bearerToken,
113
+ };
114
+ }
115
+ return {
116
+ url: await this.uploadProvider.getChunkUrl(
117
+ created.recordingId,
118
+ sequence
119
+ ),
120
+ method: 'PUT',
121
+ contentType: 'audio/ogg',
122
+ };
123
+ },
124
+ finalize: (metadata) => this.finalize(metadata),
125
+ }
126
+ );
127
+ this.receivedBytes = result.totalBytes;
128
+ this.currentState = 'completed';
129
+ this.terminal = true;
130
+ this.emit('completed', {
131
+ recordingId: created.recordingId,
132
+ totalBytes: result.totalBytes,
133
+ });
134
+ this.releaseTerminal();
135
+ } catch (error) {
136
+ const failure = error instanceof Error ? error : new Error(String(error));
137
+ this.terminal = true;
138
+ if (/disconnect|not connected/i.test(failure.message)) {
139
+ this.currentState = 'disconnected';
140
+ this.emit('disconnected');
141
+ } else {
142
+ this.currentState = 'failed';
143
+ this.emit('error', failure);
144
+ }
145
+ this.releaseTerminal();
146
+ throw failure;
147
+ }
148
+ }
149
+
150
+ abort(): void {
151
+ if (this.terminal) return;
152
+ this.terminal = true;
153
+ this.currentState = 'failed';
154
+ void this.client.streaming.abortStreaming(this.sessionId).catch(() => undefined);
155
+ this.releaseTerminal();
156
+ }
157
+
158
+ private handleProgress(progress: BotaStreamingProgress): void {
159
+ const previousState = this.currentState;
160
+ this.currentState = progress.state as StreamingState;
161
+ this.receivedBytes = progress.bytesReceived;
162
+ this.uploadedChunks = progress.chunksUploaded;
163
+ this.emit('chunk', {
164
+ state: this.currentState,
165
+ bytesReceived: this.receivedBytes,
166
+ chunksUploaded: this.uploadedChunks,
167
+ ...(this.backendRecordingId
168
+ ? { recordingId: this.backendRecordingId }
169
+ : {}),
170
+ });
171
+ if (this.currentState === 'paused') this.emit('paused');
172
+ if (previousState === 'paused' && this.currentState === 'streaming') {
173
+ this.emit('resumed');
174
+ }
175
+ }
176
+
177
+ private async finalize(metadata: BotaStreamingFinalizeRequest): Promise<void> {
178
+ if (!this.backendRecordingId) {
179
+ throw new Error('Streaming recording has not been created');
180
+ }
181
+ if (metadata.encrypted) {
182
+ if (!this.relay) throw new Error('Encrypted stream is missing relay metadata');
183
+ const response = await fetch(this.relay.finalizeUrl, {
184
+ method: 'POST',
185
+ headers: {
186
+ Authorization: `Bearer ${this.relay.bearerToken}`,
187
+ 'Content-Type': 'application/json',
188
+ },
189
+ body: JSON.stringify({
190
+ total_chunks: metadata.totalChunks,
191
+ duration_ms: metadata.durationMs,
192
+ file_size_bytes: metadata.fileSizeBytes,
193
+ }),
194
+ });
195
+ if (!response.ok) {
196
+ throw new Error(`Streaming relay finalize failed (${response.status})`);
197
+ }
198
+ return;
199
+ }
200
+ await this.uploadProvider.finalizeRecording(this.backendRecordingId, {
201
+ totalChunks: metadata.totalChunks,
202
+ durationMs: metadata.durationMs,
203
+ fileSizeBytes: metadata.fileSizeBytes,
204
+ });
205
+ }
206
+
207
+ private releaseTerminal(): void {
208
+ const handler = terminalHandlers.get(this);
209
+ terminalHandlers.delete(this);
210
+ handler?.();
211
+ }
212
+ }
@@ -0,0 +1,36 @@
1
+ import type { DeviceRecording, UploadInfo } from '../models/Recording';
2
+
3
+ export type UploadInfoProvider = (
4
+ recording: DeviceRecording
5
+ ) => Promise<UploadInfo>;
6
+
7
+ export interface FirmwareInfo {
8
+ version: string;
9
+ url: string;
10
+ checksum: string;
11
+ releaseNotes?: string;
12
+ size: number;
13
+ }
14
+
15
+ export type OtaStage =
16
+ | 'checking'
17
+ | 'downloading'
18
+ | 'preparing'
19
+ | 'updating'
20
+ | 'verifying'
21
+ | 'restarting'
22
+ | 'completed'
23
+ | 'failed';
24
+
25
+ export interface OtaProgress {
26
+ stage: OtaStage;
27
+ progress: number;
28
+ bytesTransferred?: number;
29
+ totalBytes?: number;
30
+ error?: string;
31
+ }
32
+
33
+ export type FirmwareDownloadProgressCallback = (
34
+ bytesDownloaded: number,
35
+ totalBytes: number
36
+ ) => void;