@bota.dev/web-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.
- package/LICENSE +21 -0
- package/README.md +517 -0
- package/dist/capabilities.d.ts +8 -0
- package/dist/capabilities.js +21 -0
- package/dist/client.d.ts +39 -0
- package/dist/client.js +153 -0
- package/dist/controlManager.d.ts +38 -0
- package/dist/controlManager.js +344 -0
- package/dist/core.d.ts +698 -0
- package/dist/core.js +13 -0
- package/dist/deviceManager.d.ts +52 -0
- package/dist/deviceManager.js +491 -0
- package/dist/encryptedUploadV2Host.d.ts +239 -0
- package/dist/encryptedUploadV2Host.js +2136 -0
- package/dist/errors.d.ts +24 -0
- package/dist/errors.js +230 -0
- package/dist/gatt.d.ts +39 -0
- package/dist/gatt.js +57 -0
- package/dist/generated/bota_device_sdk_core.d.ts +202 -0
- package/dist/generated/bota_device_sdk_core.js +1025 -0
- package/dist/generated/bota_device_sdk_core_bg.wasm +0 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +2 -0
- package/dist/indexedDbWorkflowStore.d.ts +52 -0
- package/dist/indexedDbWorkflowStore.js +763 -0
- package/dist/logManager.d.ts +24 -0
- package/dist/logManager.js +205 -0
- package/dist/models.d.ts +217 -0
- package/dist/models.js +1 -0
- package/dist/opfsBlobStore.d.ts +12 -0
- package/dist/opfsBlobStore.js +250 -0
- package/dist/otaManager.d.ts +49 -0
- package/dist/otaManager.js +951 -0
- package/dist/providerCancellation.d.ts +2 -0
- package/dist/providerCancellation.js +23 -0
- package/dist/providers.d.ts +138 -0
- package/dist/providers.js +1 -0
- package/dist/provisioningManager.d.ts +48 -0
- package/dist/provisioningManager.js +753 -0
- package/dist/recordingManager.d.ts +53 -0
- package/dist/recordingManager.js +1397 -0
- package/dist/storage.d.ts +103 -0
- package/dist/storage.js +60 -0
- package/dist/transport.d.ts +33 -0
- package/dist/transport.js +8 -0
- package/dist/wasmCore.d.ts +3 -0
- package/dist/wasmCore.js +1651 -0
- package/dist/webBluetoothTransport.d.ts +23 -0
- package/dist/webBluetoothTransport.js +369 -0
- package/dist/wifiManager.d.ts +54 -0
- package/dist/wifiManager.js +528 -0
- package/dist/workflowRuntime.d.ts +115 -0
- package/dist/workflowRuntime.js +1508 -0
- package/package.json +46 -0
package/dist/wasmCore.js
ADDED
|
@@ -0,0 +1,1651 @@
|
|
|
1
|
+
import initWasm, { WebCoreBridge as GeneratedWebCoreBridge, WebIntegrityHasher as GeneratedWebIntegrityHasher, decodeConnectionSettings as decodeGeneratedConnectionSettings, decodeDeprovisionResult as decodeGeneratedDeprovisionResult, decodeDeviceStatus as decodeGeneratedDeviceStatus, decodeEncryptedUploadV2Capabilities as decodeGeneratedCapabilities, decodeEncryptedUploadV2SignedBlobResult as decodeGeneratedEncryptedUploadV2SignedBlobResult, decodeEncryptedUploadV2Status as decodeGeneratedEncryptedUploadV2Status, decodeEncryptedUploadV2Transfer as decodeGeneratedEncryptedUploadV2Transfer, decodeRecordingControlResult as decodeGeneratedRecordingControlResult, decodeRecordingList as decodeGeneratedRecordingList, decodeWiFiConfigResult as decodeGeneratedWiFiConfigResult, decodeWiFiScanUpdate as decodeGeneratedWiFiScanUpdate, decodeWiFiStatus as decodeGeneratedWiFiStatus, encodeConnectionSettings as encodeGeneratedConnectionSettings, encodeDeprovisionCommand as encodeGeneratedDeprovisionCommand, encodeEncryptedUploadV2SignedBlob as encodeGeneratedEncryptedUploadV2SignedBlob, encodeEncryptedUploadV2Transfer as encodeGeneratedEncryptedUploadV2Transfer, encodeRecordingConfirm as encodeGeneratedRecordingConfirm, encodeRecordingControlCommand as encodeGeneratedRecordingControlCommand, encodeRecordingListCommand as encodeGeneratedRecordingListCommand, encodeWiFiCredentials as encodeGeneratedWiFiCredentials, encodeWiFiGrant as encodeGeneratedWiFiGrant, encodeWiFiScanCommand as encodeGeneratedWiFiScanCommand, } from './generated/bota_device_sdk_core.js';
|
|
2
|
+
import { createCoreLoader } from "./core.js";
|
|
3
|
+
import { BotaSDKError, normalizeCoreError, normalizePrivateCoreError, } from "./errors.js";
|
|
4
|
+
export async function createWasmCore(moduleInput) {
|
|
5
|
+
try {
|
|
6
|
+
if (moduleInput === undefined) {
|
|
7
|
+
await initWasm();
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
await initWasm({ module_or_path: moduleInput });
|
|
11
|
+
}
|
|
12
|
+
return new WasmCoreAdapter(new GeneratedWebCoreBridge());
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw normalizeCoreError(error, 'initialize');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const loadDefaultCore = createCoreLoader(() => createWasmCore());
|
|
19
|
+
class WasmCoreAdapter {
|
|
20
|
+
generated;
|
|
21
|
+
constructor(generated) {
|
|
22
|
+
this.generated = generated;
|
|
23
|
+
}
|
|
24
|
+
startExactConnection(input) {
|
|
25
|
+
try {
|
|
26
|
+
return normalizeEffects(this.generated.startExactConnection(input.expectedSerialNumber, input.peripheralId, input.name, input.cancellationId));
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw normalizeCoreError(error, 'connect');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
startReconnect(input) {
|
|
33
|
+
try {
|
|
34
|
+
return normalizeEffects(this.generated.startReconnect({
|
|
35
|
+
expected_serial: input.expectedSerialNumber,
|
|
36
|
+
hint: rawReconnectHint(input.hint),
|
|
37
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
throw normalizePrivateCoreError(error, 'reconnect');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
startProvisioning(input) {
|
|
45
|
+
try {
|
|
46
|
+
return normalizeEffects(this.generated.startProvisioning({
|
|
47
|
+
serial_number: input.serialNumber,
|
|
48
|
+
material_id: input.materialId,
|
|
49
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw normalizePrivateCoreError(error, 'provision');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
startRecordingTransfer(input) {
|
|
57
|
+
try {
|
|
58
|
+
return normalizeEffects(this.generated.startRecordingTransfer({
|
|
59
|
+
serial_number: input.serialNumber,
|
|
60
|
+
recording_uuid: input.recordingUuid,
|
|
61
|
+
sink_id: input.sinkId,
|
|
62
|
+
total_units: input.totalUnits,
|
|
63
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw normalizePrivateCoreError(error, 'transfer_recording');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
startEncryptedUploadV2(input) {
|
|
71
|
+
try {
|
|
72
|
+
return normalizeEffects(this.generated.startEncryptedUploadV2({
|
|
73
|
+
serial_number: input.serialNumber,
|
|
74
|
+
recording_uuid: input.recordingUuid,
|
|
75
|
+
recording_generation: input.recordingGeneration,
|
|
76
|
+
storage_format: input.storageFormat,
|
|
77
|
+
upload_session_id: input.uploadSessionId,
|
|
78
|
+
owner_revision: input.ownerRevision,
|
|
79
|
+
transport_session_id: input.transportSessionId,
|
|
80
|
+
material_id: input.materialId,
|
|
81
|
+
sink_id: input.sinkId,
|
|
82
|
+
policy: rawUploadPolicy(input.policy),
|
|
83
|
+
capabilities: rawCapabilities(input.capabilities),
|
|
84
|
+
window_packets: input.windowPackets,
|
|
85
|
+
data_payload_bytes: input.dataPayloadBytes,
|
|
86
|
+
ciphertext_length: input.ciphertextLength,
|
|
87
|
+
ciphertext_sha256: rawBytes(input.ciphertextSha256),
|
|
88
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw normalizePrivateCoreError(error, 'transfer_recording');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
startFirmwareUpdate(input) {
|
|
96
|
+
try {
|
|
97
|
+
return normalizeEffects(this.generated.startFirmwareUpdate({
|
|
98
|
+
serial_number: input.serialNumber,
|
|
99
|
+
version: input.version,
|
|
100
|
+
size_bytes: input.sizeBytes,
|
|
101
|
+
crc32: input.crc32,
|
|
102
|
+
download_id: input.downloadId,
|
|
103
|
+
reconnect_hint: rawReconnectHint(input.reconnectHint),
|
|
104
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw normalizePrivateCoreError(error, 'update_firmware');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
startDeviceLogs(input) {
|
|
112
|
+
try {
|
|
113
|
+
return normalizeEffects(this.generated.startDeviceLogs({
|
|
114
|
+
serial_number: input.serialNumber,
|
|
115
|
+
cancellation_id: rawBytes(input.cancellationId),
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw normalizePrivateCoreError(error, 'read_device_logs');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
cancel(cancellationId) {
|
|
123
|
+
try {
|
|
124
|
+
return normalizeEffects(this.generated.cancel(cancellationId));
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
throw normalizePrivateCoreError(error, 'unknown');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
dispatch(event) {
|
|
131
|
+
const rawEvent = rawHostEvent(event);
|
|
132
|
+
try {
|
|
133
|
+
return normalizeEffects(this.generated.dispatch(rawEvent));
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw normalizePrivateCoreError(error, 'unknown');
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
scrubBridgeBytes(rawEvent);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
status() {
|
|
143
|
+
try {
|
|
144
|
+
return normalizeStatus(this.generated.status());
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
throw normalizePrivateCoreError(error, 'unknown');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
decodeDeviceStatus(bytes) {
|
|
151
|
+
try {
|
|
152
|
+
return normalizeDeviceStatus(decodeGeneratedDeviceStatus(bytes));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw normalizeCoreError(error, 'read_snapshot');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
decodeEncryptedUploadV2Capabilities(bytes) {
|
|
159
|
+
try {
|
|
160
|
+
return normalizeCapabilities(decodeGeneratedCapabilities(bytes));
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
throw normalizeCoreError(error, 'read_snapshot');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
supportsEncryptedUploadV2Batch(capabilities) {
|
|
167
|
+
try {
|
|
168
|
+
return this.generated.supportsEncryptedUploadV2Batch(rawCapabilities(capabilities));
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw normalizeCoreError(error, 'transfer_recording');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
validateEncryptedUploadV2Profile(capabilities, recordingGeneration, storageFormat) {
|
|
175
|
+
try {
|
|
176
|
+
this.generated.validateEncryptedUploadV2Profile(rawCapabilities(capabilities), recordingGeneration, storageFormat);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
throw normalizeCoreError(error, 'transfer_recording');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
decodeRecordingList(bytesValue) {
|
|
183
|
+
try {
|
|
184
|
+
return normalizeRecordingList(decodeGeneratedRecordingList(bytesValue));
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
encodeRecordingListCommand() {
|
|
191
|
+
try {
|
|
192
|
+
return bytes(encodeGeneratedRecordingListCommand());
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
encodeRecordingConfirm(recordingUuid) {
|
|
199
|
+
try {
|
|
200
|
+
return bytes(encodeGeneratedRecordingConfirm(recordingUuid));
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
encodeDeprovisionCommand() {
|
|
207
|
+
try {
|
|
208
|
+
return bytes(encodeGeneratedDeprovisionCommand());
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
decodeDeprovisionResult(bytesValue) {
|
|
215
|
+
try {
|
|
216
|
+
return normalizeOperationResult(decodeGeneratedDeprovisionResult(bytesValue));
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
decodeConnectionSettings(bytesValue) {
|
|
223
|
+
try {
|
|
224
|
+
return normalizeConnectionSettings(decodeGeneratedConnectionSettings(bytesValue));
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
encodeConnectionSettings(settings, model) {
|
|
231
|
+
try {
|
|
232
|
+
return bytes(encodeGeneratedConnectionSettings(settings, model));
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
encodeWiFiGrant(grant, capacity) {
|
|
239
|
+
try {
|
|
240
|
+
return bytes(encodeGeneratedWiFiGrant(grant, capacity));
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
encodeWiFiCredentials(ssid, password) {
|
|
247
|
+
try {
|
|
248
|
+
return bytes(encodeGeneratedWiFiCredentials(ssid, password));
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
encodeWiFiScanCommand() {
|
|
255
|
+
try {
|
|
256
|
+
return bytes(encodeGeneratedWiFiScanCommand());
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
decodeWiFiConfigResult(bytesValue) {
|
|
263
|
+
try {
|
|
264
|
+
return normalizeOperationResult(decodeGeneratedWiFiConfigResult(bytesValue));
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
decodeWiFiStatus(bytesValue) {
|
|
271
|
+
try {
|
|
272
|
+
return normalizeWiFiStatus(decodeGeneratedWiFiStatus(bytesValue));
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
decodeWiFiScanUpdate(bytesValue) {
|
|
279
|
+
try {
|
|
280
|
+
return normalizeWiFiScanUpdate(decodeGeneratedWiFiScanUpdate(bytesValue));
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
encodeRecordingControlCommand(action) {
|
|
287
|
+
try {
|
|
288
|
+
return bytes(encodeGeneratedRecordingControlCommand(action));
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
decodeRecordingControlResult(bytesValue) {
|
|
295
|
+
try {
|
|
296
|
+
return normalizeOperationResult(decodeGeneratedRecordingControlResult(bytesValue));
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
decodeEncryptedUploadV2Transfer(bytesValue) {
|
|
303
|
+
try {
|
|
304
|
+
return normalizeEncryptedUploadV2Transfer(decodeGeneratedEncryptedUploadV2Transfer(bytesValue));
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
encodeEncryptedUploadV2Transfer(frame) {
|
|
311
|
+
try {
|
|
312
|
+
return bytes(encodeGeneratedEncryptedUploadV2Transfer(rawCodecFrame(frame)));
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
decodeEncryptedUploadV2Status(bytesValue) {
|
|
319
|
+
try {
|
|
320
|
+
return normalizeEncryptedUploadV2Status(decodeGeneratedEncryptedUploadV2Status(bytesValue));
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
encodeEncryptedUploadV2SignedBlob(frame) {
|
|
327
|
+
try {
|
|
328
|
+
return bytes(encodeGeneratedEncryptedUploadV2SignedBlob(rawCodecFrame(frame)));
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
throw normalizePrivateCoreError(error, 'encode');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
decodeEncryptedUploadV2SignedBlobResult(bytesValue) {
|
|
335
|
+
try {
|
|
336
|
+
const value = record(decodeGeneratedEncryptedUploadV2SignedBlobResult(bytesValue));
|
|
337
|
+
return {
|
|
338
|
+
blobKind: signedBlobKind(number(value.kind)),
|
|
339
|
+
writeId: number(value.writeId),
|
|
340
|
+
result: number(value.result),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
throw normalizePrivateCoreError(error, 'decode');
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
createIntegrityHasher() {
|
|
348
|
+
return new GeneratedWebIntegrityHasher();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function rawReconnectHint(hint) {
|
|
352
|
+
return {
|
|
353
|
+
stored_peripheral_id: hint.storedPeripheralId ?? undefined,
|
|
354
|
+
advertised_address: hint.advertisedAddress ?? undefined,
|
|
355
|
+
stored_name: hint.storedName ?? undefined,
|
|
356
|
+
scan_timeout_ms: hint.scanTimeoutMs,
|
|
357
|
+
connection_timeout_ms: hint.connectionTimeoutMs,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
function rawCapabilities(capabilities) {
|
|
361
|
+
return {
|
|
362
|
+
flags: capabilities.flags,
|
|
363
|
+
maximum_signed_blob_bytes: capabilities.maximumSignedBlobBytes,
|
|
364
|
+
maximum_manifest_bytes: capabilities.maximumManifestBytes,
|
|
365
|
+
maximum_data_payload_bytes: capabilities.maximumDataPayloadBytes,
|
|
366
|
+
maximum_window_packets: capabilities.maximumWindowPackets,
|
|
367
|
+
durable_checkpoint_interval_blocks: capabilities.durableCheckpointIntervalBlocks,
|
|
368
|
+
maximum_missing_sequences: capabilities.maximumMissingSequences,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function signedBlobKind(value) {
|
|
372
|
+
if (value === 1)
|
|
373
|
+
return 'authorization';
|
|
374
|
+
if (value === 2)
|
|
375
|
+
return 'receipt';
|
|
376
|
+
throw internalBridgeError();
|
|
377
|
+
}
|
|
378
|
+
function rawUploadPolicy(policy) {
|
|
379
|
+
switch (policy) {
|
|
380
|
+
case 'legacy_allowed': return 'LegacyAllowed';
|
|
381
|
+
case 'v2_preferred': return 'V2Preferred';
|
|
382
|
+
case 'v2_required': return 'V2Required';
|
|
383
|
+
default: throw internalBridgeError();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function rawCodecFrame(value) {
|
|
387
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, rawCodecValue(item)]));
|
|
388
|
+
}
|
|
389
|
+
function rawCodecValue(value) {
|
|
390
|
+
if (value instanceof Uint8Array)
|
|
391
|
+
return rawBytes(value);
|
|
392
|
+
if (Array.isArray(value))
|
|
393
|
+
return value.map(rawCodecValue);
|
|
394
|
+
if (value !== null && typeof value === 'object')
|
|
395
|
+
return rawCodecFrame(value);
|
|
396
|
+
return value;
|
|
397
|
+
}
|
|
398
|
+
function normalizeRecordingList(value) {
|
|
399
|
+
if (!Array.isArray(value))
|
|
400
|
+
throw internalBridgeError();
|
|
401
|
+
return value.map((item) => {
|
|
402
|
+
const recording = record(item);
|
|
403
|
+
const codec = stringUnion(recording.codec, [
|
|
404
|
+
'pcm_16k',
|
|
405
|
+
'pcm_8k',
|
|
406
|
+
'opus_16k',
|
|
407
|
+
'opus_8k',
|
|
408
|
+
'unknown',
|
|
409
|
+
]);
|
|
410
|
+
const normalized = {
|
|
411
|
+
uuid: string(recording.uuid),
|
|
412
|
+
startedAtTimestampSeconds: number(recording.startedAtTimestampSeconds),
|
|
413
|
+
durationMilliseconds: bigint(recording.durationMilliseconds),
|
|
414
|
+
fileSizeBytes: bigint(recording.fileSizeBytes),
|
|
415
|
+
codec,
|
|
416
|
+
encrypted: boolean(recording.encrypted),
|
|
417
|
+
};
|
|
418
|
+
const codecRaw = optionalNumber(recording.codecRaw);
|
|
419
|
+
if (codecRaw !== null)
|
|
420
|
+
normalized.codecRaw = byte(codecRaw);
|
|
421
|
+
return normalized;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
function normalizeOperationResult(value) {
|
|
425
|
+
const raw = record(value);
|
|
426
|
+
const result = { success: boolean(raw.success) };
|
|
427
|
+
const error = optionalString(raw.error);
|
|
428
|
+
const errorRaw = optionalNumber(raw.errorRaw);
|
|
429
|
+
if (error !== null)
|
|
430
|
+
result.error = error;
|
|
431
|
+
if (errorRaw !== null)
|
|
432
|
+
result.errorRaw = byte(errorRaw);
|
|
433
|
+
return result;
|
|
434
|
+
}
|
|
435
|
+
function normalizeConnectionSettings(value) {
|
|
436
|
+
const raw = record(value);
|
|
437
|
+
const enabled = record(raw.enabledConnections);
|
|
438
|
+
const heartbeat = record(raw.heartbeatEnabledConnections);
|
|
439
|
+
const power = record(raw.powerManagement);
|
|
440
|
+
if (!Array.isArray(raw.uploadNetworkPreference))
|
|
441
|
+
throw internalBridgeError();
|
|
442
|
+
return {
|
|
443
|
+
enabledConnections: {
|
|
444
|
+
wifi: boolean(enabled.wifi),
|
|
445
|
+
cellular: boolean(enabled.cellular),
|
|
446
|
+
},
|
|
447
|
+
heartbeatEnabledConnections: {
|
|
448
|
+
wifi: boolean(heartbeat.wifi),
|
|
449
|
+
cellular: boolean(heartbeat.cellular),
|
|
450
|
+
},
|
|
451
|
+
uploadNetworkPreference: raw.uploadNetworkPreference.map((connection) => stringUnion(connection, ['wifi', 'ble', 'cellular', 'unknown'])),
|
|
452
|
+
powerManagement: {
|
|
453
|
+
cellularIdleTimeoutSeconds: number(power.cellularIdleTimeoutSeconds),
|
|
454
|
+
wifiIdleTimeoutSeconds: number(power.wifiIdleTimeoutSeconds),
|
|
455
|
+
},
|
|
456
|
+
streamingEnabled: boolean(raw.streamingEnabled),
|
|
457
|
+
streamingFlushIntervalSeconds: byte(raw.streamingFlushIntervalSeconds),
|
|
458
|
+
supportedVersion: boolean(raw.supportedVersion),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function normalizeWiFiStatus(value) {
|
|
462
|
+
const raw = record(value);
|
|
463
|
+
const result = {
|
|
464
|
+
status: stringUnion(raw.status, [
|
|
465
|
+
'idle',
|
|
466
|
+
'connecting',
|
|
467
|
+
'connected',
|
|
468
|
+
'failed',
|
|
469
|
+
'disconnected',
|
|
470
|
+
'unknown',
|
|
471
|
+
]),
|
|
472
|
+
statusRaw: byte(raw.statusRaw),
|
|
473
|
+
};
|
|
474
|
+
const signalStrength = optionalNumber(raw.signalStrength);
|
|
475
|
+
const ssid = optionalString(raw.ssid);
|
|
476
|
+
const lastError = optionalString(raw.lastError);
|
|
477
|
+
if (signalStrength !== null)
|
|
478
|
+
result.signalStrength = byte(signalStrength);
|
|
479
|
+
if (ssid !== null)
|
|
480
|
+
result.ssid = ssid;
|
|
481
|
+
if (lastError !== null)
|
|
482
|
+
result.lastError = lastError;
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
function normalizeWiFiScanUpdate(value) {
|
|
486
|
+
const raw = record(value);
|
|
487
|
+
const kind = string(raw.kind);
|
|
488
|
+
if (kind === 'pending') {
|
|
489
|
+
return { kind, statusRaw: byte(raw.statusRaw) };
|
|
490
|
+
}
|
|
491
|
+
if (kind === 'done') {
|
|
492
|
+
if (!Array.isArray(raw.networks))
|
|
493
|
+
throw internalBridgeError();
|
|
494
|
+
return {
|
|
495
|
+
kind,
|
|
496
|
+
networks: raw.networks.map((item) => {
|
|
497
|
+
const network = record(item);
|
|
498
|
+
return {
|
|
499
|
+
ssid: string(network.ssid),
|
|
500
|
+
quality: byte(network.quality),
|
|
501
|
+
isCurrent: boolean(network.isCurrent),
|
|
502
|
+
isOpen: boolean(network.isOpen),
|
|
503
|
+
};
|
|
504
|
+
}),
|
|
505
|
+
currentSsid: optionalString(raw.currentSsid),
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
throw internalBridgeError();
|
|
509
|
+
}
|
|
510
|
+
function normalizeEncryptedUploadV2Status(value) {
|
|
511
|
+
const raw = record(value);
|
|
512
|
+
return {
|
|
513
|
+
phase: byte(raw.phase),
|
|
514
|
+
result: u16(raw.result),
|
|
515
|
+
transportSessionId: bigint(raw.transportSessionId),
|
|
516
|
+
durableCiphertextBytes: bigint(raw.durableCiphertextBytes),
|
|
517
|
+
progressPercent: byte(raw.progressPercent),
|
|
518
|
+
transportProfile: byte(raw.transportProfile),
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function normalizeEncryptedUploadV2Transfer(value) {
|
|
522
|
+
const raw = record(value);
|
|
523
|
+
const common = {
|
|
524
|
+
flags: u16(raw.flags),
|
|
525
|
+
transportSessionId: bigint(raw.transportSessionId),
|
|
526
|
+
};
|
|
527
|
+
switch (string(raw.kind)) {
|
|
528
|
+
case 'list':
|
|
529
|
+
return { kind: 'list', ...common };
|
|
530
|
+
case 'recording_entry':
|
|
531
|
+
return {
|
|
532
|
+
kind: 'recording_entry',
|
|
533
|
+
...common,
|
|
534
|
+
recordingUuid: string(raw.recordingUuid),
|
|
535
|
+
recordingGeneration: u32(raw.recordingGeneration),
|
|
536
|
+
storageFormat: byte(raw.storageFormat),
|
|
537
|
+
completionState: byte(raw.completionState),
|
|
538
|
+
startedAt: bigint(raw.startedAt),
|
|
539
|
+
durationSeconds: u32(raw.durationSeconds),
|
|
540
|
+
plaintextLength: bigint(raw.plaintextLength),
|
|
541
|
+
ciphertextLength: bigint(raw.ciphertextLength),
|
|
542
|
+
ciphertextSha256: bytes(raw.ciphertextSha256, 32),
|
|
543
|
+
};
|
|
544
|
+
case 'recording_list_end':
|
|
545
|
+
return {
|
|
546
|
+
kind: 'recording_list_end',
|
|
547
|
+
...common,
|
|
548
|
+
count: u32(raw.count),
|
|
549
|
+
listRevision: u32(raw.listRevision),
|
|
550
|
+
listSha256: bytes(raw.listSha256, 32),
|
|
551
|
+
};
|
|
552
|
+
case 'start':
|
|
553
|
+
return {
|
|
554
|
+
kind: 'start',
|
|
555
|
+
...common,
|
|
556
|
+
uploadSessionUuid: string(raw.uploadSessionUuid),
|
|
557
|
+
recordingUuid: string(raw.recordingUuid),
|
|
558
|
+
recordingGeneration: u32(raw.recordingGeneration),
|
|
559
|
+
authorizationSha256: bytes(raw.authorizationSha256, 32),
|
|
560
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
561
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
562
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
563
|
+
windowPackets: u16(raw.windowPackets),
|
|
564
|
+
dataPayloadBytes: u16(raw.dataPayloadBytes),
|
|
565
|
+
};
|
|
566
|
+
case 'start_ack':
|
|
567
|
+
return {
|
|
568
|
+
kind: 'start_ack',
|
|
569
|
+
...common,
|
|
570
|
+
uploadSessionUuid: string(raw.uploadSessionUuid),
|
|
571
|
+
recordingUuid: string(raw.recordingUuid),
|
|
572
|
+
recordingGeneration: u32(raw.recordingGeneration),
|
|
573
|
+
ciphertextLength: bigint(raw.ciphertextLength),
|
|
574
|
+
ciphertextSha256: bytes(raw.ciphertextSha256, 32),
|
|
575
|
+
windowPackets: u16(raw.windowPackets),
|
|
576
|
+
dataPayloadBytes: u16(raw.dataPayloadBytes),
|
|
577
|
+
checkpointIntervalBlocks: u32(raw.checkpointIntervalBlocks),
|
|
578
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
579
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
580
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
581
|
+
};
|
|
582
|
+
case 'data':
|
|
583
|
+
return {
|
|
584
|
+
kind: 'data',
|
|
585
|
+
...common,
|
|
586
|
+
sequence: u32(raw.sequence),
|
|
587
|
+
offset: bigint(raw.offset),
|
|
588
|
+
data: bytes(raw.data),
|
|
589
|
+
};
|
|
590
|
+
case 'window_end':
|
|
591
|
+
return {
|
|
592
|
+
kind: 'window_end',
|
|
593
|
+
...common,
|
|
594
|
+
windowIndex: u32(raw.windowIndex),
|
|
595
|
+
firstSequence: u32(raw.firstSequence),
|
|
596
|
+
lastSequence: u32(raw.lastSequence),
|
|
597
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
598
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
599
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
600
|
+
};
|
|
601
|
+
case 'window_ack':
|
|
602
|
+
return {
|
|
603
|
+
kind: 'window_ack',
|
|
604
|
+
...common,
|
|
605
|
+
windowIndex: u32(raw.windowIndex),
|
|
606
|
+
highestContiguousSequence: u32(raw.highestContiguousSequence),
|
|
607
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
608
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
609
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
610
|
+
missingSequences: numbers(raw.missingSequences).map(u32Value),
|
|
611
|
+
};
|
|
612
|
+
case 'manifest_chunk':
|
|
613
|
+
return {
|
|
614
|
+
kind: 'manifest_chunk',
|
|
615
|
+
...common,
|
|
616
|
+
totalManifestLength: u16(raw.totalManifestLength),
|
|
617
|
+
chunkOffset: u16(raw.chunkOffset),
|
|
618
|
+
manifestSha256: bytes(raw.manifestSha256, 32),
|
|
619
|
+
chunk: bytes(raw.chunk),
|
|
620
|
+
};
|
|
621
|
+
case 'eof':
|
|
622
|
+
return {
|
|
623
|
+
kind: 'eof',
|
|
624
|
+
...common,
|
|
625
|
+
finalSequence: u32(raw.finalSequence),
|
|
626
|
+
blockCount: u32(raw.blockCount),
|
|
627
|
+
ciphertextLength: bigint(raw.ciphertextLength),
|
|
628
|
+
ciphertextSha256: bytes(raw.ciphertextSha256, 32),
|
|
629
|
+
manifestSha256: bytes(raw.manifestSha256, 32),
|
|
630
|
+
};
|
|
631
|
+
case 'resume_request':
|
|
632
|
+
return normalizeResumeFrame('resume_request', raw, common);
|
|
633
|
+
case 'resume_accept':
|
|
634
|
+
return normalizeResumeFrame('resume_accept', raw, common);
|
|
635
|
+
case 'resume_reject':
|
|
636
|
+
return {
|
|
637
|
+
kind: 'resume_reject',
|
|
638
|
+
...common,
|
|
639
|
+
reason: u16(raw.reason),
|
|
640
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
641
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
642
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
643
|
+
};
|
|
644
|
+
case 'confirm':
|
|
645
|
+
return {
|
|
646
|
+
kind: 'confirm',
|
|
647
|
+
...common,
|
|
648
|
+
uploadSessionUuid: string(raw.uploadSessionUuid),
|
|
649
|
+
recordingUuid: string(raw.recordingUuid),
|
|
650
|
+
recordingGeneration: u32(raw.recordingGeneration),
|
|
651
|
+
ownerRevision: u32(raw.ownerRevision),
|
|
652
|
+
receiptSha256: bytes(raw.receiptSha256, 32),
|
|
653
|
+
};
|
|
654
|
+
case 'abort':
|
|
655
|
+
return { kind: 'abort', ...common, reason: u16(raw.reason) };
|
|
656
|
+
case 'error':
|
|
657
|
+
return {
|
|
658
|
+
kind: 'error',
|
|
659
|
+
...common,
|
|
660
|
+
result: u16(raw.result),
|
|
661
|
+
failedMessageType: byte(raw.failedMessageType),
|
|
662
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
663
|
+
};
|
|
664
|
+
default:
|
|
665
|
+
throw internalBridgeError();
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function normalizeResumeFrame(kind, raw, common) {
|
|
669
|
+
return {
|
|
670
|
+
kind,
|
|
671
|
+
...common,
|
|
672
|
+
uploadSessionUuid: string(raw.uploadSessionUuid),
|
|
673
|
+
recordingUuid: string(raw.recordingUuid),
|
|
674
|
+
recordingGeneration: u32(raw.recordingGeneration),
|
|
675
|
+
checkpointRevision: u32(raw.checkpointRevision),
|
|
676
|
+
nextCiphertextOffset: bigint(raw.nextCiphertextOffset),
|
|
677
|
+
prefixSha256: bytes(raw.prefixSha256, 32),
|
|
678
|
+
windowPackets: u16(raw.windowPackets),
|
|
679
|
+
dataPayloadBytes: u16(raw.dataPayloadBytes),
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function normalizeEffects(value) {
|
|
683
|
+
try {
|
|
684
|
+
if (!Array.isArray(value))
|
|
685
|
+
throw internalBridgeError();
|
|
686
|
+
return value.map((item) => {
|
|
687
|
+
const request = record(item);
|
|
688
|
+
return {
|
|
689
|
+
requestId: bigint(request.request_id),
|
|
690
|
+
operation: normalizeOperation(request.operation),
|
|
691
|
+
cancellationId: bytes(request.cancellation_id, 16),
|
|
692
|
+
effect: normalizeEffect(request.effect),
|
|
693
|
+
};
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
finally {
|
|
697
|
+
scrubBridgeBytes(value);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function normalizeEffect(value) {
|
|
701
|
+
const effect = record(value);
|
|
702
|
+
if ('Notify' in effect) {
|
|
703
|
+
return { kind: 'notify', notification: normalizeNotification(effect.Notify) };
|
|
704
|
+
}
|
|
705
|
+
if ('Ble' in effect)
|
|
706
|
+
return normalizeBleEffect(effect.Ble);
|
|
707
|
+
if ('Timer' in effect) {
|
|
708
|
+
const timer = record(effect.Timer);
|
|
709
|
+
if ('Schedule' in timer) {
|
|
710
|
+
const schedule = record(timer.Schedule);
|
|
711
|
+
return {
|
|
712
|
+
kind: 'timer_schedule',
|
|
713
|
+
timerId: bigint(schedule.timer_id),
|
|
714
|
+
delayMs: bigint(schedule.delay_ms),
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
if ('Cancel' in timer) {
|
|
718
|
+
return {
|
|
719
|
+
kind: 'timer_cancel',
|
|
720
|
+
timerId: bigint(record(timer.Cancel).timer_id),
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if ('Persistence' in effect)
|
|
725
|
+
return normalizePersistenceEffect(effect.Persistence);
|
|
726
|
+
if ('Network' in effect) {
|
|
727
|
+
const network = record(effect.Network);
|
|
728
|
+
if ('Download' in network) {
|
|
729
|
+
return {
|
|
730
|
+
kind: 'network_download',
|
|
731
|
+
downloadId: bigint(record(network.Download).download_id),
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
if ('Progress' in effect) {
|
|
736
|
+
const progress = record(effect.Progress);
|
|
737
|
+
return {
|
|
738
|
+
kind: 'progress',
|
|
739
|
+
completedUnits: bigint(progress.completed_units),
|
|
740
|
+
totalUnits: bigint(progress.total_units),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
if ('HostMaterial' in effect) {
|
|
744
|
+
const host = record(effect.HostMaterial);
|
|
745
|
+
if ('PrepareProvisioning' in host) {
|
|
746
|
+
const prepare = record(host.PrepareProvisioning);
|
|
747
|
+
return {
|
|
748
|
+
kind: 'host_material_prepare_provisioning',
|
|
749
|
+
materialId: string(prepare.material_id),
|
|
750
|
+
serialNumber: string(prepare.device),
|
|
751
|
+
nonce: bytes(prepare.nonce, 16),
|
|
752
|
+
devicePublicKey: bytes(prepare.device_public_key),
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if ('RecordingSink' in effect)
|
|
757
|
+
return normalizeRecordingSinkEffect(effect.RecordingSink);
|
|
758
|
+
if ('FirmwareBlob' in effect) {
|
|
759
|
+
const firmware = record(effect.FirmwareBlob);
|
|
760
|
+
if ('ReadChunk' in firmware) {
|
|
761
|
+
const chunk = record(firmware.ReadChunk);
|
|
762
|
+
return {
|
|
763
|
+
kind: 'firmware_blob_read_chunk',
|
|
764
|
+
downloadId: bigint(chunk.download_id),
|
|
765
|
+
offset: bigint(chunk.offset),
|
|
766
|
+
maxLength: number(chunk.max_length),
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if ('EncryptedUploadV2' in effect) {
|
|
771
|
+
return normalizeEncryptedUploadV2Effect(effect.EncryptedUploadV2);
|
|
772
|
+
}
|
|
773
|
+
throw internalBridgeError();
|
|
774
|
+
}
|
|
775
|
+
function normalizeBleEffect(value) {
|
|
776
|
+
if (value === 'StopScan')
|
|
777
|
+
return { kind: 'ble_stop_scan' };
|
|
778
|
+
const ble = record(value);
|
|
779
|
+
if ('StartScan' in ble) {
|
|
780
|
+
return {
|
|
781
|
+
kind: 'ble_start_scan',
|
|
782
|
+
allowDuplicates: boolean(record(ble.StartScan).allow_duplicates),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
if ('Connect' in ble) {
|
|
786
|
+
return {
|
|
787
|
+
kind: 'ble_connect',
|
|
788
|
+
peripheralId: string(record(ble.Connect).peripheral_id),
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
if ('DiscoverServices' in ble) {
|
|
792
|
+
return {
|
|
793
|
+
kind: 'ble_discover_services',
|
|
794
|
+
peripheralId: string(record(ble.DiscoverServices).peripheral_id),
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
if ('Disconnect' in ble) {
|
|
798
|
+
return {
|
|
799
|
+
kind: 'ble_disconnect',
|
|
800
|
+
peripheralId: string(record(ble.Disconnect).peripheral_id),
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
if ('Read' in ble) {
|
|
804
|
+
const read = record(ble.Read);
|
|
805
|
+
return {
|
|
806
|
+
kind: 'ble_read',
|
|
807
|
+
serviceUuid: string(read.service_uuid),
|
|
808
|
+
characteristicUuid: string(read.characteristic_uuid),
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
if ('Write' in ble) {
|
|
812
|
+
const write = record(ble.Write);
|
|
813
|
+
return {
|
|
814
|
+
kind: 'ble_write',
|
|
815
|
+
serviceUuid: string(write.service_uuid),
|
|
816
|
+
characteristicUuid: string(write.characteristic_uuid),
|
|
817
|
+
payload: bytes(write.payload),
|
|
818
|
+
withResponse: boolean(write.with_response),
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
if ('Subscribe' in ble) {
|
|
822
|
+
const subscribe = record(ble.Subscribe);
|
|
823
|
+
return {
|
|
824
|
+
kind: 'ble_subscribe',
|
|
825
|
+
serviceUuid: string(subscribe.service_uuid),
|
|
826
|
+
characteristicUuid: string(subscribe.characteristic_uuid),
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
if ('Unsubscribe' in ble) {
|
|
830
|
+
const unsubscribe = record(ble.Unsubscribe);
|
|
831
|
+
return {
|
|
832
|
+
kind: 'ble_unsubscribe',
|
|
833
|
+
serviceUuid: string(unsubscribe.service_uuid),
|
|
834
|
+
characteristicUuid: string(unsubscribe.characteristic_uuid),
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
throw internalBridgeError();
|
|
838
|
+
}
|
|
839
|
+
function normalizePersistenceEffect(value) {
|
|
840
|
+
if (value === 'LoadCheckpoint')
|
|
841
|
+
return { kind: 'persistence_load_checkpoint' };
|
|
842
|
+
if (value === 'DeleteCheckpoint')
|
|
843
|
+
return { kind: 'persistence_delete_checkpoint' };
|
|
844
|
+
const persistence = record(value);
|
|
845
|
+
if ('SaveCheckpoint' in persistence) {
|
|
846
|
+
return {
|
|
847
|
+
kind: 'persistence_save_checkpoint',
|
|
848
|
+
checkpoint: normalizeWorkflowCheckpoint(record(persistence.SaveCheckpoint).checkpoint),
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
if ('SaveConnectionIdentity' in persistence) {
|
|
852
|
+
const save = record(persistence.SaveConnectionIdentity);
|
|
853
|
+
return {
|
|
854
|
+
kind: 'persistence_save_connection_identity',
|
|
855
|
+
serialNumber: string(save.device),
|
|
856
|
+
candidate: normalizeCandidate(save.candidate),
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
throw internalBridgeError();
|
|
860
|
+
}
|
|
861
|
+
function normalizeRecordingSinkEffect(value) {
|
|
862
|
+
const sink = record(value);
|
|
863
|
+
if ('Truncate' in sink) {
|
|
864
|
+
const truncate = record(sink.Truncate);
|
|
865
|
+
return {
|
|
866
|
+
kind: 'recording_sink_truncate',
|
|
867
|
+
sinkId: string(truncate.sink_id),
|
|
868
|
+
completedUnits: bigint(truncate.completed_units),
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
if ('Append' in sink) {
|
|
872
|
+
const append = record(sink.Append);
|
|
873
|
+
return {
|
|
874
|
+
kind: 'recording_sink_append',
|
|
875
|
+
sinkId: string(append.sink_id),
|
|
876
|
+
sequence: number(append.sequence),
|
|
877
|
+
payload: bytes(append.payload),
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
if ('Finalize' in sink) {
|
|
881
|
+
const finalize = record(sink.Finalize);
|
|
882
|
+
return {
|
|
883
|
+
kind: 'recording_sink_finalize',
|
|
884
|
+
sinkId: string(finalize.sink_id),
|
|
885
|
+
expectedCrc32: optionalNumber(finalize.expected_crc32),
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
if ('Discard' in sink) {
|
|
889
|
+
return {
|
|
890
|
+
kind: 'recording_sink_discard',
|
|
891
|
+
sinkId: string(record(sink.Discard).sink_id),
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
throw internalBridgeError();
|
|
895
|
+
}
|
|
896
|
+
function normalizeEncryptedUploadV2Effect(value) {
|
|
897
|
+
const encrypted = record(value);
|
|
898
|
+
if ('LoadCheckpoint' in encrypted) {
|
|
899
|
+
const load = record(encrypted.LoadCheckpoint);
|
|
900
|
+
return {
|
|
901
|
+
kind: 'encrypted_upload_v2_load_checkpoint',
|
|
902
|
+
serialNumber: string(load.device),
|
|
903
|
+
recordingUuid: bytes(load.recording, 16),
|
|
904
|
+
recordingGeneration: number(load.recording_generation),
|
|
905
|
+
uploadSessionId: bytes(load.upload_session_uuid, 16),
|
|
906
|
+
ownerRevision: number(load.owner_revision),
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
if ('DeleteCheckpoint' in encrypted) {
|
|
910
|
+
return {
|
|
911
|
+
kind: 'encrypted_upload_v2_delete_checkpoint',
|
|
912
|
+
uploadSessionId: bytes(record(encrypted.DeleteCheckpoint).upload_session_uuid, 16),
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
if ('TruncateSink' in encrypted) {
|
|
916
|
+
const truncate = record(encrypted.TruncateSink);
|
|
917
|
+
return {
|
|
918
|
+
kind: 'encrypted_upload_v2_truncate_sink',
|
|
919
|
+
sinkId: string(truncate.sink_id),
|
|
920
|
+
nextCiphertextOffset: bigint(truncate.next_ciphertext_offset),
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
if ('PrepareSession' in encrypted) {
|
|
924
|
+
return {
|
|
925
|
+
kind: 'encrypted_upload_v2_prepare_session',
|
|
926
|
+
materialId: string(record(encrypted.PrepareSession).material_id),
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
if ('StartTransfer' in encrypted) {
|
|
930
|
+
const start = record(encrypted.StartTransfer);
|
|
931
|
+
const request = record(start.request);
|
|
932
|
+
const selection = record(request.selection);
|
|
933
|
+
if (selection.profile !== 'EncryptedUploadV2')
|
|
934
|
+
throw internalBridgeError();
|
|
935
|
+
return {
|
|
936
|
+
kind: 'encrypted_upload_v2_start_transfer',
|
|
937
|
+
serialNumber: string(request.device),
|
|
938
|
+
recordingUuid: bytes(request.recording, 16),
|
|
939
|
+
recordingGeneration: number(request.recording_generation),
|
|
940
|
+
storageFormat: number(request.storage_format),
|
|
941
|
+
uploadSessionId: bytes(request.upload_session_uuid, 16),
|
|
942
|
+
ownerRevision: number(request.owner_revision),
|
|
943
|
+
transportSessionId: bigint(request.transport_session_id),
|
|
944
|
+
materialId: string(request.material_id),
|
|
945
|
+
sinkId: string(request.sink_id),
|
|
946
|
+
policy: normalizeUploadPolicy(selection.policy),
|
|
947
|
+
capabilities: normalizeCapabilities(request.capabilities),
|
|
948
|
+
windowPackets: number(request.window_packets),
|
|
949
|
+
dataPayloadBytes: number(request.data_payload_bytes),
|
|
950
|
+
ciphertextLength: bigint(request.ciphertext_length),
|
|
951
|
+
ciphertextSha256: bytes(request.ciphertext_sha256, 32),
|
|
952
|
+
checkpoint: optionalEncryptedCheckpoint(start.checkpoint),
|
|
953
|
+
authorizationSha256: bytes(start.authorization_sha256, 32),
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
if ('RepairWindow' in encrypted) {
|
|
957
|
+
return {
|
|
958
|
+
kind: 'encrypted_upload_v2_repair_window',
|
|
959
|
+
missingSequences: numbers(record(encrypted.RepairWindow).missing_sequences),
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
if ('SaveCheckpoint' in encrypted) {
|
|
963
|
+
return {
|
|
964
|
+
kind: 'encrypted_upload_v2_save_checkpoint',
|
|
965
|
+
checkpoint: normalizeEncryptedCheckpoint(record(encrypted.SaveCheckpoint).checkpoint),
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
if ('AcknowledgeWindow' in encrypted) {
|
|
969
|
+
return {
|
|
970
|
+
kind: 'encrypted_upload_v2_acknowledge_window',
|
|
971
|
+
checkpoint: normalizeEncryptedCheckpoint(record(encrypted.AcknowledgeWindow).checkpoint),
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
if ('StageArtifacts' in encrypted) {
|
|
975
|
+
const stage = record(encrypted.StageArtifacts);
|
|
976
|
+
return {
|
|
977
|
+
kind: 'encrypted_upload_v2_stage_artifacts',
|
|
978
|
+
sinkId: string(stage.sink_id),
|
|
979
|
+
materialId: string(stage.material_id),
|
|
980
|
+
evidence: normalizeEncryptedEvidence(stage.evidence),
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
if ('AwaitCompletionReceipt' in encrypted) {
|
|
984
|
+
const awaitReceipt = record(encrypted.AwaitCompletionReceipt);
|
|
985
|
+
return {
|
|
986
|
+
kind: 'encrypted_upload_v2_await_completion_receipt',
|
|
987
|
+
materialId: string(awaitReceipt.material_id),
|
|
988
|
+
evidence: normalizeEncryptedEvidence(awaitReceipt.evidence),
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
if ('ConfirmWithReceipt' in encrypted) {
|
|
992
|
+
const confirm = record(encrypted.ConfirmWithReceipt);
|
|
993
|
+
return {
|
|
994
|
+
kind: 'encrypted_upload_v2_confirm_with_receipt',
|
|
995
|
+
materialId: string(confirm.material_id),
|
|
996
|
+
receiptSha256: bytes(confirm.receipt_sha256, 32),
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
if ('AbortV2' in encrypted) {
|
|
1000
|
+
return {
|
|
1001
|
+
kind: 'encrypted_upload_v2_abort',
|
|
1002
|
+
materialId: string(record(encrypted.AbortV2).material_id),
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
throw internalBridgeError();
|
|
1006
|
+
}
|
|
1007
|
+
function normalizeNotification(value) {
|
|
1008
|
+
const notification = record(value);
|
|
1009
|
+
if ('Started' in notification) {
|
|
1010
|
+
return {
|
|
1011
|
+
kind: 'started',
|
|
1012
|
+
operation: normalizeOperation(record(notification.Started).operation),
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if ('ConnectionEstablished' in notification) {
|
|
1016
|
+
const established = record(notification.ConnectionEstablished);
|
|
1017
|
+
return {
|
|
1018
|
+
kind: 'connection_established',
|
|
1019
|
+
serialNumber: string(established.device),
|
|
1020
|
+
candidate: normalizeCandidate(established.candidate),
|
|
1021
|
+
mode: enumValue(established.mode, { Manual: 'manual', Reconnect: 'reconnect' }),
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
if ('Progress' in notification) {
|
|
1025
|
+
const progress = record(notification.Progress);
|
|
1026
|
+
return {
|
|
1027
|
+
kind: 'progress',
|
|
1028
|
+
operation: normalizeOperation(progress.operation),
|
|
1029
|
+
completedUnits: bigint(progress.completed_units),
|
|
1030
|
+
totalUnits: bigint(progress.total_units),
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
if ('Retrying' in notification) {
|
|
1034
|
+
const retrying = record(notification.Retrying);
|
|
1035
|
+
return {
|
|
1036
|
+
kind: 'retrying',
|
|
1037
|
+
operation: normalizeOperation(retrying.operation),
|
|
1038
|
+
attempt: number(retrying.attempt),
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
if ('FirmwareProgress' in notification) {
|
|
1042
|
+
const progress = record(record(notification.FirmwareProgress).progress);
|
|
1043
|
+
return {
|
|
1044
|
+
kind: 'firmware_progress',
|
|
1045
|
+
phase: enumValue(progress.phase, {
|
|
1046
|
+
Downloading: 'downloading',
|
|
1047
|
+
AwaitingDevice: 'awaiting_device',
|
|
1048
|
+
Transferring: 'transferring',
|
|
1049
|
+
Verifying: 'verifying',
|
|
1050
|
+
Rebooting: 'rebooting',
|
|
1051
|
+
Reconnecting: 'reconnecting',
|
|
1052
|
+
Complete: 'complete',
|
|
1053
|
+
}),
|
|
1054
|
+
completedBytes: bigint(progress.completed_bytes),
|
|
1055
|
+
totalBytes: bigint(progress.total_bytes),
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
if ('DeviceLog' in notification) {
|
|
1059
|
+
const event = record(record(notification.DeviceLog).event);
|
|
1060
|
+
return {
|
|
1061
|
+
kind: 'device_log',
|
|
1062
|
+
message: string(event.message),
|
|
1063
|
+
isBacklog: boolean(event.is_backlog),
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
if ('RecordingTransferCompleted' in notification) {
|
|
1067
|
+
const completed = record(notification.RecordingTransferCompleted);
|
|
1068
|
+
return {
|
|
1069
|
+
kind: 'recording_transfer_completed',
|
|
1070
|
+
encrypted: boolean(completed.encrypted),
|
|
1071
|
+
sha256: optionalBytes(completed.sha256, 32),
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
if ('EncryptedUploadV2Staged' in notification) {
|
|
1075
|
+
const staged = record(notification.EncryptedUploadV2Staged);
|
|
1076
|
+
return {
|
|
1077
|
+
kind: 'encrypted_upload_v2_staged',
|
|
1078
|
+
uploadSessionId: bytes(staged.upload_session_uuid, 16),
|
|
1079
|
+
ownerRevision: number(staged.owner_revision),
|
|
1080
|
+
ciphertextLength: bigint(staged.ciphertext_length),
|
|
1081
|
+
ciphertextSha256: bytes(staged.ciphertext_sha256, 32),
|
|
1082
|
+
manifestLength: number(staged.manifest_length),
|
|
1083
|
+
manifestSha256: bytes(staged.manifest_sha256, 32),
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
if ('Completed' in notification) {
|
|
1087
|
+
return {
|
|
1088
|
+
kind: 'completed',
|
|
1089
|
+
operation: normalizeOperation(record(notification.Completed).operation),
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
if ('Cancelled' in notification) {
|
|
1093
|
+
return {
|
|
1094
|
+
kind: 'cancelled',
|
|
1095
|
+
operation: normalizeOperation(record(notification.Cancelled).operation),
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
if ('Failed' in notification) {
|
|
1099
|
+
return {
|
|
1100
|
+
kind: 'failed',
|
|
1101
|
+
error: record(notification.Failed).error,
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
throw internalBridgeError();
|
|
1105
|
+
}
|
|
1106
|
+
function rawHostEvent(event) {
|
|
1107
|
+
const request_id = event.requestId;
|
|
1108
|
+
switch (event.kind) {
|
|
1109
|
+
case 'ble_scan_result':
|
|
1110
|
+
return { request_id, kind: { Ble: { ScanResult: { candidate: rawCandidate(event.candidate) } } } };
|
|
1111
|
+
case 'ble_scan_stopped':
|
|
1112
|
+
return { request_id, kind: { Ble: 'ScanStopped' } };
|
|
1113
|
+
case 'ble_connected':
|
|
1114
|
+
return { request_id, kind: { Ble: { Connected: { peripheral_id: event.peripheralId } } } };
|
|
1115
|
+
case 'ble_services_discovered':
|
|
1116
|
+
return { request_id, kind: { Ble: { ServicesDiscovered: { peripheral_id: event.peripheralId } } } };
|
|
1117
|
+
case 'ble_subscribed':
|
|
1118
|
+
return { request_id, kind: { Ble: { Subscribed: { characteristic_uuid: event.characteristicUuid } } } };
|
|
1119
|
+
case 'ble_disconnected':
|
|
1120
|
+
return {
|
|
1121
|
+
request_id,
|
|
1122
|
+
kind: { Ble: { Disconnected: {
|
|
1123
|
+
peripheral_id: event.peripheralId,
|
|
1124
|
+
reason_code: event.reasonCode ?? undefined,
|
|
1125
|
+
} } },
|
|
1126
|
+
};
|
|
1127
|
+
case 'ble_read_completed':
|
|
1128
|
+
return { request_id, kind: { Ble: { ReadCompleted: { value: rawBytes(event.value) } } } };
|
|
1129
|
+
case 'ble_write_completed':
|
|
1130
|
+
return { request_id, kind: { Ble: 'WriteCompleted' } };
|
|
1131
|
+
case 'ble_notification':
|
|
1132
|
+
return { request_id, kind: { Ble: { Notification: {
|
|
1133
|
+
characteristic_uuid: event.characteristicUuid,
|
|
1134
|
+
value: rawBytes(event.value),
|
|
1135
|
+
} } } };
|
|
1136
|
+
case 'ble_failed':
|
|
1137
|
+
return { request_id, kind: { Ble: { Failed: { platform_code: event.platformCode ?? undefined } } } };
|
|
1138
|
+
case 'timer_fired':
|
|
1139
|
+
return { request_id, kind: { TimerFired: { timer_id: event.timerId } } };
|
|
1140
|
+
case 'checkpoint_loaded':
|
|
1141
|
+
return { request_id, kind: { CheckpointLoaded: {
|
|
1142
|
+
checkpoint: event.checkpoint ? rawWorkflowCheckpoint(event.checkpoint) : undefined,
|
|
1143
|
+
} } };
|
|
1144
|
+
case 'checkpoint_saved':
|
|
1145
|
+
return { request_id, kind: 'CheckpointSaved' };
|
|
1146
|
+
case 'connection_identity_saved':
|
|
1147
|
+
return { request_id, kind: 'ConnectionIdentitySaved' };
|
|
1148
|
+
case 'persistence_failed':
|
|
1149
|
+
return { request_id, kind: { PersistenceFailed: {
|
|
1150
|
+
platform_code: event.platformCode ?? undefined,
|
|
1151
|
+
} } };
|
|
1152
|
+
case 'provisioning_material_prepared':
|
|
1153
|
+
return { request_id, kind: { ProvisioningMaterialPrepared: { material: {
|
|
1154
|
+
api_endpoint: rawBytes(event.apiEndpoint),
|
|
1155
|
+
device_token: rawBytes(event.deviceToken),
|
|
1156
|
+
mtu: event.mtu,
|
|
1157
|
+
} } } };
|
|
1158
|
+
case 'host_material_failed':
|
|
1159
|
+
return { request_id, kind: { HostMaterialFailed: {
|
|
1160
|
+
platform_code: event.platformCode ?? undefined,
|
|
1161
|
+
} } };
|
|
1162
|
+
case 'recording_sink_truncated':
|
|
1163
|
+
return { request_id, kind: 'RecordingSinkTruncated' };
|
|
1164
|
+
case 'recording_sink_append_completed':
|
|
1165
|
+
return { request_id, kind: { RecordingSinkAppendCompleted: {
|
|
1166
|
+
durable_units: event.durableUnits,
|
|
1167
|
+
} } };
|
|
1168
|
+
case 'recording_sink_finalized':
|
|
1169
|
+
return { request_id, kind: { RecordingSinkFinalized: {
|
|
1170
|
+
durable_units: event.durableUnits,
|
|
1171
|
+
} } };
|
|
1172
|
+
case 'recording_sink_integrity_failed':
|
|
1173
|
+
return { request_id, kind: 'RecordingSinkIntegrityFailed' };
|
|
1174
|
+
case 'recording_sink_failed':
|
|
1175
|
+
return { request_id, kind: { RecordingSinkFailed: {
|
|
1176
|
+
platform_code: event.platformCode ?? undefined,
|
|
1177
|
+
} } };
|
|
1178
|
+
case 'firmware_chunk_read':
|
|
1179
|
+
return { request_id, kind: { FirmwareChunkRead: {
|
|
1180
|
+
download_id: event.downloadId,
|
|
1181
|
+
offset: event.offset,
|
|
1182
|
+
bytes: rawBytes(event.bytes),
|
|
1183
|
+
} } };
|
|
1184
|
+
case 'firmware_blob_failed':
|
|
1185
|
+
return { request_id, kind: { FirmwareBlobFailed: {
|
|
1186
|
+
platform_code: event.platformCode ?? undefined,
|
|
1187
|
+
} } };
|
|
1188
|
+
case 'network_download_progress':
|
|
1189
|
+
return { request_id, kind: { Network: { DownloadProgress: {
|
|
1190
|
+
download_id: event.downloadId,
|
|
1191
|
+
completed_bytes: event.completedBytes,
|
|
1192
|
+
total_bytes: event.totalBytes ?? undefined,
|
|
1193
|
+
} } } };
|
|
1194
|
+
case 'network_download_completed':
|
|
1195
|
+
return { request_id, kind: { Network: { DownloadCompleted: {
|
|
1196
|
+
download_id: event.downloadId,
|
|
1197
|
+
crc32: event.crc32,
|
|
1198
|
+
} } } };
|
|
1199
|
+
case 'network_failed':
|
|
1200
|
+
return { request_id, kind: { Network: { Failed: {
|
|
1201
|
+
transfer_id: event.transferId,
|
|
1202
|
+
status_code: event.statusCode ?? undefined,
|
|
1203
|
+
} } } };
|
|
1204
|
+
case 'encrypted_upload_v2_checkpoint_loaded':
|
|
1205
|
+
return { request_id, kind: { EncryptedUploadV2: {
|
|
1206
|
+
CheckpointLoaded: event.checkpoint ? rawEncryptedCheckpoint(event.checkpoint) : null,
|
|
1207
|
+
} } };
|
|
1208
|
+
case 'encrypted_upload_v2_sink_truncated':
|
|
1209
|
+
return { request_id, kind: { EncryptedUploadV2: 'SinkTruncated' } };
|
|
1210
|
+
case 'encrypted_upload_v2_session_prepared':
|
|
1211
|
+
return { request_id, kind: { EncryptedUploadV2: { SessionPrepared: {
|
|
1212
|
+
authorization_sha256: rawBytes(event.authorizationSha256),
|
|
1213
|
+
} } } };
|
|
1214
|
+
case 'encrypted_upload_v2_transfer_started':
|
|
1215
|
+
return { request_id, kind: { EncryptedUploadV2: 'TransferStarted' } };
|
|
1216
|
+
case 'encrypted_upload_v2_resume_rejected':
|
|
1217
|
+
return { request_id, kind: { EncryptedUploadV2: 'ResumeRejected' } };
|
|
1218
|
+
case 'encrypted_upload_v2_window_staged':
|
|
1219
|
+
return { request_id, kind: { EncryptedUploadV2: { WindowStaged: {
|
|
1220
|
+
checkpoint: rawEncryptedCheckpoint(event.checkpoint),
|
|
1221
|
+
missing_sequences: [...event.missingSequences],
|
|
1222
|
+
} } } };
|
|
1223
|
+
case 'encrypted_upload_v2_checkpoint_saved':
|
|
1224
|
+
return { request_id, kind: { EncryptedUploadV2: 'CheckpointSaved' } };
|
|
1225
|
+
case 'encrypted_upload_v2_window_acknowledged':
|
|
1226
|
+
return { request_id, kind: { EncryptedUploadV2: { WindowAcknowledged: {
|
|
1227
|
+
checkpoint: rawEncryptedCheckpoint(event.checkpoint),
|
|
1228
|
+
} } } };
|
|
1229
|
+
case 'encrypted_upload_v2_transfer_completed':
|
|
1230
|
+
return { request_id, kind: { EncryptedUploadV2: {
|
|
1231
|
+
TransferCompleted: rawEncryptedEvidence(event.evidence),
|
|
1232
|
+
} } };
|
|
1233
|
+
case 'encrypted_upload_v2_artifacts_staged':
|
|
1234
|
+
return { request_id, kind: { EncryptedUploadV2: 'ArtifactsStaged' } };
|
|
1235
|
+
case 'encrypted_upload_v2_completion_receipt_accepted':
|
|
1236
|
+
return { request_id, kind: { EncryptedUploadV2: { CompletionReceiptAccepted: {
|
|
1237
|
+
receipt_sha256: rawBytes(event.receiptSha256),
|
|
1238
|
+
} } } };
|
|
1239
|
+
case 'encrypted_upload_v2_recording_confirmed':
|
|
1240
|
+
return { request_id, kind: { EncryptedUploadV2: 'RecordingConfirmed' } };
|
|
1241
|
+
case 'encrypted_upload_v2_mixed_profile':
|
|
1242
|
+
return { request_id, kind: { EncryptedUploadV2: 'MixedProfile' } };
|
|
1243
|
+
case 'encrypted_upload_v2_failed':
|
|
1244
|
+
return { request_id, kind: { EncryptedUploadV2: { Failed: { error: event.error } } } };
|
|
1245
|
+
default:
|
|
1246
|
+
throw internalBridgeError();
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
function normalizeStatus(value) {
|
|
1250
|
+
if (value === 'Idle')
|
|
1251
|
+
return { kind: 'idle' };
|
|
1252
|
+
const status = record(value);
|
|
1253
|
+
if ('Running' in status) {
|
|
1254
|
+
const running = record(status.Running);
|
|
1255
|
+
return {
|
|
1256
|
+
kind: 'running',
|
|
1257
|
+
operation: normalizeOperation(running.operation),
|
|
1258
|
+
cancellationId: bytes(running.cancellation_id, 16),
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
if ('Completed' in status) {
|
|
1262
|
+
return {
|
|
1263
|
+
kind: 'completed',
|
|
1264
|
+
operation: normalizeOperation(record(status.Completed).operation),
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
if ('Cancelled' in status) {
|
|
1268
|
+
return {
|
|
1269
|
+
kind: 'cancelled',
|
|
1270
|
+
operation: normalizeOperation(record(status.Cancelled).operation),
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
if ('Failed' in status)
|
|
1274
|
+
return { kind: 'failed', error: record(status.Failed).error };
|
|
1275
|
+
throw internalBridgeError();
|
|
1276
|
+
}
|
|
1277
|
+
function normalizeCandidate(value) {
|
|
1278
|
+
const candidate = record(value);
|
|
1279
|
+
return {
|
|
1280
|
+
peripheralId: string(candidate.peripheral_id),
|
|
1281
|
+
name: optionalString(candidate.name),
|
|
1282
|
+
advertisedAddress: optionalString(candidate.advertised_address),
|
|
1283
|
+
rssi: number(candidate.rssi),
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
function rawCandidate(candidate) {
|
|
1287
|
+
return {
|
|
1288
|
+
peripheral_id: candidate.peripheralId,
|
|
1289
|
+
name: candidate.name ?? undefined,
|
|
1290
|
+
advertised_address: candidate.advertisedAddress ?? undefined,
|
|
1291
|
+
rssi: candidate.rssi,
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
function normalizeWorkflowCheckpoint(value) {
|
|
1295
|
+
const checkpoint = record(value);
|
|
1296
|
+
return {
|
|
1297
|
+
workflow: normalizeWorkflowKind(checkpoint.workflow),
|
|
1298
|
+
operation: normalizeOperation(checkpoint.operation),
|
|
1299
|
+
serialNumber: string(checkpoint.device),
|
|
1300
|
+
recordingUuid: optionalBytes(checkpoint.recording, 16),
|
|
1301
|
+
phase: normalizeCheckpointPhase(checkpoint.phase),
|
|
1302
|
+
completedUnits: bigint(checkpoint.completed_units),
|
|
1303
|
+
retryCount: number(checkpoint.retry_count),
|
|
1304
|
+
lastSequence: optionalNumber(checkpoint.last_sequence),
|
|
1305
|
+
firmwareVersion: optionalString(checkpoint.firmware_version),
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function rawWorkflowCheckpoint(checkpoint) {
|
|
1309
|
+
return {
|
|
1310
|
+
workflow: rawWorkflowKind(checkpoint.workflow),
|
|
1311
|
+
operation: rawOperation(checkpoint.operation),
|
|
1312
|
+
device: checkpoint.serialNumber,
|
|
1313
|
+
recording: checkpoint.recordingUuid ? rawBytes(checkpoint.recordingUuid) : undefined,
|
|
1314
|
+
phase: rawCheckpointPhase(checkpoint.phase),
|
|
1315
|
+
completed_units: checkpoint.completedUnits,
|
|
1316
|
+
retry_count: checkpoint.retryCount,
|
|
1317
|
+
last_sequence: checkpoint.lastSequence ?? undefined,
|
|
1318
|
+
firmware_version: checkpoint.firmwareVersion ?? undefined,
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
function normalizeEncryptedCheckpoint(value) {
|
|
1322
|
+
const checkpoint = record(value);
|
|
1323
|
+
return {
|
|
1324
|
+
serialNumber: string(checkpoint.device),
|
|
1325
|
+
recordingUuid: bytes(checkpoint.recording, 16),
|
|
1326
|
+
recordingGeneration: number(checkpoint.recording_generation),
|
|
1327
|
+
uploadSessionId: bytes(checkpoint.upload_session_uuid, 16),
|
|
1328
|
+
ownerRevision: number(checkpoint.owner_revision),
|
|
1329
|
+
transportSessionId: bigint(checkpoint.transport_session_id),
|
|
1330
|
+
checkpointRevision: number(checkpoint.checkpoint_revision),
|
|
1331
|
+
nextCiphertextOffset: bigint(checkpoint.next_ciphertext_offset),
|
|
1332
|
+
prefixSha256: bytes(checkpoint.prefix_sha256, 32),
|
|
1333
|
+
windowPackets: number(checkpoint.window_packets),
|
|
1334
|
+
dataPayloadBytes: number(checkpoint.data_payload_bytes),
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
function optionalEncryptedCheckpoint(value) {
|
|
1338
|
+
return value === undefined || value === null ? null : normalizeEncryptedCheckpoint(value);
|
|
1339
|
+
}
|
|
1340
|
+
function rawEncryptedCheckpoint(checkpoint) {
|
|
1341
|
+
return {
|
|
1342
|
+
device: checkpoint.serialNumber,
|
|
1343
|
+
recording: rawBytes(checkpoint.recordingUuid),
|
|
1344
|
+
recording_generation: checkpoint.recordingGeneration,
|
|
1345
|
+
upload_session_uuid: rawBytes(checkpoint.uploadSessionId),
|
|
1346
|
+
owner_revision: checkpoint.ownerRevision,
|
|
1347
|
+
transport_session_id: checkpoint.transportSessionId,
|
|
1348
|
+
checkpoint_revision: checkpoint.checkpointRevision,
|
|
1349
|
+
next_ciphertext_offset: checkpoint.nextCiphertextOffset,
|
|
1350
|
+
prefix_sha256: rawBytes(checkpoint.prefixSha256),
|
|
1351
|
+
window_packets: checkpoint.windowPackets,
|
|
1352
|
+
data_payload_bytes: checkpoint.dataPayloadBytes,
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
function normalizeEncryptedEvidence(value) {
|
|
1356
|
+
const evidence = record(value);
|
|
1357
|
+
return {
|
|
1358
|
+
ciphertextLength: bigint(evidence.ciphertext_length),
|
|
1359
|
+
ciphertextSha256: bytes(evidence.ciphertext_sha256, 32),
|
|
1360
|
+
manifestLength: number(evidence.manifest_length),
|
|
1361
|
+
manifestSha256: bytes(evidence.manifest_sha256, 32),
|
|
1362
|
+
blockCount: number(evidence.block_count),
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
function rawEncryptedEvidence(evidence) {
|
|
1366
|
+
return {
|
|
1367
|
+
ciphertext_length: evidence.ciphertextLength,
|
|
1368
|
+
ciphertext_sha256: rawBytes(evidence.ciphertextSha256),
|
|
1369
|
+
manifest_length: evidence.manifestLength,
|
|
1370
|
+
manifest_sha256: rawBytes(evidence.manifestSha256),
|
|
1371
|
+
block_count: evidence.blockCount,
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
function normalizeOperation(value) {
|
|
1375
|
+
return enumValue(value, {
|
|
1376
|
+
Validate: 'validate',
|
|
1377
|
+
Decode: 'decode',
|
|
1378
|
+
Encode: 'encode',
|
|
1379
|
+
Discover: 'discover',
|
|
1380
|
+
Connect: 'connect',
|
|
1381
|
+
Reconnect: 'reconnect',
|
|
1382
|
+
Provision: 'provision',
|
|
1383
|
+
TransferRecording: 'transfer_recording',
|
|
1384
|
+
Upload: 'upload',
|
|
1385
|
+
UpdateFirmware: 'update_firmware',
|
|
1386
|
+
ReadDeviceLogs: 'read_device_logs',
|
|
1387
|
+
FactoryReset: 'factory_reset',
|
|
1388
|
+
Unknown: 'unknown',
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
function rawOperation(operation) {
|
|
1392
|
+
return reverseEnumValue(operation, {
|
|
1393
|
+
Validate: 'validate',
|
|
1394
|
+
Decode: 'decode',
|
|
1395
|
+
Encode: 'encode',
|
|
1396
|
+
Discover: 'discover',
|
|
1397
|
+
Connect: 'connect',
|
|
1398
|
+
Reconnect: 'reconnect',
|
|
1399
|
+
Provision: 'provision',
|
|
1400
|
+
TransferRecording: 'transfer_recording',
|
|
1401
|
+
Upload: 'upload',
|
|
1402
|
+
UpdateFirmware: 'update_firmware',
|
|
1403
|
+
ReadDeviceLogs: 'read_device_logs',
|
|
1404
|
+
FactoryReset: 'factory_reset',
|
|
1405
|
+
Unknown: 'unknown',
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
function normalizeWorkflowKind(value) {
|
|
1409
|
+
return enumValue(value, {
|
|
1410
|
+
Discovery: 'discovery',
|
|
1411
|
+
Connection: 'connection',
|
|
1412
|
+
Provisioning: 'provisioning',
|
|
1413
|
+
RecordingTransfer: 'recording_transfer',
|
|
1414
|
+
RecordingUpload: 'recording_upload',
|
|
1415
|
+
FirmwareUpdate: 'firmware_update',
|
|
1416
|
+
DeviceLogs: 'device_logs',
|
|
1417
|
+
FactoryReset: 'factory_reset',
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
function rawWorkflowKind(value) {
|
|
1421
|
+
return reverseEnumValue(value, {
|
|
1422
|
+
Discovery: 'discovery',
|
|
1423
|
+
Connection: 'connection',
|
|
1424
|
+
Provisioning: 'provisioning',
|
|
1425
|
+
RecordingTransfer: 'recording_transfer',
|
|
1426
|
+
RecordingUpload: 'recording_upload',
|
|
1427
|
+
FirmwareUpdate: 'firmware_update',
|
|
1428
|
+
DeviceLogs: 'device_logs',
|
|
1429
|
+
FactoryReset: 'factory_reset',
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
function normalizeCheckpointPhase(value) {
|
|
1433
|
+
return enumValue(value, {
|
|
1434
|
+
Pending: 'pending',
|
|
1435
|
+
Connecting: 'connecting',
|
|
1436
|
+
Transferring: 'transferring',
|
|
1437
|
+
Uploading: 'uploading',
|
|
1438
|
+
Verifying: 'verifying',
|
|
1439
|
+
Reconnecting: 'reconnecting',
|
|
1440
|
+
AwaitingReceipt: 'awaiting_receipt',
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
function rawCheckpointPhase(value) {
|
|
1444
|
+
return reverseEnumValue(value, {
|
|
1445
|
+
Pending: 'pending',
|
|
1446
|
+
Connecting: 'connecting',
|
|
1447
|
+
Transferring: 'transferring',
|
|
1448
|
+
Uploading: 'uploading',
|
|
1449
|
+
Verifying: 'verifying',
|
|
1450
|
+
Reconnecting: 'reconnecting',
|
|
1451
|
+
AwaitingReceipt: 'awaiting_receipt',
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
function normalizeUploadPolicy(value) {
|
|
1455
|
+
return enumValue(value, {
|
|
1456
|
+
LegacyAllowed: 'legacy_allowed',
|
|
1457
|
+
V2Preferred: 'v2_preferred',
|
|
1458
|
+
V2Required: 'v2_required',
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
function normalizeDeviceStatus(value) {
|
|
1462
|
+
const status = record(value);
|
|
1463
|
+
const flags = record(status.flags);
|
|
1464
|
+
return {
|
|
1465
|
+
batteryPercent: number(status.battery_percent),
|
|
1466
|
+
batteryMillivolts: optionalNumber(status.battery_mv),
|
|
1467
|
+
storageTotalMb: number(status.storage_total_mb),
|
|
1468
|
+
storageUsedMb: number(status.storage_used_mb),
|
|
1469
|
+
...normalizeDeviceState(status.state),
|
|
1470
|
+
pendingRecordings: number(status.pending_recordings),
|
|
1471
|
+
lastTimeSyncTimestamp: number(status.last_time_sync_timestamp),
|
|
1472
|
+
flags: {
|
|
1473
|
+
charging: boolean(flags.charging),
|
|
1474
|
+
lowBattery: boolean(flags.low_battery),
|
|
1475
|
+
storageFull: boolean(flags.storage_full),
|
|
1476
|
+
wifiConnected: boolean(flags.wifi_connected),
|
|
1477
|
+
lteConnected: boolean(flags.lte_connected),
|
|
1478
|
+
syncActive: boolean(flags.sync_active),
|
|
1479
|
+
},
|
|
1480
|
+
lteStatusRaw: number(status.lte_status_raw),
|
|
1481
|
+
lteSignalQuality: optionalNumber(status.lte_signal_quality),
|
|
1482
|
+
wifiStatusRaw: optionalNumber(status.wifi_status_raw),
|
|
1483
|
+
modemInfo: normalizeModemInfo(status.modem_info),
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
function normalizeDeviceState(value) {
|
|
1487
|
+
if (typeof value === 'string') {
|
|
1488
|
+
const known = {
|
|
1489
|
+
Idle: 'idle',
|
|
1490
|
+
Recording: 'recording',
|
|
1491
|
+
Syncing: 'syncing',
|
|
1492
|
+
Uploading: 'uploading',
|
|
1493
|
+
Charging: 'charging',
|
|
1494
|
+
LowBattery: 'low_battery',
|
|
1495
|
+
StorageFull: 'storage_full',
|
|
1496
|
+
Error: 'error',
|
|
1497
|
+
};
|
|
1498
|
+
return { state: known[value] ?? 'unknown' };
|
|
1499
|
+
}
|
|
1500
|
+
return { state: 'unknown', stateRaw: number(record(value).Unknown) };
|
|
1501
|
+
}
|
|
1502
|
+
function normalizeModemInfo(value) {
|
|
1503
|
+
if (value === undefined || value === null)
|
|
1504
|
+
return null;
|
|
1505
|
+
const modem = record(value);
|
|
1506
|
+
return {
|
|
1507
|
+
imei: optionalString(modem.imei),
|
|
1508
|
+
iccid: optionalString(modem.iccid),
|
|
1509
|
+
operator: optionalString(modem.operator),
|
|
1510
|
+
rat: optionalString(modem.rat),
|
|
1511
|
+
band: optionalString(modem.band),
|
|
1512
|
+
apn: optionalString(modem.apn),
|
|
1513
|
+
simStatus: optionalString(modem.sim_status),
|
|
1514
|
+
csq: optionalNumber(modem.csq),
|
|
1515
|
+
ipAddress: optionalString(modem.ip_address),
|
|
1516
|
+
voltageMillivolts: optionalNumber(modem.voltage_mv),
|
|
1517
|
+
firmware: optionalString(modem.firmware),
|
|
1518
|
+
roaming: optionalBoolean(modem.roaming),
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
function normalizeCapabilities(value) {
|
|
1522
|
+
const capabilities = record(value);
|
|
1523
|
+
return {
|
|
1524
|
+
flags: number(capabilities.flags),
|
|
1525
|
+
maximumSignedBlobBytes: number(capabilities.maximum_signed_blob_bytes),
|
|
1526
|
+
maximumManifestBytes: number(capabilities.maximum_manifest_bytes),
|
|
1527
|
+
maximumDataPayloadBytes: number(capabilities.maximum_data_payload_bytes),
|
|
1528
|
+
maximumWindowPackets: number(capabilities.maximum_window_packets),
|
|
1529
|
+
durableCheckpointIntervalBlocks: number(capabilities.durable_checkpoint_interval_blocks),
|
|
1530
|
+
maximumMissingSequences: number(capabilities.maximum_missing_sequences),
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
function record(value) {
|
|
1534
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
1535
|
+
throw internalBridgeError();
|
|
1536
|
+
}
|
|
1537
|
+
return value;
|
|
1538
|
+
}
|
|
1539
|
+
function string(value) {
|
|
1540
|
+
if (typeof value !== 'string')
|
|
1541
|
+
throw internalBridgeError();
|
|
1542
|
+
return value;
|
|
1543
|
+
}
|
|
1544
|
+
function stringUnion(value, values) {
|
|
1545
|
+
const result = string(value);
|
|
1546
|
+
if (!values.includes(result))
|
|
1547
|
+
throw internalBridgeError();
|
|
1548
|
+
return result;
|
|
1549
|
+
}
|
|
1550
|
+
function optionalString(value) {
|
|
1551
|
+
return value === undefined || value === null ? null : string(value);
|
|
1552
|
+
}
|
|
1553
|
+
function number(value) {
|
|
1554
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value))
|
|
1555
|
+
throw internalBridgeError();
|
|
1556
|
+
return value;
|
|
1557
|
+
}
|
|
1558
|
+
function optionalNumber(value) {
|
|
1559
|
+
return value === undefined || value === null ? null : number(value);
|
|
1560
|
+
}
|
|
1561
|
+
function boolean(value) {
|
|
1562
|
+
if (typeof value !== 'boolean')
|
|
1563
|
+
throw internalBridgeError();
|
|
1564
|
+
return value;
|
|
1565
|
+
}
|
|
1566
|
+
function optionalBoolean(value) {
|
|
1567
|
+
return value === undefined || value === null ? null : boolean(value);
|
|
1568
|
+
}
|
|
1569
|
+
function bigint(value) {
|
|
1570
|
+
if (typeof value !== 'bigint')
|
|
1571
|
+
throw internalBridgeError();
|
|
1572
|
+
return value;
|
|
1573
|
+
}
|
|
1574
|
+
function bytes(value, expectedLength) {
|
|
1575
|
+
const result = value instanceof Uint8Array
|
|
1576
|
+
? new Uint8Array(value)
|
|
1577
|
+
: Array.isArray(value)
|
|
1578
|
+
? Uint8Array.from(value.map(byte))
|
|
1579
|
+
: null;
|
|
1580
|
+
if (!result || (expectedLength !== undefined && result.length !== expectedLength)) {
|
|
1581
|
+
throw internalBridgeError();
|
|
1582
|
+
}
|
|
1583
|
+
return result;
|
|
1584
|
+
}
|
|
1585
|
+
function optionalBytes(value, expectedLength) {
|
|
1586
|
+
return value === undefined || value === null ? null : bytes(value, expectedLength);
|
|
1587
|
+
}
|
|
1588
|
+
function byte(value) {
|
|
1589
|
+
const result = number(value);
|
|
1590
|
+
if (result < 0 || result > 255)
|
|
1591
|
+
throw internalBridgeError();
|
|
1592
|
+
return result;
|
|
1593
|
+
}
|
|
1594
|
+
function u16(value) {
|
|
1595
|
+
const result = number(value);
|
|
1596
|
+
if (result < 0 || result > 0xffff)
|
|
1597
|
+
throw internalBridgeError();
|
|
1598
|
+
return result;
|
|
1599
|
+
}
|
|
1600
|
+
function u32(value) {
|
|
1601
|
+
return u32Value(number(value));
|
|
1602
|
+
}
|
|
1603
|
+
function u32Value(value) {
|
|
1604
|
+
if (value < 0 || value > 0xffff_ffff)
|
|
1605
|
+
throw internalBridgeError();
|
|
1606
|
+
return value;
|
|
1607
|
+
}
|
|
1608
|
+
function numbers(value) {
|
|
1609
|
+
if (!Array.isArray(value))
|
|
1610
|
+
throw internalBridgeError();
|
|
1611
|
+
return value.map(number);
|
|
1612
|
+
}
|
|
1613
|
+
function rawBytes(value) {
|
|
1614
|
+
return [...value];
|
|
1615
|
+
}
|
|
1616
|
+
function scrubBridgeBytes(value, seen = new Set()) {
|
|
1617
|
+
if (value instanceof Uint8Array) {
|
|
1618
|
+
value.fill(0);
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
if (Array.isArray(value)) {
|
|
1622
|
+
if (value.every((item) => typeof item === 'number')) {
|
|
1623
|
+
value.fill(0);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
for (const item of value)
|
|
1627
|
+
scrubBridgeBytes(item, seen);
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (typeof value !== 'object' || value === null || seen.has(value))
|
|
1631
|
+
return;
|
|
1632
|
+
seen.add(value);
|
|
1633
|
+
for (const item of Object.values(value))
|
|
1634
|
+
scrubBridgeBytes(item, seen);
|
|
1635
|
+
}
|
|
1636
|
+
function enumValue(value, values) {
|
|
1637
|
+
const key = string(value);
|
|
1638
|
+
const result = values[key];
|
|
1639
|
+
if (!result)
|
|
1640
|
+
throw internalBridgeError();
|
|
1641
|
+
return result;
|
|
1642
|
+
}
|
|
1643
|
+
function reverseEnumValue(value, values) {
|
|
1644
|
+
const entry = Object.entries(values).find(([, normalized]) => normalized === value);
|
|
1645
|
+
if (!entry)
|
|
1646
|
+
throw internalBridgeError();
|
|
1647
|
+
return entry[0];
|
|
1648
|
+
}
|
|
1649
|
+
function internalBridgeError() {
|
|
1650
|
+
return new BotaSDKError('internal_error', 'unknown');
|
|
1651
|
+
}
|