@onekeyfe/hd-core 1.2.0-alpha.75 → 1.2.0-alpha.77
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 +45 -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 +86 -31
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +121 -0
- package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
- package/__tests__/protocol-v2.test.ts +405 -100
- 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 -5
- 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 +3088 -1063
- 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 +308 -121
- package/src/api/FirmwareUpdateV3.ts +265 -58
- package/src/api/FirmwareUpdateV4.ts +881 -349
- 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 +62 -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,20 @@ 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
|
+
Log.warn(
|
|
420
|
+
'[DataConfig] External firmware config is unavailable; SDK-managed networking remains disabled'
|
|
421
|
+
);
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
if (manifestMode !== 'sdk-managed') {
|
|
412
425
|
return false;
|
|
413
426
|
}
|
|
414
427
|
|
|
@@ -419,26 +432,19 @@ export default class DataManager {
|
|
|
419
432
|
const urlWithCache = `${url}?noCache=${getTimeStamp()}`;
|
|
420
433
|
let data: RemoteConfigResponse | null = null;
|
|
421
434
|
let fetchMethod: 'configFetcher' | 'axios' | 'none' = 'none';
|
|
422
|
-
|
|
423
|
-
// 1. Try custom configFetcher first (client-side IP direct connection support)
|
|
424
435
|
if (settings.configFetcher) {
|
|
425
|
-
Log.debug('[DataConfig] Trying
|
|
436
|
+
Log.debug('[DataConfig] Trying client configFetcher...');
|
|
426
437
|
try {
|
|
427
438
|
data = await settings.configFetcher(urlWithCache);
|
|
428
439
|
if (data) {
|
|
429
440
|
fetchMethod = 'configFetcher';
|
|
430
|
-
Log.log('[DataConfig] ConfigFetcher success');
|
|
431
|
-
} else {
|
|
432
|
-
Log.debug('[DataConfig] ConfigFetcher returned null, will fallback to axios');
|
|
433
441
|
}
|
|
434
442
|
} catch (e) {
|
|
435
|
-
Log.warn('[DataConfig]
|
|
443
|
+
Log.warn('[DataConfig] Client configFetcher failed:', e);
|
|
436
444
|
}
|
|
437
445
|
}
|
|
438
|
-
|
|
439
|
-
// 2. Fallback to default axios request
|
|
440
446
|
if (!data) {
|
|
441
|
-
Log.debug('[DataConfig] Trying
|
|
447
|
+
Log.debug('[DataConfig] Trying SDK-managed config request...');
|
|
442
448
|
try {
|
|
443
449
|
const response = await axios.get<RemoteConfigResponse>(urlWithCache, {
|
|
444
450
|
// because of iframe timeout is 10000
|
|
@@ -446,61 +452,63 @@ export default class DataManager {
|
|
|
446
452
|
});
|
|
447
453
|
data = response.data;
|
|
448
454
|
fetchMethod = 'axios';
|
|
449
|
-
Log.log('[DataConfig]
|
|
455
|
+
Log.log('[DataConfig] SDK-managed config request succeeded');
|
|
450
456
|
} catch (e) {
|
|
451
|
-
Log.warn('[DataConfig]
|
|
457
|
+
Log.warn('[DataConfig] SDK-managed config request failed:', e);
|
|
452
458
|
}
|
|
453
459
|
}
|
|
454
460
|
|
|
455
|
-
// 3. Apply config if available
|
|
456
461
|
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;
|
|
462
|
+
this.applyRemoteConfig(data);
|
|
478
463
|
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
464
|
return true;
|
|
499
465
|
}
|
|
500
466
|
Log.warn('[DataConfig] All fetch methods failed, using built-in default config');
|
|
501
467
|
return false;
|
|
502
468
|
}
|
|
503
469
|
|
|
470
|
+
private static applyRemoteConfig(data: RemoteConfigResponse) {
|
|
471
|
+
let pro2Resources: IProtocolV2Resources | undefined;
|
|
472
|
+
let neoResources: IProtocolV2Resources | undefined;
|
|
473
|
+
try {
|
|
474
|
+
pro2Resources = parseProtocolV2Resources(
|
|
475
|
+
(data.pro2 as { resources?: unknown } | undefined)?.resources
|
|
476
|
+
);
|
|
477
|
+
neoResources = parseProtocolV2Resources(
|
|
478
|
+
(data.neo as { resources?: unknown } | undefined)?.resources
|
|
479
|
+
);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
// Firmware resource metadata is not required for base communication. If the
|
|
482
|
+
// remote config is temporarily incomplete, disable this resource update only.
|
|
483
|
+
this.protocolV2ResourcesConfigError =
|
|
484
|
+
error instanceof Error ? error : new Error(String(error));
|
|
485
|
+
Log.warn('[DataConfig] Ignoring invalid Protocol V2 resources config:', error);
|
|
486
|
+
}
|
|
487
|
+
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
488
|
+
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
489
|
+
const { resources: _unvalidatedResources, ...pro2Config } = enrichedPro2Config;
|
|
490
|
+
const { resources: _unvalidatedNeoResources, ...neoConfig } = enrichedNeoConfig;
|
|
491
|
+
this.deviceMap = {
|
|
492
|
+
[EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
|
|
493
|
+
[EDeviceType.Classic1s]: this.enrichFirmwareReleaseInfo(data.classic1s),
|
|
494
|
+
[EDeviceType.ClassicPure]: this.enrichFirmwareReleaseInfo(data.classicpure),
|
|
495
|
+
[EDeviceType.Mini]: this.enrichFirmwareReleaseInfo(data.mini),
|
|
496
|
+
[EDeviceType.Touch]: this.enrichFirmwareReleaseInfo(data.touch),
|
|
497
|
+
[EDeviceType.Pro]: this.enrichFirmwareReleaseInfo(data.pro),
|
|
498
|
+
[EDeviceType.Pro2]: {
|
|
499
|
+
...pro2Config,
|
|
500
|
+
...(pro2Resources ? { resources: pro2Resources } : undefined),
|
|
501
|
+
},
|
|
502
|
+
[EDeviceType.Neo]: {
|
|
503
|
+
...neoConfig,
|
|
504
|
+
...(neoResources ? { resources: neoResources } : undefined),
|
|
505
|
+
},
|
|
506
|
+
};
|
|
507
|
+
this.assets = {
|
|
508
|
+
bridge: data.bridge,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
504
512
|
static updateEnv(newEnv: ConnectSettings['env']) {
|
|
505
513
|
if (this.settings) {
|
|
506
514
|
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 = {
|
|
@@ -909,7 +914,7 @@ export class Device extends EventEmitter {
|
|
|
909
914
|
const initStartAt = Date.now();
|
|
910
915
|
const { message } = await this.commands.typedCall('Initialize', 'Features', payload, {
|
|
911
916
|
// iOS BLE bound devices can need close to 20 seconds.
|
|
912
|
-
timeoutMs: 25 * 1000,
|
|
917
|
+
timeoutMs: options?.timeoutMs ?? 25 * 1000,
|
|
913
918
|
});
|
|
914
919
|
this.setLastInitializeDuration(Date.now() - initStartAt);
|
|
915
920
|
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,
|