@onekeyfe/hd-core 1.2.0-alpha.97 → 1.2.0-alpha.99
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__/check-all-firmware-release-protocol-v2.test.ts +411 -86
- package/__tests__/check-firmware-release-protocol-v2.test.ts +199 -0
- package/__tests__/firmware-memory-host.test.ts +126 -0
- package/__tests__/firmware-update/device-update-bootloader.test.ts +14 -2
- package/__tests__/firmware-update/firmware-host-binding.test.ts +9 -0
- package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +573 -0
- package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +150 -0
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +65 -2
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +80 -0
- package/__tests__/firmware-update/firmware-update-plan.test.ts +293 -71
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
- package/__tests__/firmware-update/firmware-update-prepared-resource-executors.test.ts +326 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +2 -2
- package/__tests__/protocol-v2-firmware-targets.test.ts +16 -0
- package/__tests__/protocol-v2-resources.test.ts +148 -232
- package/__tests__/protocol-v2.test.ts +1326 -510
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -3
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBLEFirmwareRelease.d.ts +3 -2
- package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/api/CheckBootloaderRelease.d.ts +2 -1
- package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
- package/dist/api/CheckFirmwareRelease.d.ts +3 -2
- package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +1 -0
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +11 -9
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +1 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareMemoryHost.d.ts +22 -0
- package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts +11 -0
- package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -0
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +48 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +7 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -1
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/protocolV2Release.d.ts +33 -0
- package/dist/api/firmware/protocolV2Release.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +4 -3
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/index.d.ts +108 -114
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1825 -1006
- package/dist/protocols/protocol-v2/resources.d.ts +10 -28
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +20 -8
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBLEFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkBootloaderRelease.d.ts +2 -6
- package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareRelease.d.ts +2 -13
- package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts +2 -2
- package/dist/types/api/checkFirmwareTypeAvailable.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +1 -1
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +4 -12
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
- package/dist/types/settings.d.ts +35 -36
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +113 -80
- package/src/api/CheckBLEFirmwareRelease.ts +37 -5
- package/src/api/CheckBootloaderRelease.ts +35 -3
- package/src/api/CheckFirmwareRelease.ts +35 -7
- package/src/api/FirmwareUpdateV2.ts +231 -138
- package/src/api/FirmwareUpdateV3.ts +101 -56
- package/src/api/FirmwareUpdateV4.ts +936 -408
- package/src/api/UploadPortfolio.ts +18 -0
- package/src/api/device/DeviceUpdateBootloader.ts +37 -11
- package/src/api/firmware/FirmwareHostBinding.ts +26 -3
- package/src/api/firmware/FirmwareMemoryHost.ts +143 -0
- package/src/api/firmware/FirmwarePreparedResourceArchive.ts +207 -0
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +122 -73
- package/src/api/firmware/FirmwareUpdatePlan.ts +295 -122
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +49 -12
- package/src/api/firmware/protocolV2Release.ts +168 -0
- package/src/data-manager/DataManager.ts +35 -19
- package/src/index.ts +10 -0
- package/src/protocols/protocol-v2/resources.ts +157 -341
- package/src/types/api/checkAllFirmwareRelease.ts +27 -12
- package/src/types/api/checkBLEFirmwareRelease.ts +4 -13
- package/src/types/api/checkBootloaderRelease.ts +2 -6
- package/src/types/api/checkFirmwareRelease.ts +2 -13
- package/src/types/api/checkFirmwareTypeAvailable.ts +2 -2
- package/src/types/api/deviceUpdateBootloader.ts +1 -0
- package/src/types/api/export.ts +6 -1
- package/src/types/api/firmwareUpdate.ts +12 -17
- package/src/types/api/firmwareUpdatePlan.ts +2 -2
- package/src/types/settings.ts +35 -61
- package/src/utils/deviceFeaturesUtils.ts +2 -2
|
@@ -278,7 +278,14 @@ export const validateFirmwareUpdatePreparedPlan = (value: unknown): FirmwareUpda
|
|
|
278
278
|
artifactIds.add(artifact.artifactId);
|
|
279
279
|
artifactTargets.add(artifact.target);
|
|
280
280
|
assertFirmwareArtifactReference(artifact.artifact);
|
|
281
|
-
|
|
281
|
+
const materializedEntryNames =
|
|
282
|
+
artifact.materializedEntries?.map(entry => {
|
|
283
|
+
assertPreparedEntry(entry);
|
|
284
|
+
return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
|
|
285
|
+
}) ?? [];
|
|
286
|
+
if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
|
|
287
|
+
return preparedPlanError('Firmware prepared plan contains duplicate entry names');
|
|
288
|
+
}
|
|
282
289
|
}
|
|
283
290
|
if (
|
|
284
291
|
preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
|
|
@@ -295,25 +302,53 @@ export const validateFirmwareUpdatePreparedPlan = (value: unknown): FirmwareUpda
|
|
|
295
302
|
return preparedPlan;
|
|
296
303
|
};
|
|
297
304
|
|
|
305
|
+
export const getFirmwareUpdatePreparedRawArtifact = ({
|
|
306
|
+
preparedPlan: value,
|
|
307
|
+
target,
|
|
308
|
+
role,
|
|
309
|
+
}: {
|
|
310
|
+
preparedPlan: unknown;
|
|
311
|
+
target: FirmwareUpdatePreparedArtifact['target'];
|
|
312
|
+
role: FirmwareUpdatePreparedArtifact['role'];
|
|
313
|
+
}): FirmwareUpdatePreparedArtifact => {
|
|
314
|
+
const preparedPlan = validateFirmwareUpdatePreparedPlan(value);
|
|
315
|
+
const artifacts = preparedPlan.artifacts.filter(artifact => artifact.target === target);
|
|
316
|
+
if (artifacts.length !== 1 || artifacts[0].role !== role || artifacts[0].container !== 'raw') {
|
|
317
|
+
return preparedPlanError(`Firmware prepared plan ${target} artifact is invalid`);
|
|
318
|
+
}
|
|
319
|
+
return artifacts[0];
|
|
320
|
+
};
|
|
321
|
+
|
|
298
322
|
/**
|
|
299
323
|
* Identity observed on the live device while a degraded recovery plan runs, keyed by
|
|
300
|
-
* the plan
|
|
301
|
-
* reports one only after the firmware phase reboots it, so the later
|
|
302
|
-
* SAME workflow must be allowed to continue — but only for the device
|
|
303
|
-
* answered, never for a second one that appears mid-recovery.
|
|
324
|
+
* the approved prepared-plan digest. Bootloader recovery starts with no serial and
|
|
325
|
+
* the device reports one only after the firmware phase reboots it, so the later
|
|
326
|
+
* phases of the SAME workflow must be allowed to continue — but only for the device
|
|
327
|
+
* that first answered, never for a second one that appears mid-recovery.
|
|
304
328
|
*/
|
|
305
329
|
const degradedPlanIdentityPins = new Map<string, string>();
|
|
306
330
|
/** Keep the pin map from growing without bound across many workflows. */
|
|
307
331
|
const DEGRADED_PLAN_IDENTITY_PIN_LIMIT = 32;
|
|
308
332
|
|
|
309
|
-
const pinDegradedPlanIdentity = (
|
|
310
|
-
|
|
333
|
+
const pinDegradedPlanIdentity = (preparedPlanDigest: string, deviceIdentity: string) => {
|
|
334
|
+
const key = preparedPlanDigest.toLowerCase();
|
|
335
|
+
if (
|
|
336
|
+
!degradedPlanIdentityPins.has(key) &&
|
|
337
|
+
degradedPlanIdentityPins.size >= DEGRADED_PLAN_IDENTITY_PIN_LIMIT
|
|
338
|
+
) {
|
|
311
339
|
const oldest = degradedPlanIdentityPins.keys().next();
|
|
312
340
|
if (!oldest.done) {
|
|
313
341
|
degradedPlanIdentityPins.delete(oldest.value);
|
|
314
342
|
}
|
|
315
343
|
}
|
|
316
|
-
degradedPlanIdentityPins.set(
|
|
344
|
+
degradedPlanIdentityPins.set(key, deviceIdentity);
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
/** Release recovery identity state when its digest-bound host workflow ends. */
|
|
348
|
+
export const clearFirmwareUpdatePreparedPlanDeviceIdentityPin = (
|
|
349
|
+
preparedPlanDigest: string
|
|
350
|
+
): void => {
|
|
351
|
+
degradedPlanIdentityPins.delete(preparedPlanDigest.toLowerCase());
|
|
317
352
|
};
|
|
318
353
|
|
|
319
354
|
export const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({
|
|
@@ -340,10 +375,12 @@ export const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({
|
|
|
340
375
|
if (deviceModel === undefined || preparedPlan.deviceModel !== deviceModel) {
|
|
341
376
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
342
377
|
}
|
|
343
|
-
const pinnedIdentity = degradedPlanIdentityPins.get(
|
|
378
|
+
const pinnedIdentity = degradedPlanIdentityPins.get(
|
|
379
|
+
preparedPlan.preparedPlanDigest.toLowerCase()
|
|
380
|
+
);
|
|
344
381
|
if (!deviceIdentity) {
|
|
345
|
-
//
|
|
346
|
-
if (bootloaderMode !== true) {
|
|
382
|
+
// V4 设备可能尚未写入序列号;V2 则只允许 bootloader 恢复流程缺少身份。
|
|
383
|
+
if (preparedPlan.executor !== 'v4' && bootloaderMode !== true) {
|
|
347
384
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceCheckDeviceIdError);
|
|
348
385
|
}
|
|
349
386
|
return preparedPlan;
|
|
@@ -351,7 +388,7 @@ export const assertFirmwareUpdatePreparedPlanDeviceIdentity = ({
|
|
|
351
388
|
// The recovered device now reports a serial: bind this recovery to it, and hold
|
|
352
389
|
// every later phase to the same one.
|
|
353
390
|
if (!pinnedIdentity) {
|
|
354
|
-
pinDegradedPlanIdentity(preparedPlan.
|
|
391
|
+
pinDegradedPlanIdentity(preparedPlan.preparedPlanDigest, deviceIdentity);
|
|
355
392
|
return preparedPlan;
|
|
356
393
|
}
|
|
357
394
|
if (pinnedIdentity !== deviceIdentity) {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
3
|
+
import { DataManager } from '../../data-manager';
|
|
4
|
+
|
|
5
|
+
import type { EDeviceType } from '@onekeyfe/hd-shared';
|
|
6
|
+
import type { Device } from '../../device/Device';
|
|
7
|
+
import type {
|
|
8
|
+
DeviceState,
|
|
9
|
+
Features,
|
|
10
|
+
IFirmwareReleaseInfo,
|
|
11
|
+
IProtocolV2FirmwareComponentTarget,
|
|
12
|
+
} from '../../types';
|
|
13
|
+
import type {
|
|
14
|
+
FirmwareReleaseCheckResult,
|
|
15
|
+
ProtocolV2ComponentReleaseInfo,
|
|
16
|
+
ProtocolV2FirmwareReleaseStatus,
|
|
17
|
+
} from '../../types/api/checkAllFirmwareRelease';
|
|
18
|
+
import type { ProtocolV2FirmwareReleasePlan } from '../CheckAllFirmwareRelease';
|
|
19
|
+
|
|
20
|
+
export const PROTOCOL_V2_MAIN_FIRMWARE_TARGETS: readonly IProtocolV2FirmwareComponentTarget[] = [
|
|
21
|
+
'APPLICATION_P1',
|
|
22
|
+
'APPLICATION_P2',
|
|
23
|
+
'SE01',
|
|
24
|
+
'SE02',
|
|
25
|
+
'SE03',
|
|
26
|
+
'SE04',
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export const PROTOCOL_V2_BLE_TARGETS: readonly IProtocolV2FirmwareComponentTarget[] = [
|
|
30
|
+
'COPROCESSOR',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export const PROTOCOL_V2_BOOTLOADER_TARGETS: readonly IProtocolV2FirmwareComponentTarget[] = [
|
|
34
|
+
'BOOTLOADER',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export type ProtocolV2FirmwareReleaseContext = {
|
|
38
|
+
state: Omit<DeviceState, 'identity'> & {
|
|
39
|
+
identity: Omit<DeviceState['identity'], 'deviceType'> & {
|
|
40
|
+
deviceType: EDeviceType.Pro2 | EDeviceType.Neo;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
features: Features;
|
|
44
|
+
firmwareType: EFirmwareType;
|
|
45
|
+
release: IFirmwareReleaseInfo | undefined;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export async function loadProtocolV2FirmwareReleaseContext({
|
|
49
|
+
device,
|
|
50
|
+
firmwareType: firmwareTypeParam,
|
|
51
|
+
checkFirmwareHash = false,
|
|
52
|
+
methodName,
|
|
53
|
+
}: {
|
|
54
|
+
device: Device;
|
|
55
|
+
firmwareType?: EFirmwareType;
|
|
56
|
+
checkFirmwareHash?: boolean;
|
|
57
|
+
methodName: string;
|
|
58
|
+
}): Promise<ProtocolV2FirmwareReleaseContext> {
|
|
59
|
+
const state = await device.getDeviceState({
|
|
60
|
+
refreshSections: checkFirmwareHash
|
|
61
|
+
? ['identity', 'versions', 'verification']
|
|
62
|
+
: ['identity', 'versions'],
|
|
63
|
+
});
|
|
64
|
+
if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
|
|
65
|
+
throw ERRORS.TypedError(
|
|
66
|
+
HardwareErrorCode.DeviceNotSupportMethod,
|
|
67
|
+
`${methodName} requires a Pro2 or Neo device for Protocol V2`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const { features } = device;
|
|
72
|
+
if (!features) {
|
|
73
|
+
throw ERRORS.TypedError(
|
|
74
|
+
HardwareErrorCode.RuntimeError,
|
|
75
|
+
`${methodName} requires initialized device features`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const firmwareType = firmwareTypeParam ?? state.identity.firmwareType ?? EFirmwareType.Universal;
|
|
80
|
+
return {
|
|
81
|
+
state: state as ProtocolV2FirmwareReleaseContext['state'],
|
|
82
|
+
features,
|
|
83
|
+
firmwareType,
|
|
84
|
+
release: DataManager.getFirmwareLatestRelease(features, firmwareType),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function summarizeProtocolV2FirmwareRelease(
|
|
89
|
+
plan: ProtocolV2FirmwareReleasePlan,
|
|
90
|
+
componentTargets: readonly IProtocolV2FirmwareComponentTarget[]
|
|
91
|
+
): ProtocolV2FirmwareReleasePlan {
|
|
92
|
+
const targetSet = new Set<IProtocolV2FirmwareComponentTarget>(componentTargets);
|
|
93
|
+
const components = plan.components.filter(component => targetSet.has(component.componentTarget));
|
|
94
|
+
const targetsToUpdate = Array.from(
|
|
95
|
+
new Set(
|
|
96
|
+
components.flatMap(component =>
|
|
97
|
+
component.status === 'outdated' && component.updateTarget ? [component.updateTarget] : []
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
const hasUpgrade = targetsToUpdate.length > 0;
|
|
102
|
+
const required = !!plan.release?.required && hasUpgrade;
|
|
103
|
+
let status: ProtocolV2FirmwareReleaseStatus = 'valid';
|
|
104
|
+
if (!plan.release || components.length === 0) {
|
|
105
|
+
status = 'unavailable';
|
|
106
|
+
} else if (required) {
|
|
107
|
+
status = 'required';
|
|
108
|
+
} else if (hasUpgrade) {
|
|
109
|
+
status = 'outdated';
|
|
110
|
+
} else if (components.some(component => component.status === 'unknown')) {
|
|
111
|
+
status = 'unknown';
|
|
112
|
+
} else if (components.every(component => component.status === 'unsupported')) {
|
|
113
|
+
status = 'unavailable';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
...plan,
|
|
118
|
+
status,
|
|
119
|
+
hasUpgrade,
|
|
120
|
+
required,
|
|
121
|
+
components,
|
|
122
|
+
targetsToUpdate,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function toProtocolV2FirmwareReleaseInfo({
|
|
127
|
+
plan,
|
|
128
|
+
state,
|
|
129
|
+
release,
|
|
130
|
+
}: {
|
|
131
|
+
plan: ProtocolV2FirmwareReleasePlan;
|
|
132
|
+
state: DeviceState;
|
|
133
|
+
release: FirmwareReleaseCheckResult['release'];
|
|
134
|
+
}): FirmwareReleaseCheckResult {
|
|
135
|
+
return {
|
|
136
|
+
shouldUpdate: plan.hasUpgrade,
|
|
137
|
+
status: plan.status === 'unavailable' ? 'unknown' : plan.status,
|
|
138
|
+
// Protocol V2 components share package-set release notes. The optional
|
|
139
|
+
// bootloaderChangelog field belongs to the legacy Protocol V1 release model.
|
|
140
|
+
changelog: plan.release ? [plan.release.changelog] : [],
|
|
141
|
+
release,
|
|
142
|
+
bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function getProtocolV2ComponentReleaseInfo(
|
|
147
|
+
plan: ProtocolV2FirmwareReleasePlan,
|
|
148
|
+
componentTarget: IProtocolV2FirmwareComponentTarget
|
|
149
|
+
): ProtocolV2ComponentReleaseInfo | undefined {
|
|
150
|
+
const componentRelease = plan.components.find(
|
|
151
|
+
component => component.componentTarget === componentTarget
|
|
152
|
+
);
|
|
153
|
+
if (!componentRelease || !plan.release) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
const component = plan.release.components?.[componentRelease.configKey];
|
|
157
|
+
if (!component) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
...component,
|
|
162
|
+
protocol: 'V2',
|
|
163
|
+
configKey: componentRelease.configKey,
|
|
164
|
+
componentTarget,
|
|
165
|
+
required: plan.release.required,
|
|
166
|
+
changelog: plan.release.changelog,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
@@ -94,12 +94,10 @@ export default class DataManager {
|
|
|
94
94
|
ble: [],
|
|
95
95
|
},
|
|
96
96
|
[EDeviceType.Pro2]: {
|
|
97
|
-
firmware: [],
|
|
98
|
-
ble: [],
|
|
97
|
+
'firmware-v1': [],
|
|
99
98
|
},
|
|
100
99
|
[EDeviceType.Neo]: {
|
|
101
|
-
firmware: [],
|
|
102
|
-
ble: [],
|
|
100
|
+
'firmware-v1': [],
|
|
103
101
|
},
|
|
104
102
|
[EDeviceType.ClassicPure]: {
|
|
105
103
|
firmware: [],
|
|
@@ -121,6 +119,8 @@ export default class DataManager {
|
|
|
121
119
|
|
|
122
120
|
static protocolV2ResourcesConfigError: Error | undefined;
|
|
123
121
|
|
|
122
|
+
private static protocolV2NeoResourcesConfigError: Error | undefined;
|
|
123
|
+
|
|
124
124
|
static getFirmwareStatus = (
|
|
125
125
|
features: Features,
|
|
126
126
|
firmwareType: EFirmwareType
|
|
@@ -410,6 +410,7 @@ export default class DataManager {
|
|
|
410
410
|
static async load(settings: ConnectSettings): Promise<boolean> {
|
|
411
411
|
this.settings = settings;
|
|
412
412
|
this.protocolV2ResourcesConfigError = undefined;
|
|
413
|
+
this.protocolV2NeoResourcesConfigError = undefined;
|
|
413
414
|
const manifestMode =
|
|
414
415
|
settings.firmwareManifestMode ?? (settings.fetchConfig ? 'sdk-managed' : undefined);
|
|
415
416
|
if (settings.preloadedConfig) {
|
|
@@ -476,15 +477,21 @@ export default class DataManager {
|
|
|
476
477
|
pro2Resources = parseProtocolV2Resources(
|
|
477
478
|
(data.pro2 as { resources?: unknown } | undefined)?.resources
|
|
478
479
|
);
|
|
479
|
-
neoResources = parseProtocolV2Resources(
|
|
480
|
-
(data.neo as { resources?: unknown } | undefined)?.resources
|
|
481
|
-
);
|
|
482
480
|
} catch (error) {
|
|
483
481
|
// Firmware resource metadata is not required for base communication. If the
|
|
484
482
|
// remote config is temporarily incomplete, disable this resource update only.
|
|
485
483
|
this.protocolV2ResourcesConfigError =
|
|
486
484
|
error instanceof Error ? error : new Error(String(error));
|
|
487
|
-
Log.warn('[DataConfig] Ignoring invalid
|
|
485
|
+
Log.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
neoResources = parseProtocolV2Resources(
|
|
489
|
+
(data.neo as { resources?: unknown } | undefined)?.resources
|
|
490
|
+
);
|
|
491
|
+
} catch (error) {
|
|
492
|
+
this.protocolV2NeoResourcesConfigError =
|
|
493
|
+
error instanceof Error ? error : new Error(String(error));
|
|
494
|
+
Log.warn('[DataConfig] Ignoring invalid Neo resources config:', error);
|
|
488
495
|
}
|
|
489
496
|
const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
|
|
490
497
|
const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
|
|
@@ -537,7 +544,12 @@ export default class DataManager {
|
|
|
537
544
|
/** Force a fresh remote config before an update is allowed to mutate the device. */
|
|
538
545
|
static async forceReloadData({
|
|
539
546
|
requireResources = false,
|
|
540
|
-
|
|
547
|
+
resourceDeviceType = EDeviceType.Pro2,
|
|
548
|
+
}: {
|
|
549
|
+
requireResources?: boolean;
|
|
550
|
+
resourceDeviceType?: EDeviceType.Pro2 | EDeviceType.Neo;
|
|
551
|
+
} = {}): Promise<void> {
|
|
552
|
+
const resourceDeviceName = resourceDeviceType === EDeviceType.Pro2 ? 'Pro2' : 'Neo';
|
|
541
553
|
if (!this.settings) {
|
|
542
554
|
throw new Error('Remote config settings are not initialized');
|
|
543
555
|
}
|
|
@@ -545,10 +557,14 @@ export default class DataManager {
|
|
|
545
557
|
this.lastCheckTimestamp > 0 &&
|
|
546
558
|
getTimeStamp() - this.lastCheckTimestamp <= FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS;
|
|
547
559
|
if (hasFreshConfig) {
|
|
548
|
-
|
|
560
|
+
const resourcesConfigError =
|
|
561
|
+
resourceDeviceType === EDeviceType.Pro2
|
|
562
|
+
? this.protocolV2ResourcesConfigError
|
|
563
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
564
|
+
if (requireResources && resourcesConfigError) {
|
|
549
565
|
throw ERRORS.TypedError(
|
|
550
566
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
551
|
-
`Invalid
|
|
567
|
+
`Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`
|
|
552
568
|
);
|
|
553
569
|
}
|
|
554
570
|
return;
|
|
@@ -560,23 +576,23 @@ export default class DataManager {
|
|
|
560
576
|
'Unable to refresh the latest remote config'
|
|
561
577
|
);
|
|
562
578
|
}
|
|
563
|
-
|
|
579
|
+
const resourcesConfigError =
|
|
580
|
+
resourceDeviceType === EDeviceType.Pro2
|
|
581
|
+
? this.protocolV2ResourcesConfigError
|
|
582
|
+
: this.protocolV2NeoResourcesConfigError;
|
|
583
|
+
if (requireResources && resourcesConfigError) {
|
|
564
584
|
throw ERRORS.TypedError(
|
|
565
585
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
566
|
-
`Invalid
|
|
586
|
+
`Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`
|
|
567
587
|
);
|
|
568
588
|
}
|
|
569
589
|
this.lastCheckTimestamp = getTimeStamp();
|
|
570
590
|
}
|
|
571
591
|
|
|
572
|
-
static
|
|
573
|
-
return this.deviceMap[deviceType]?.resources?.stable;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
static getProtocolV2BootResources(
|
|
592
|
+
static getProtocolV2ResourceSource(
|
|
577
593
|
deviceType: EDeviceType.Pro2 | EDeviceType.Neo = EDeviceType.Pro2
|
|
578
594
|
) {
|
|
579
|
-
return this.deviceMap[deviceType]?.resources?.
|
|
595
|
+
return this.deviceMap[deviceType]?.resources?.source;
|
|
580
596
|
}
|
|
581
597
|
|
|
582
598
|
static getProtobufMessages(schema: ProtobufMessageSchema = 'v1CurrentSchema'): JSON {
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,16 @@ export { executeCallback, cleanupCallback };
|
|
|
21
21
|
export { preloadSessionCache } from './device/Device';
|
|
22
22
|
export { projectFeatures as projectDeviceStateFeatures } from './device/DeviceStateProjector';
|
|
23
23
|
export { getMethodSupportedProtocols } from './api/utils';
|
|
24
|
+
export {
|
|
25
|
+
parseProtocolV2ResourceManifest,
|
|
26
|
+
selectProtocolV2ResourceManifestFiles,
|
|
27
|
+
} from './protocols/protocol-v2/resources';
|
|
28
|
+
export { prepareFirmwareUpdateV4MemoryHost } from './api/firmware/FirmwareMemoryHost';
|
|
29
|
+
export type {
|
|
30
|
+
FirmwareMemoryArtifact,
|
|
31
|
+
FirmwareMemoryArtifactEntry,
|
|
32
|
+
FirmwareUpdateV4MemoryHost,
|
|
33
|
+
} from './api/firmware/FirmwareMemoryHost';
|
|
24
34
|
export {
|
|
25
35
|
getFirmwareUpdateHostBindingGeneration,
|
|
26
36
|
registerFirmwareUpdateHostBinding,
|