@onekeyfe/hd-core 1.2.0-alpha.66 → 1.2.0-alpha.68
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/__tests__/connectSettings.test.ts +47 -5
- package/__tests__/device-initialize-timeout.test.ts +56 -0
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +87 -0
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
- package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +200 -0
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +394 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +231 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +59 -31
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +63 -0
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/protocol-v2.test.ts +371 -94
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +10 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +7 -3
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +25 -4
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +8 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +32 -0
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/api/firmware/getBinary.d.ts +7 -0
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +2 -0
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +9 -1
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/data-manager/DataManager.d.ts +1 -0
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/index.d.ts +179 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3020 -955
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +4 -0
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +4 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +68 -0
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
- package/dist/types/api/index.d.ts +9 -1
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +1 -0
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +57 -6
- package/src/api/FirmwareUpdate.ts +13 -1
- package/src/api/FirmwareUpdateV2.ts +296 -121
- package/src/api/FirmwareUpdateV3.ts +263 -57
- package/src/api/FirmwareUpdateV4.ts +863 -243
- package/src/api/device/DeviceUpdateBootloader.ts +125 -6
- package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
- package/src/api/firmware/FirmwareHostBinding.ts +100 -0
- package/src/api/firmware/FirmwarePreparationError.ts +12 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +72 -1
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
- package/src/api/firmware/FirmwareUpdatePlan.ts +772 -0
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +449 -0
- package/src/api/firmware/updateBootloader.ts +19 -4
- package/src/api/firmware/uploadFirmware.ts +140 -22
- package/src/data-manager/DataManager.ts +59 -54
- package/src/data-manager/connectSettings.ts +11 -0
- package/src/device/Device.ts +6 -1
- package/src/index.ts +5 -0
- package/src/inject.ts +22 -2
- package/src/lowLevelInject.ts +5 -1
- package/src/topLevelInject.ts +5 -1
- package/src/types/api/checkAllFirmwareRelease.ts +4 -0
- package/src/types/api/deviceUpdateBootloader.ts +6 -0
- package/src/types/api/export.ts +18 -0
- package/src/types/api/firmwareUpdate.ts +75 -0
- package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
- package/src/types/api/firmwareUpdatePlan.ts +38 -0
- package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
- package/src/types/api/index.ts +14 -0
- package/src/types/settings.ts +13 -0
- package/src/utils/deviceFeaturesCompat.ts +6 -0
|
@@ -10,6 +10,7 @@ import { bytesToHex } from '../helpers/hexUtils';
|
|
|
10
10
|
import { DataManager } from '../../data-manager';
|
|
11
11
|
import { DevicePool } from '../../device/DevicePool';
|
|
12
12
|
import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
|
|
13
|
+
import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
|
|
13
14
|
|
|
14
15
|
import type { KnownDevice } from '../../types';
|
|
15
16
|
import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
|
|
@@ -17,6 +18,7 @@ import type { PROTO } from '../../constants';
|
|
|
17
18
|
import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
|
|
18
19
|
import type { Success } from '@onekeyfe/hd-transport';
|
|
19
20
|
import type { Device } from '../../device/Device';
|
|
21
|
+
import type { FirmwareByteSource } from './FirmwareArtifactSource';
|
|
20
22
|
|
|
21
23
|
const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
|
|
22
24
|
const SESSION_ERROR = 'session not found';
|
|
@@ -88,17 +90,20 @@ export const waitBleInstall = async (updateType: string) => {
|
|
|
88
90
|
}
|
|
89
91
|
};
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
const toArrayBuffer = (payload: ArrayBuffer | Buffer): ArrayBuffer => {
|
|
94
|
+
if (payload instanceof ArrayBuffer) {
|
|
95
|
+
return payload;
|
|
96
|
+
}
|
|
97
|
+
return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const uploadFirmwareFromSource = async (
|
|
92
101
|
updateType: 'firmware' | 'ble',
|
|
93
102
|
typedCall: TypedCall,
|
|
94
103
|
postMessage: (message: CoreMessage) => void,
|
|
95
104
|
device: Device,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
rebootOnSuccess,
|
|
99
|
-
}: PROTO.FirmwareUpload & {
|
|
100
|
-
rebootOnSuccess?: boolean;
|
|
101
|
-
},
|
|
105
|
+
source: FirmwareByteSource,
|
|
106
|
+
rebootOnSuccess?: boolean,
|
|
102
107
|
isUpdateBootloader?: boolean
|
|
103
108
|
) => {
|
|
104
109
|
const deviceType = device.getCurrentDeviceType();
|
|
@@ -119,20 +124,20 @@ export const uploadFirmware = async (
|
|
|
119
124
|
if (supportUpgradeFileHeader) {
|
|
120
125
|
// Extract and validate firmware header (first 1KB)
|
|
121
126
|
const HEADER_SIZE = 1024;
|
|
122
|
-
if (
|
|
127
|
+
if (source.size < HEADER_SIZE) {
|
|
123
128
|
throw ERRORS.TypedError(
|
|
124
129
|
HardwareErrorCode.RuntimeError,
|
|
125
|
-
`firmware payload too small: ${
|
|
130
|
+
`firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
|
|
126
131
|
);
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
Log.debug('Uploading firmware header:', {
|
|
130
135
|
size: HEADER_SIZE,
|
|
131
|
-
totalSize:
|
|
136
|
+
totalSize: source.size,
|
|
132
137
|
});
|
|
133
138
|
postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
|
|
134
139
|
|
|
135
|
-
const header = new Uint8Array(
|
|
140
|
+
const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
|
|
136
141
|
|
|
137
142
|
try {
|
|
138
143
|
const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
|
|
@@ -169,6 +174,9 @@ export const uploadFirmware = async (
|
|
|
169
174
|
postProgressMessage(device, 0, 'installingFirmware', postMessage);
|
|
170
175
|
let updateResponse: TypedResponseMessage<'Success'>;
|
|
171
176
|
try {
|
|
177
|
+
// Classic/Mini bootloaders accept one protobuf payload and do not expose
|
|
178
|
+
// a request-range protocol. Other device families remain fully streamed.
|
|
179
|
+
const payload = await readFirmwareByteSourceFully(source);
|
|
172
180
|
updateResponse = await typedCall('FirmwareUpload', 'Success', {
|
|
173
181
|
payload,
|
|
174
182
|
});
|
|
@@ -200,9 +208,7 @@ export const uploadFirmware = async (
|
|
|
200
208
|
updateType,
|
|
201
209
|
postMessage,
|
|
202
210
|
device,
|
|
203
|
-
|
|
204
|
-
payload,
|
|
205
|
-
},
|
|
211
|
+
source,
|
|
206
212
|
rebootOnSuccess
|
|
207
213
|
);
|
|
208
214
|
return response.message;
|
|
@@ -211,7 +217,7 @@ export const uploadFirmware = async (
|
|
|
211
217
|
|
|
212
218
|
postConfirmationMessage(device);
|
|
213
219
|
postProgressTip(device, 'ConfirmOnDevice', postMessage);
|
|
214
|
-
const length =
|
|
220
|
+
const length = source.size;
|
|
215
221
|
|
|
216
222
|
let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
|
|
217
223
|
postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
|
|
@@ -220,7 +226,7 @@ export const uploadFirmware = async (
|
|
|
220
226
|
const start = response.message.offset!;
|
|
221
227
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
222
228
|
const end = response.message.offset! + response.message.length!;
|
|
223
|
-
const chunk =
|
|
229
|
+
const chunk = await source.readAt(start, end - start);
|
|
224
230
|
|
|
225
231
|
if (start > 0) {
|
|
226
232
|
postProgressMessage(
|
|
@@ -249,11 +255,45 @@ export const uploadFirmware = async (
|
|
|
249
255
|
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
|
|
250
256
|
};
|
|
251
257
|
|
|
258
|
+
export const uploadFirmware = async (
|
|
259
|
+
updateType: 'firmware' | 'ble',
|
|
260
|
+
typedCall: TypedCall,
|
|
261
|
+
postMessage: (message: CoreMessage) => void,
|
|
262
|
+
device: Device,
|
|
263
|
+
{
|
|
264
|
+
payload,
|
|
265
|
+
rebootOnSuccess,
|
|
266
|
+
}: PROTO.FirmwareUpload & {
|
|
267
|
+
rebootOnSuccess?: boolean;
|
|
268
|
+
},
|
|
269
|
+
isUpdateBootloader?: boolean
|
|
270
|
+
) => {
|
|
271
|
+
const source = await openFirmwareByteSource({
|
|
272
|
+
binary: toArrayBuffer(payload),
|
|
273
|
+
});
|
|
274
|
+
if (!source) {
|
|
275
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
return await uploadFirmwareFromSource(
|
|
279
|
+
updateType,
|
|
280
|
+
typedCall,
|
|
281
|
+
postMessage,
|
|
282
|
+
device,
|
|
283
|
+
source,
|
|
284
|
+
rebootOnSuccess,
|
|
285
|
+
isUpdateBootloader
|
|
286
|
+
);
|
|
287
|
+
} finally {
|
|
288
|
+
await source.close();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
252
292
|
const newTouchUpdateProcess = async (
|
|
253
293
|
updateType: 'firmware' | 'ble',
|
|
254
294
|
postMessage: (message: CoreMessage) => void,
|
|
255
295
|
device: Device,
|
|
256
|
-
|
|
296
|
+
source: FirmwareByteSource,
|
|
257
297
|
rebootOnSuccess = true
|
|
258
298
|
) => {
|
|
259
299
|
let typedCall = device.getCommands().typedCall.bind(device.getCommands());
|
|
@@ -263,13 +303,13 @@ const newTouchUpdateProcess = async (
|
|
|
263
303
|
const env = DataManager.getSettings('env');
|
|
264
304
|
const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
|
|
265
305
|
const chunkSize = 1024 * perPackageSize;
|
|
266
|
-
const totalChunks = Math.ceil(
|
|
306
|
+
const totalChunks = Math.ceil(source.size / chunkSize);
|
|
267
307
|
let offset = 0;
|
|
268
308
|
for (let i = 0; i < totalChunks; i++) {
|
|
269
309
|
const chunkStart = i * chunkSize;
|
|
270
|
-
const chunkEnd = Math.min(chunkStart + chunkSize,
|
|
310
|
+
const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
|
|
271
311
|
const chunkLength = chunkEnd - chunkStart;
|
|
272
|
-
const chunk =
|
|
312
|
+
const chunk = await source.readAt(chunkStart, chunkLength);
|
|
273
313
|
const overwrite = i === 0;
|
|
274
314
|
const progress = Math.round(((i + 1) / totalChunks) * 100);
|
|
275
315
|
const writeRes = await emmcFileWriteWithRetry(
|
|
@@ -503,6 +543,67 @@ export const updateResource = async (
|
|
|
503
543
|
return processResourceRequest(typedCall, res, data);
|
|
504
544
|
};
|
|
505
545
|
|
|
546
|
+
export const updateResourceFromSource = async (
|
|
547
|
+
typedCall: TypedCall,
|
|
548
|
+
fileName: string,
|
|
549
|
+
source: FirmwareByteSource,
|
|
550
|
+
onConfirmAfter?: () => void
|
|
551
|
+
) => {
|
|
552
|
+
const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
|
|
553
|
+
const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
|
|
554
|
+
let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
|
|
555
|
+
file_name: fileName,
|
|
556
|
+
data_length: source.size,
|
|
557
|
+
initial_data_chunk: bytesToHex(initialChunk),
|
|
558
|
+
hash: bytesToHex(blake2s(initialChunk)),
|
|
559
|
+
});
|
|
560
|
+
onConfirmAfter?.();
|
|
561
|
+
|
|
562
|
+
while (response.type !== 'Success') {
|
|
563
|
+
const { offset, data_length: dataLength } = response.message;
|
|
564
|
+
if (
|
|
565
|
+
!Number.isSafeInteger(offset) ||
|
|
566
|
+
offset === undefined ||
|
|
567
|
+
offset < 0 ||
|
|
568
|
+
!Number.isSafeInteger(dataLength) ||
|
|
569
|
+
dataLength === undefined ||
|
|
570
|
+
dataLength <= 0 ||
|
|
571
|
+
offset + dataLength > source.size
|
|
572
|
+
) {
|
|
573
|
+
throw ERRORS.TypedError(
|
|
574
|
+
HardwareErrorCode.RuntimeError,
|
|
575
|
+
'Device requested an invalid firmware resource range'
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
const chunk = new Uint8Array(await source.readAt(offset, dataLength));
|
|
579
|
+
response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
|
|
580
|
+
data_chunk: bytesToHex(chunk),
|
|
581
|
+
hash: bytesToHex(blake2s(chunk)),
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
return response.message;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
export const updateResourcesFromSources = async (
|
|
588
|
+
typedCall: TypedCall,
|
|
589
|
+
postMessage: (message: CoreMessage) => void,
|
|
590
|
+
device: Device,
|
|
591
|
+
entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
|
|
592
|
+
) => {
|
|
593
|
+
postProgressTip(device, 'UpdateSysResource', postMessage);
|
|
594
|
+
for (const [index, entry] of entries.entries()) {
|
|
595
|
+
await updateResourceFromSource(typedCall, entry.entryName, entry.source);
|
|
596
|
+
postProgressMessage(
|
|
597
|
+
device,
|
|
598
|
+
Math.floor(((index + 1) / entries.length) * 100),
|
|
599
|
+
'installingFirmware',
|
|
600
|
+
postMessage
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
|
|
604
|
+
return true;
|
|
605
|
+
};
|
|
606
|
+
|
|
506
607
|
export const updateResources = async (
|
|
507
608
|
typedCall: TypedCall,
|
|
508
609
|
postMessage: (message: CoreMessage) => void,
|
|
@@ -537,11 +638,28 @@ export const updateBootloader = async (
|
|
|
537
638
|
typedCall: TypedCall,
|
|
538
639
|
postMessage: (message: CoreMessage) => void,
|
|
539
640
|
device: Device,
|
|
540
|
-
|
|
641
|
+
data: ArrayBuffer
|
|
642
|
+
) => {
|
|
643
|
+
const source = await openFirmwareByteSource({ binary: data });
|
|
644
|
+
if (!source) {
|
|
645
|
+
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
|
|
646
|
+
}
|
|
647
|
+
try {
|
|
648
|
+
return await updateBootloaderFromSource(typedCall, postMessage, device, source);
|
|
649
|
+
} finally {
|
|
650
|
+
await source.close();
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
export const updateBootloaderFromSource = async (
|
|
655
|
+
typedCall: TypedCall,
|
|
656
|
+
postMessage: (message: CoreMessage) => void,
|
|
657
|
+
device: Device,
|
|
658
|
+
source: FirmwareByteSource
|
|
541
659
|
) => {
|
|
542
660
|
postProgressTip(device, 'UpdateBootloader', postMessage);
|
|
543
661
|
postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
|
|
544
|
-
await
|
|
662
|
+
await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
|
|
545
663
|
postProcessingMessage('resource', postMessage);
|
|
546
664
|
});
|
|
547
665
|
postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
|
|
@@ -408,7 +408,17 @@ export default class DataManager {
|
|
|
408
408
|
static async load(settings: ConnectSettings): Promise<boolean> {
|
|
409
409
|
this.settings = settings;
|
|
410
410
|
this.protocolV2ResourcesConfigError = undefined;
|
|
411
|
-
|
|
411
|
+
const manifestMode =
|
|
412
|
+
settings.firmwareManifestMode ?? (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
413
|
+
if (settings.preloadedConfig) {
|
|
414
|
+
this.applyRemoteConfig(settings.preloadedConfig);
|
|
415
|
+
Log.log('[DataConfig] Preloaded firmware config loaded');
|
|
416
|
+
return true;
|
|
417
|
+
}
|
|
418
|
+
if (manifestMode === 'external-only') {
|
|
419
|
+
throw new Error('External firmware config snapshot is required');
|
|
420
|
+
}
|
|
421
|
+
if (manifestMode !== 'sdk-managed') {
|
|
412
422
|
return false;
|
|
413
423
|
}
|
|
414
424
|
|
|
@@ -419,26 +429,19 @@ export default class DataManager {
|
|
|
419
429
|
const urlWithCache = `${url}?noCache=${getTimeStamp()}`;
|
|
420
430
|
let data: RemoteConfigResponse | null = null;
|
|
421
431
|
let fetchMethod: 'configFetcher' | 'axios' | 'none' = 'none';
|
|
422
|
-
|
|
423
|
-
// 1. Try custom configFetcher first (client-side IP direct connection support)
|
|
424
432
|
if (settings.configFetcher) {
|
|
425
|
-
Log.debug('[DataConfig] Trying
|
|
433
|
+
Log.debug('[DataConfig] Trying client configFetcher...');
|
|
426
434
|
try {
|
|
427
435
|
data = await settings.configFetcher(urlWithCache);
|
|
428
436
|
if (data) {
|
|
429
437
|
fetchMethod = 'configFetcher';
|
|
430
|
-
Log.log('[DataConfig] ConfigFetcher success');
|
|
431
|
-
} else {
|
|
432
|
-
Log.debug('[DataConfig] ConfigFetcher returned null, will fallback to axios');
|
|
433
438
|
}
|
|
434
439
|
} catch (e) {
|
|
435
|
-
Log.warn('[DataConfig]
|
|
440
|
+
Log.warn('[DataConfig] Client configFetcher failed:', e);
|
|
436
441
|
}
|
|
437
442
|
}
|
|
438
|
-
|
|
439
|
-
// 2. Fallback to default axios request
|
|
440
443
|
if (!data) {
|
|
441
|
-
Log.debug('[DataConfig] Trying
|
|
444
|
+
Log.debug('[DataConfig] Trying SDK-managed config request...');
|
|
442
445
|
try {
|
|
443
446
|
const response = await axios.get<RemoteConfigResponse>(urlWithCache, {
|
|
444
447
|
// because of iframe timeout is 10000
|
|
@@ -446,61 +449,63 @@ export default class DataManager {
|
|
|
446
449
|
});
|
|
447
450
|
data = response.data;
|
|
448
451
|
fetchMethod = 'axios';
|
|
449
|
-
Log.log('[DataConfig]
|
|
452
|
+
Log.log('[DataConfig] SDK-managed config request succeeded');
|
|
450
453
|
} catch (e) {
|
|
451
|
-
Log.warn('[DataConfig]
|
|
454
|
+
Log.warn('[DataConfig] SDK-managed config request failed:', e);
|
|
452
455
|
}
|
|
453
456
|
}
|
|
454
457
|
|
|
455
|
-
// 3. Apply config if available
|
|
456
458
|
if (data) {
|
|
457
|
-
|
|
458
|
-
let neoResources: IProtocolV2Resources | undefined;
|
|
459
|
-
this.protocolV2ResourcesConfigError = undefined;
|
|
460
|
-
try {
|
|
461
|
-
pro2Resources = parseProtocolV2Resources(
|
|
462
|
-
(data.pro2 as { resources?: unknown } | undefined)?.resources
|
|
463
|
-
);
|
|
464
|
-
neoResources = parseProtocolV2Resources(
|
|
465
|
-
(data.neo as { resources?: unknown } | undefined)?.resources
|
|
466
|
-
);
|
|
467
|
-
} catch (error) {
|
|
468
|
-
// Firmware resource metadata is not required for base communication. If the
|
|
469
|
-
// remote config is temporarily incomplete, disable this resource update only.
|
|
470
|
-
this.protocolV2ResourcesConfigError =
|
|
471
|
-
error instanceof Error ? error : new Error(String(error));
|
|
472
|
-
Log.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
|
|
473
|
-
}
|
|
474
|
-
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
475
|
-
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
476
|
-
const { resources: _unvalidatedResources, ...pro2Config } = enrichedPro2Config;
|
|
477
|
-
const { resources: _unvalidatedNeoResources, ...neoConfig } = enrichedNeoConfig;
|
|
459
|
+
this.applyRemoteConfig(data);
|
|
478
460
|
Log.log(`[DataConfig] Config loaded successfully via [${fetchMethod}]`);
|
|
479
|
-
this.deviceMap = {
|
|
480
|
-
[EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
|
|
481
|
-
[EDeviceType.Classic1s]: this.enrichFirmwareReleaseInfo(data.classic1s),
|
|
482
|
-
[EDeviceType.ClassicPure]: this.enrichFirmwareReleaseInfo(data.classicpure),
|
|
483
|
-
[EDeviceType.Mini]: this.enrichFirmwareReleaseInfo(data.mini),
|
|
484
|
-
[EDeviceType.Touch]: this.enrichFirmwareReleaseInfo(data.touch),
|
|
485
|
-
[EDeviceType.Pro]: this.enrichFirmwareReleaseInfo(data.pro),
|
|
486
|
-
[EDeviceType.Pro2]: {
|
|
487
|
-
...pro2Config,
|
|
488
|
-
...(pro2Resources ? { resources: pro2Resources } : undefined),
|
|
489
|
-
},
|
|
490
|
-
[EDeviceType.Neo]: {
|
|
491
|
-
...neoConfig,
|
|
492
|
-
...(neoResources ? { resources: neoResources } : undefined),
|
|
493
|
-
},
|
|
494
|
-
};
|
|
495
|
-
this.assets = {
|
|
496
|
-
bridge: data.bridge,
|
|
497
|
-
};
|
|
498
461
|
return true;
|
|
499
462
|
}
|
|
500
463
|
Log.warn('[DataConfig] All fetch methods failed, using built-in default config');
|
|
501
464
|
return false;
|
|
502
465
|
}
|
|
503
466
|
|
|
467
|
+
private static applyRemoteConfig(data: RemoteConfigResponse) {
|
|
468
|
+
let pro2Resources: IProtocolV2Resources | undefined;
|
|
469
|
+
let neoResources: IProtocolV2Resources | undefined;
|
|
470
|
+
try {
|
|
471
|
+
pro2Resources = parseProtocolV2Resources(
|
|
472
|
+
(data.pro2 as { resources?: unknown } | undefined)?.resources
|
|
473
|
+
);
|
|
474
|
+
neoResources = parseProtocolV2Resources(
|
|
475
|
+
(data.neo as { resources?: unknown } | undefined)?.resources
|
|
476
|
+
);
|
|
477
|
+
} catch (error) {
|
|
478
|
+
// Firmware resource metadata is not required for base communication. If the
|
|
479
|
+
// remote config is temporarily incomplete, disable this resource update only.
|
|
480
|
+
this.protocolV2ResourcesConfigError =
|
|
481
|
+
error instanceof Error ? error : new Error(String(error));
|
|
482
|
+
Log.warn('[DataConfig] Ignoring invalid Protocol V2 resources config:', error);
|
|
483
|
+
}
|
|
484
|
+
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
485
|
+
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
486
|
+
const { resources: _unvalidatedResources, ...pro2Config } = enrichedPro2Config;
|
|
487
|
+
const { resources: _unvalidatedNeoResources, ...neoConfig } = enrichedNeoConfig;
|
|
488
|
+
this.deviceMap = {
|
|
489
|
+
[EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
|
|
490
|
+
[EDeviceType.Classic1s]: this.enrichFirmwareReleaseInfo(data.classic1s),
|
|
491
|
+
[EDeviceType.ClassicPure]: this.enrichFirmwareReleaseInfo(data.classicpure),
|
|
492
|
+
[EDeviceType.Mini]: this.enrichFirmwareReleaseInfo(data.mini),
|
|
493
|
+
[EDeviceType.Touch]: this.enrichFirmwareReleaseInfo(data.touch),
|
|
494
|
+
[EDeviceType.Pro]: this.enrichFirmwareReleaseInfo(data.pro),
|
|
495
|
+
[EDeviceType.Pro2]: {
|
|
496
|
+
...pro2Config,
|
|
497
|
+
...(pro2Resources ? { resources: pro2Resources } : undefined),
|
|
498
|
+
},
|
|
499
|
+
[EDeviceType.Neo]: {
|
|
500
|
+
...neoConfig,
|
|
501
|
+
...(neoResources ? { resources: neoResources } : undefined),
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
this.assets = {
|
|
505
|
+
bridge: data.bridge,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
|
|
504
509
|
static updateEnv(newEnv: ConnectSettings['env']) {
|
|
505
510
|
if (this.settings) {
|
|
506
511
|
const prevEnv = this.settings.env;
|
|
@@ -115,10 +115,21 @@ export const parseConnectSettings = (input: Partial<ConnectSettings> = {}) => {
|
|
|
115
115
|
settings.fetchConfig = input.fetchConfig;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
if (
|
|
119
|
+
input.firmwareManifestMode === 'sdk-managed' ||
|
|
120
|
+
input.firmwareManifestMode === 'external-only'
|
|
121
|
+
) {
|
|
122
|
+
settings.firmwareManifestMode = input.firmwareManifestMode;
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
if (input.configFetcher) {
|
|
119
126
|
settings.configFetcher = input.configFetcher;
|
|
120
127
|
}
|
|
121
128
|
|
|
129
|
+
if (input.preloadedConfig) {
|
|
130
|
+
settings.preloadedConfig = input.preloadedConfig;
|
|
131
|
+
}
|
|
132
|
+
|
|
122
133
|
return settings;
|
|
123
134
|
};
|
|
124
135
|
|
package/src/device/Device.ts
CHANGED
|
@@ -99,6 +99,11 @@ export type InitOptions = {
|
|
|
99
99
|
protocolV2DeviceInfoTimeoutMs?: number;
|
|
100
100
|
/** Refresh Protocol V2 runtime state before returning discovery results. */
|
|
101
101
|
refreshRuntimeState?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Protocol V1 Initialize response timeout override. Reboot-wait polling passes a
|
|
104
|
+
* short value so an unanswered probe settles before the next poll tick.
|
|
105
|
+
*/
|
|
106
|
+
timeoutMs?: number;
|
|
102
107
|
};
|
|
103
108
|
|
|
104
109
|
export type RunOptions = {
|
|
@@ -908,7 +913,7 @@ export class Device extends EventEmitter {
|
|
|
908
913
|
const initStartAt = Date.now();
|
|
909
914
|
const { message } = await this.commands.typedCall('Initialize', 'Features', payload, {
|
|
910
915
|
// iOS BLE bound devices can need close to 20 seconds.
|
|
911
|
-
timeoutMs: 25 * 1000,
|
|
916
|
+
timeoutMs: options?.timeoutMs ?? 25 * 1000,
|
|
912
917
|
});
|
|
913
918
|
this.setLastInitializeDuration(Date.now() - initStartAt);
|
|
914
919
|
this._updateFeatures(message, initSession);
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,11 @@ export * from './types';
|
|
|
19
19
|
export { whitelist, whitelistExtension } from './data/config';
|
|
20
20
|
export { executeCallback, cleanupCallback };
|
|
21
21
|
export { preloadSessionCache } from './device/Device';
|
|
22
|
+
export {
|
|
23
|
+
getFirmwareUpdateHostBindingGeneration,
|
|
24
|
+
registerFirmwareUpdateHostBinding,
|
|
25
|
+
unregisterFirmwareUpdateHostBinding,
|
|
26
|
+
} from './api/firmware/FirmwareHostBinding';
|
|
22
27
|
|
|
23
28
|
const HardwareSdk = ({
|
|
24
29
|
init,
|
package/src/inject.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
import { getFirmwareUpdateCapabilities } from './api/firmware/FirmwareUpdateCapabilities';
|
|
2
|
+
import {
|
|
3
|
+
prepareFirmwareUpdatePlan,
|
|
4
|
+
validateFirmwareUpdatePreparedPlan,
|
|
5
|
+
} from './api/firmware/FirmwareUpdatePreparedPlan';
|
|
6
|
+
import {
|
|
7
|
+
getFirmwareUpdateHostBindingGeneration,
|
|
8
|
+
registerFirmwareUpdateHostBinding,
|
|
9
|
+
unregisterFirmwareUpdateHostBinding,
|
|
10
|
+
} from './api/firmware/FirmwareHostBinding';
|
|
11
|
+
|
|
1
12
|
import type { HardwareConnectProtocol } from '@onekeyfe/hd-shared';
|
|
2
|
-
import type { Unsuccessful } from './types';
|
|
3
13
|
import type { EventEmitter } from 'events';
|
|
4
14
|
import type { CallMethod } from './events';
|
|
15
|
+
import type { Unsuccessful } from './types';
|
|
5
16
|
import type { CoreApi } from './types/api';
|
|
6
17
|
import type { AllNetworkAddress } from './types/api/allNetworkGetAddress';
|
|
7
18
|
|
|
@@ -116,7 +127,10 @@ export const inject = ({
|
|
|
116
127
|
|
|
117
128
|
setDeviceConnectProtocol: protocolAwareCall.setDeviceConnectProtocol,
|
|
118
129
|
|
|
119
|
-
dispose
|
|
130
|
+
dispose: async () => {
|
|
131
|
+
unregisterFirmwareUpdateHostBinding();
|
|
132
|
+
await dispose();
|
|
133
|
+
},
|
|
120
134
|
|
|
121
135
|
uiResponse,
|
|
122
136
|
|
|
@@ -148,6 +162,12 @@ export const createCoreApi = (
|
|
|
148
162
|
| 'updateSettings'
|
|
149
163
|
| 'switchTransport'
|
|
150
164
|
> => ({
|
|
165
|
+
getFirmwareUpdateCapabilities,
|
|
166
|
+
registerFirmwareUpdateHostBinding,
|
|
167
|
+
unregisterFirmwareUpdateHostBinding,
|
|
168
|
+
getFirmwareUpdateHostBindingGeneration,
|
|
169
|
+
prepareFirmwareUpdatePlan,
|
|
170
|
+
validateFirmwareUpdatePreparedPlan,
|
|
151
171
|
getLogs: () => call({ method: 'getLogs' }),
|
|
152
172
|
clearSessionCache: params => call({ ...params, method: 'clearSessionCache' }),
|
|
153
173
|
/**
|
package/src/lowLevelInject.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createCoreApi, createProtocolAwareCall } from './inject';
|
|
2
|
+
import { unregisterFirmwareUpdateHostBinding } from './api/firmware/FirmwareHostBinding';
|
|
2
3
|
|
|
3
4
|
import type { EventEmitter } from 'events';
|
|
4
5
|
import type { CallMethod, CoreMessage } from './events';
|
|
@@ -46,7 +47,10 @@ export const lowLevelInject = ({
|
|
|
46
47
|
|
|
47
48
|
setDeviceConnectProtocol: protocolAwareCall.setDeviceConnectProtocol,
|
|
48
49
|
|
|
49
|
-
dispose
|
|
50
|
+
dispose: async () => {
|
|
51
|
+
unregisterFirmwareUpdateHostBinding();
|
|
52
|
+
await dispose();
|
|
53
|
+
},
|
|
50
54
|
|
|
51
55
|
uiResponse,
|
|
52
56
|
|
package/src/topLevelInject.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import EventEmitter from 'events';
|
|
2
2
|
|
|
3
3
|
import { createCoreApi, createProtocolAwareCall } from './inject';
|
|
4
|
+
import { unregisterFirmwareUpdateHostBinding } from './api/firmware/FirmwareHostBinding';
|
|
4
5
|
|
|
5
6
|
import type { ConnectSettings } from './types/settings';
|
|
6
7
|
import type { CoreApi } from './types/api';
|
|
@@ -49,7 +50,10 @@ export const topLevelInject = () => {
|
|
|
49
50
|
lowLevelApi?.removeAllListeners(type);
|
|
50
51
|
},
|
|
51
52
|
|
|
52
|
-
dispose: () =>
|
|
53
|
+
dispose: async () => {
|
|
54
|
+
unregisterFirmwareUpdateHostBinding();
|
|
55
|
+
await lowLevelApi?.dispose();
|
|
56
|
+
},
|
|
53
57
|
|
|
54
58
|
uiResponse: response => lowLevelApi?.uiResponse(response),
|
|
55
59
|
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
IProtocolV2FirmwareComponentTarget,
|
|
13
13
|
} from '../settings';
|
|
14
14
|
import type { FirmwareUpdateV4Target } from './firmwareUpdate';
|
|
15
|
+
import type { FirmwareUpdatePlan, FirmwareUpdatePlanForceTarget } from './firmwareUpdatePlan';
|
|
15
16
|
|
|
16
17
|
export type FirmwareRelease = {
|
|
17
18
|
shouldUpdate?: boolean;
|
|
@@ -64,12 +65,15 @@ export type AllFirmwareRelease = {
|
|
|
64
65
|
components?: ProtocolV2FirmwareComponentRelease[];
|
|
65
66
|
targetsToUpdate?: FirmwareUpdateV4Target[];
|
|
66
67
|
release?: IFirmwareReleaseInfo;
|
|
68
|
+
firmwareUpdatePlan?: FirmwareUpdatePlan;
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
export type CheckAllFirmwareReleaseParams = {
|
|
70
72
|
checkBridgeRelease?: boolean;
|
|
71
73
|
checkFirmwareHash?: boolean;
|
|
72
74
|
firmwareType?: EFirmwareType;
|
|
75
|
+
platform?: 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
|
|
76
|
+
forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
|
|
73
77
|
};
|
|
74
78
|
|
|
75
79
|
export declare function checkAllFirmwareRelease(
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { Success } from '@onekeyfe/hd-transport';
|
|
2
2
|
import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
3
|
+
import type { FirmwareArtifactReader, FirmwareArtifactReference } from './firmwareUpdate';
|
|
4
|
+
import type { FirmwareUpdatePreparedPlan } from './firmwareUpdatePreparedPlan';
|
|
3
5
|
import type { Response } from '../params';
|
|
4
6
|
|
|
5
7
|
export type DeviceUpdateBootloaderParams = {
|
|
8
|
+
preparedPlan?: FirmwareUpdatePreparedPlan;
|
|
9
|
+
hostBindingGeneration?: number;
|
|
6
10
|
binary?: ArrayBuffer;
|
|
11
|
+
artifact?: FirmwareArtifactReference;
|
|
12
|
+
artifactReader?: FirmwareArtifactReader;
|
|
7
13
|
firmwareType?: EFirmwareType;
|
|
8
14
|
};
|
|
9
15
|
|
package/src/types/api/export.ts
CHANGED
|
@@ -26,12 +26,30 @@ export type {
|
|
|
26
26
|
DeviceUploadResourceResponse,
|
|
27
27
|
} from './deviceUploadResource';
|
|
28
28
|
export type {
|
|
29
|
+
FirmwareArtifactReader,
|
|
30
|
+
FirmwareArtifactReference,
|
|
31
|
+
FirmwareUpdateHostBinding,
|
|
32
|
+
FirmwareUpdateArtifactParams,
|
|
29
33
|
FirmwareUpdateParams,
|
|
30
34
|
FirmwareUpdateBinaryParams,
|
|
31
35
|
FirmwareUpdateV3Params,
|
|
32
36
|
FirmwareUpdateV4Params,
|
|
33
37
|
FirmwareUpdateV4Target,
|
|
34
38
|
} from './firmwareUpdate';
|
|
39
|
+
export type {
|
|
40
|
+
FirmwareUpdatePlan,
|
|
41
|
+
FirmwareUpdatePlanArtifact,
|
|
42
|
+
FirmwareUpdatePlanArtifactRole,
|
|
43
|
+
FirmwareUpdatePlanForceTarget,
|
|
44
|
+
FirmwareUpdatePlanTarget,
|
|
45
|
+
} from './firmwareUpdatePlan';
|
|
46
|
+
export type {
|
|
47
|
+
FirmwareUpdatePreparedArtifact,
|
|
48
|
+
FirmwareUpdatePreparedArtifactInput,
|
|
49
|
+
FirmwareUpdatePreparedEntry,
|
|
50
|
+
FirmwareUpdatePreparedPlan,
|
|
51
|
+
} from './firmwareUpdatePreparedPlan';
|
|
52
|
+
export type { FirmwareUpdateCapabilities } from './firmwareUpdateCapabilities';
|
|
35
53
|
export type { AllFirmwareRelease } from './checkAllFirmwareRelease';
|
|
36
54
|
export type {
|
|
37
55
|
ProtocolV2FirmwareComponentRelease,
|