@bota.dev/react-native-app-sdk 2.0.0-beta.5 → 2.0.0-beta.6
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.
- package/README.md +25 -3
- package/generated/codegen-contract.json +2 -2
- package/lib/commonjs/BotaClient.js +3 -0
- package/lib/commonjs/BotaClient.js.map +1 -1
- package/lib/commonjs/clientPresence.js +26 -0
- package/lib/commonjs/clientPresence.js.map +1 -0
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/managers/DeviceManager.js +15 -0
- package/lib/commonjs/managers/DeviceManager.js.map +1 -1
- package/lib/commonjs/sdkIdentity.js +1 -1
- package/lib/commonjs/uploadRecovery.js +68 -0
- package/lib/commonjs/uploadRecovery.js.map +1 -0
- package/lib/module/BotaClient.js +3 -0
- package/lib/module/BotaClient.js.map +1 -1
- package/lib/module/clientPresence.js +22 -0
- package/lib/module/clientPresence.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/managers/DeviceManager.js +15 -0
- package/lib/module/managers/DeviceManager.js.map +1 -1
- package/lib/module/sdkIdentity.js +1 -1
- package/lib/module/uploadRecovery.js +64 -0
- package/lib/module/uploadRecovery.js.map +1 -0
- package/lib/typescript/BotaClient.d.ts +2 -0
- package/lib/typescript/BotaClient.d.ts.map +1 -1
- package/lib/typescript/client.d.ts +2 -2
- package/lib/typescript/client.d.ts.map +1 -1
- package/lib/typescript/clientPresence.d.ts +26 -0
- package/lib/typescript/clientPresence.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +5 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/managers/DeviceManager.d.ts +2 -0
- package/lib/typescript/managers/DeviceManager.d.ts.map +1 -1
- package/lib/typescript/sdkIdentity.d.ts +1 -1
- package/lib/typescript/uploadRecovery.d.ts +27 -0
- package/lib/typescript/uploadRecovery.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/BotaClient.ts +4 -0
- package/src/client.ts +2 -2
- package/src/clientPresence.ts +33 -0
- package/src/index.ts +5 -1
- package/src/managers/DeviceManager.ts +12 -0
- package/src/sdkIdentity.ts +1 -1
- package/src/uploadRecovery.ts +66 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { UploadInfo, UploadRecoveryContext, UploadRecoveryProvider } from './models/Recording';
|
|
2
|
+
|
|
3
|
+
/** A host-owned, authenticated lease. It must permanently reject changed identities. */
|
|
4
|
+
export interface UploadRecoveryBackend {
|
|
5
|
+
scopeKey: string;
|
|
6
|
+
signal: AbortSignal;
|
|
7
|
+
checkScope(): void;
|
|
8
|
+
dispose(): void;
|
|
9
|
+
getRecording(id: string, signal: AbortSignal): Promise<{
|
|
10
|
+
id: string; status: string; metadata?: Record<string, unknown>;
|
|
11
|
+
content_sha256?: string | null; file_size_bytes?: number | null;
|
|
12
|
+
}>;
|
|
13
|
+
getUploadInfo(id: string, relay: boolean, contentType: string | undefined, signal: AbortSignal): Promise<Pick<UploadInfo, 'uploadUrl' | 'relay' | 'contentType'>>;
|
|
14
|
+
completeRecording(id: string, data: { duration_seconds?: number; file_size_bytes: number; content_sha256?: string }, signal: AbortSignal): Promise<unknown>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Build scoped metadata recovery while native SDK storage retains recording bytes.
|
|
18
|
+
* A null host lease parks work until its original account is available.
|
|
19
|
+
* Even an already-uploaded recording requires the exact backend completion ACK.
|
|
20
|
+
*/
|
|
21
|
+
export function createUploadRecoveryProvider(
|
|
22
|
+
openBackend: (task: UploadRecoveryContext) => Promise<UploadRecoveryBackend | null>,
|
|
23
|
+
): UploadRecoveryProvider {
|
|
24
|
+
return async (task) => {
|
|
25
|
+
if (!task.recoveryScope || task.signal.aborted) return null;
|
|
26
|
+
let backend: UploadRecoveryBackend | null = null;
|
|
27
|
+
try {
|
|
28
|
+
backend = await openBackend(task);
|
|
29
|
+
if (!backend) return null;
|
|
30
|
+
const api = backend;
|
|
31
|
+
const check = (signal = task.signal) => {
|
|
32
|
+
api.checkScope();
|
|
33
|
+
if (api.signal.aborted || task.signal.aborted || signal.aborted) throw new Error('Upload recovery cancelled');
|
|
34
|
+
};
|
|
35
|
+
if (api.scopeKey !== task.recoveryScope) { api.dispose(); return null; }
|
|
36
|
+
check();
|
|
37
|
+
const recording = await api.getRecording(task.recordingId, task.signal);
|
|
38
|
+
check();
|
|
39
|
+
if (recording.id !== task.recordingId || (!task.relayUpload && (
|
|
40
|
+
(task.contentSha256 && recording.content_sha256 && task.contentSha256 !== recording.content_sha256) ||
|
|
41
|
+
(task.fileSizeBytes !== undefined && recording.file_size_bytes != null && task.fileSizeBytes !== recording.file_size_bytes)
|
|
42
|
+
))) throw new Error('Upload recovery identity or evidence changed');
|
|
43
|
+
if (!['pending', 'uploaded', 'integrity_failure'].includes(recording.status)) throw new Error('Recording unavailable for recovery');
|
|
44
|
+
const start = Date.parse(String(recording.metadata?.started_at ?? ''));
|
|
45
|
+
const end = Date.parse(String(recording.metadata?.ended_at ?? ''));
|
|
46
|
+
const duration = Number.isFinite(start) && Number.isFinite(end) && end >= start ? Math.floor((end - start) / 1000) : undefined;
|
|
47
|
+
const target = recording.status === 'uploaded' ? { uploadUrl: '' }
|
|
48
|
+
: await api.getUploadInfo(task.recordingId, task.relayUpload, task.contentType, task.signal);
|
|
49
|
+
check();
|
|
50
|
+
return {
|
|
51
|
+
...target, recordingId: task.recordingId, recoveryScope: task.recoveryScope,
|
|
52
|
+
alreadyUploaded: recording.status === 'uploaded', signal: api.signal, dispose: () => api.dispose(),
|
|
53
|
+
complete: async ({ fileSizeBytes, contentSha256, signal }) => {
|
|
54
|
+
check(signal);
|
|
55
|
+
await api.completeRecording(task.recordingId, {
|
|
56
|
+
duration_seconds: duration, file_size_bytes: fileSizeBytes, content_sha256: contentSha256,
|
|
57
|
+
}, signal);
|
|
58
|
+
check(signal);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
} catch {
|
|
62
|
+
backend?.dispose();
|
|
63
|
+
throw new Error('Upload recovery request failed');
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|