@onekeyfe/hd-core 1.2.0-alpha.70 → 1.2.0-alpha.71
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 +28 -0
- package/__tests__/protocol-v2-firmware-targets.test.ts +33 -1
- package/__tests__/protocol-v2-resources.test.ts +9 -6
- package/__tests__/protocol-v2.test.ts +80 -12
- package/__tests__/protocolV2FileWrite.test.ts +48 -7
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +2 -0
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +97 -25
- package/dist/protocols/protocol-v2/resources.d.ts +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
- package/dist/types/settings.d.ts +1 -1
- package/dist/types/settings.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/CheckAllFirmwareRelease.ts +19 -4
- package/src/api/FirmwareUpdateV4.ts +49 -4
- package/src/api/helpers/protocolV2FileWrite.ts +54 -4
- package/src/protocols/protocol-v2/resources.ts +5 -1
- package/src/types/settings.ts +2 -1
|
@@ -163,6 +163,34 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
|
|
|
163
163
|
});
|
|
164
164
|
});
|
|
165
165
|
|
|
166
|
+
test('marks SE03 and SE04 as unsupported in a Neo firmware plan', () => {
|
|
167
|
+
const neoRelease: IFirmwareReleaseInfo = {
|
|
168
|
+
...release,
|
|
169
|
+
installOrder: ['se01', 'se02', 'se03', 'se04'],
|
|
170
|
+
components: {
|
|
171
|
+
se01: { target: 'SE01', url: 'https://example.com/se01.bin', version: [2, 0, 0] },
|
|
172
|
+
se02: { target: 'SE02', url: 'https://example.com/se02.bin', version: [3, 0, 0] },
|
|
173
|
+
se03: { target: 'SE03', url: 'https://example.com/se03.bin', version: [2, 0, 0] },
|
|
174
|
+
se04: { target: 'SE04', url: 'https://example.com/se04.bin', version: [2, 0, 0] },
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const result = buildProtocolV2FirmwareRelease({
|
|
179
|
+
currentVersions,
|
|
180
|
+
firmwareType: EFirmwareType.Universal,
|
|
181
|
+
release: neoRelease,
|
|
182
|
+
deviceType: 'neo',
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(result.targetsToUpdate).toEqual(['se01', 'se02']);
|
|
186
|
+
expect(result.components).toEqual(
|
|
187
|
+
expect.arrayContaining([
|
|
188
|
+
expect.objectContaining({ configKey: 'se03', status: 'unsupported', updateTarget: null }),
|
|
189
|
+
expect.objectContaining({ configKey: 'se04', status: 'unsupported', updateTarget: null }),
|
|
190
|
+
])
|
|
191
|
+
);
|
|
192
|
+
});
|
|
193
|
+
|
|
166
194
|
test('returns an unavailable plan when no Pro2 release is configured', () => {
|
|
167
195
|
expect(
|
|
168
196
|
buildProtocolV2FirmwareRelease({
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { EDeviceType } from '@onekeyfe/hd-shared';
|
|
2
|
+
|
|
1
3
|
import { ProtocolV2FirmwareTargetType } from '../src/protocols/protocol-v2/firmware';
|
|
2
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
assertProtocolV2FirmwareTargetsSupported,
|
|
6
|
+
isProtocolV2FirmwareFingerprintValid,
|
|
7
|
+
} from '../src/api/FirmwareUpdateV4';
|
|
3
8
|
|
|
4
9
|
jest.mock('../src/data/config', () => ({
|
|
5
10
|
DEFAULT_DOMAIN: 'https://example.com/',
|
|
@@ -34,4 +39,31 @@ describe('Protocol V2 firmware target contract', () => {
|
|
|
34
39
|
).toBe(true);
|
|
35
40
|
expect(isProtocolV2FirmwareFingerprintValid(binary, '00'.repeat(32))).toBe(false);
|
|
36
41
|
});
|
|
42
|
+
|
|
43
|
+
test('allows only SE01 and SE02 firmware targets on Neo', () => {
|
|
44
|
+
expect(() =>
|
|
45
|
+
assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
|
|
46
|
+
platform: 'web',
|
|
47
|
+
targetsToUpdate: ['se01', 'se02'],
|
|
48
|
+
})
|
|
49
|
+
).not.toThrow();
|
|
50
|
+
|
|
51
|
+
expect(() =>
|
|
52
|
+
assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
|
|
53
|
+
platform: 'web',
|
|
54
|
+
targetsToUpdate: ['se03'],
|
|
55
|
+
se04Binary: new ArrayBuffer(1),
|
|
56
|
+
})
|
|
57
|
+
).toThrow('Neo only supports SE01 and SE02; unsupported firmware targets: se03, se04');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('keeps all four SE firmware targets available on Pro2', () => {
|
|
61
|
+
expect(() =>
|
|
62
|
+
assertProtocolV2FirmwareTargetsSupported(EDeviceType.Pro2, {
|
|
63
|
+
platform: 'web',
|
|
64
|
+
targetsToUpdate: ['se03'],
|
|
65
|
+
se04Binary: new ArrayBuffer(1),
|
|
66
|
+
})
|
|
67
|
+
).not.toThrow();
|
|
68
|
+
});
|
|
37
69
|
});
|
|
@@ -95,7 +95,7 @@ describe('Pro2 resource configuration', () => {
|
|
|
95
95
|
DataManager.lastCheckTimestamp = 0;
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
test('accepts exactly
|
|
98
|
+
test('accepts exactly seven resources and normalizes their deterministic order', () => {
|
|
99
99
|
const parsed = parseProtocolV2Resources({
|
|
100
100
|
stable: [...resources].reverse(),
|
|
101
101
|
boot: bootResources,
|
|
@@ -106,15 +106,18 @@ describe('Pro2 resource configuration', () => {
|
|
|
106
106
|
expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.translations).toBe(
|
|
107
107
|
'vol0:/bundles/translations/translations.okpkg'
|
|
108
108
|
);
|
|
109
|
+
expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.firmware_logo).toBe(
|
|
110
|
+
'vol0:/bundles/firmware_logo.okpkg'
|
|
111
|
+
);
|
|
109
112
|
});
|
|
110
113
|
|
|
111
114
|
test('rejects incomplete, duplicate, or malformed stable sets', () => {
|
|
112
115
|
expect(() => parseProtocolV2Resources({ stable: resources.slice(1) })).toThrow(
|
|
113
|
-
'
|
|
116
|
+
'7 unique resource types'
|
|
114
117
|
);
|
|
115
118
|
expect(() =>
|
|
116
|
-
parseProtocolV2Resources({ stable: [...resources.slice(0,
|
|
117
|
-
).toThrow('
|
|
119
|
+
parseProtocolV2Resources({ stable: [...resources.slice(0, 6), resources[0]] })
|
|
120
|
+
).toThrow('7 unique resource types');
|
|
118
121
|
expect(() =>
|
|
119
122
|
parseProtocolV2Resources({
|
|
120
123
|
stable: resources.map((resource, index) =>
|
|
@@ -224,7 +227,7 @@ describe('Pro2 resource configuration', () => {
|
|
|
224
227
|
);
|
|
225
228
|
expect(typedCall.mock.calls.some(call => call[0] === 'ResourceInventoryGet')).toBe(false);
|
|
226
229
|
expect(typedCall.mock.calls.filter(call => call[0] === 'FilesystemPathInfoQuery')).toHaveLength(
|
|
227
|
-
|
|
230
|
+
7
|
|
228
231
|
);
|
|
229
232
|
expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
|
|
230
233
|
});
|
|
@@ -255,7 +258,7 @@ describe('Pro2 resource configuration', () => {
|
|
|
255
258
|
});
|
|
256
259
|
expect(
|
|
257
260
|
buildProtocolV2ResourceUpdatePlan({ resources, mode: 'bootloader-recovery' }).resources
|
|
258
|
-
).toHaveLength(
|
|
261
|
+
).toHaveLength(7);
|
|
259
262
|
});
|
|
260
263
|
|
|
261
264
|
test('uses a filesystem inventory for incremental recovery mode updates', () => {
|
|
@@ -35,7 +35,10 @@ import ProtocolInfoRequest from '../src/api/protocol-v2/ProtocolInfoRequest';
|
|
|
35
35
|
import EVMSignTypedData from '../src/api/evm/EVMSignTypedData';
|
|
36
36
|
import EVMSignMessageEIP712 from '../src/api/evm/EVMSignMessageEIP712';
|
|
37
37
|
import FirmwareUpdateV3 from '../src/api/FirmwareUpdateV3';
|
|
38
|
-
import FirmwareUpdateV4, {
|
|
38
|
+
import FirmwareUpdateV4, {
|
|
39
|
+
assertProtocolV2FirmwareTargetsSupported,
|
|
40
|
+
assertProtocolV2ReconnectIdentity,
|
|
41
|
+
} from '../src/api/FirmwareUpdateV4';
|
|
39
42
|
import GetPassphraseState from '../src/api/GetPassphraseState';
|
|
40
43
|
import GetOnekeyFeatures from '../src/api/GetOnekeyFeatures';
|
|
41
44
|
import { batchGetPublickeys } from '../src/api/helpers/batchGetPublickeys';
|
|
@@ -255,7 +258,10 @@ describe('UploadPortfolio', () => {
|
|
|
255
258
|
'FilesystemFileWrite',
|
|
256
259
|
'FilesystemFile',
|
|
257
260
|
expect.any(Object),
|
|
258
|
-
{
|
|
261
|
+
expect.objectContaining({
|
|
262
|
+
timeoutMs: undefined,
|
|
263
|
+
onWriteCompleted: expect.any(Function),
|
|
264
|
+
})
|
|
259
265
|
);
|
|
260
266
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
|
|
261
267
|
});
|
|
@@ -298,7 +304,10 @@ describe('UploadPortfolio', () => {
|
|
|
298
304
|
append: false,
|
|
299
305
|
ui_percentage: 100,
|
|
300
306
|
},
|
|
301
|
-
{
|
|
307
|
+
expect.objectContaining({
|
|
308
|
+
timeoutMs: undefined,
|
|
309
|
+
onWriteCompleted: expect.any(Function),
|
|
310
|
+
})
|
|
302
311
|
);
|
|
303
312
|
expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
|
|
304
313
|
expect(method.postMessage).not.toHaveBeenCalled();
|
|
@@ -3989,6 +3998,10 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
3989
3998
|
});
|
|
3990
3999
|
|
|
3991
4000
|
const order: string[] = [];
|
|
4001
|
+
(method as any).prepareProtocolV2BootResources = jest.fn().mockImplementation(() => {
|
|
4002
|
+
order.push('prepare-startup-resources');
|
|
4003
|
+
return Promise.resolve([]);
|
|
4004
|
+
});
|
|
3992
4005
|
(method as any).enterProtocolV2BootloaderMode = jest.fn().mockImplementation(() => {
|
|
3993
4006
|
order.push('enter-bootloader');
|
|
3994
4007
|
return Promise.resolve(true);
|
|
@@ -4017,7 +4030,12 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4017
4030
|
|
|
4018
4031
|
await method.run();
|
|
4019
4032
|
|
|
4020
|
-
expect(order).toEqual([
|
|
4033
|
+
expect(order).toEqual([
|
|
4034
|
+
'prepare-startup-resources',
|
|
4035
|
+
'enter-bootloader',
|
|
4036
|
+
'prepare-resources',
|
|
4037
|
+
'execute-update',
|
|
4038
|
+
]);
|
|
4021
4039
|
});
|
|
4022
4040
|
|
|
4023
4041
|
test('reboots Protocol V2 normal-mode device to bootloader before transfer', async () => {
|
|
@@ -4261,6 +4279,41 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
4261
4279
|
expect(typedCall.mock.calls.map(call => call[0])).toEqual(['DeviceInfoGet']);
|
|
4262
4280
|
});
|
|
4263
4281
|
|
|
4282
|
+
test('polls again when Protocol V2 bootloader serial is temporarily unavailable', async () => {
|
|
4283
|
+
const method = new FirmwareUpdateV4({
|
|
4284
|
+
id: 1,
|
|
4285
|
+
payload: {
|
|
4286
|
+
method: 'firmwareUpdateV4',
|
|
4287
|
+
},
|
|
4288
|
+
});
|
|
4289
|
+
const typedCall = jest
|
|
4290
|
+
.fn()
|
|
4291
|
+
.mockResolvedValueOnce({
|
|
4292
|
+
type: 'DeviceInfo',
|
|
4293
|
+
message: { protocol_version: 1, hw: {} },
|
|
4294
|
+
})
|
|
4295
|
+
.mockResolvedValueOnce({
|
|
4296
|
+
type: 'DeviceInfo',
|
|
4297
|
+
message: protocolV2BootloaderDeviceInfo,
|
|
4298
|
+
});
|
|
4299
|
+
const reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
|
|
4300
|
+
(method as any).device = stubDevice({
|
|
4301
|
+
originalDescriptor: { id: 'ble-id', protocolType: 'V2' },
|
|
4302
|
+
getCommands: () => ({ typedCall }),
|
|
4303
|
+
probeProtocolV2RuntimeState: jest.fn().mockResolvedValue({
|
|
4304
|
+
mode: 'bootloader',
|
|
4305
|
+
bootloaderMode: true,
|
|
4306
|
+
}),
|
|
4307
|
+
});
|
|
4308
|
+
(method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
|
|
4309
|
+
(method as any).protocolV2ExpectedSerialNumber = 'PR9999999999';
|
|
4310
|
+
|
|
4311
|
+
await (method as any).waitForProtocolV2BootloaderMode(60 * 1000, 0);
|
|
4312
|
+
|
|
4313
|
+
expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(2);
|
|
4314
|
+
expect(typedCall).toHaveBeenCalledTimes(2);
|
|
4315
|
+
});
|
|
4316
|
+
|
|
4264
4317
|
test('does not run generic initialize during Protocol V2 USB firmware reconnect', async () => {
|
|
4265
4318
|
const method = new FirmwareUpdateV4({
|
|
4266
4319
|
id: 1,
|
|
@@ -6374,8 +6427,14 @@ describe('Protocol V2 firmware update targets', () => {
|
|
|
6374
6427
|
expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1800, 1]);
|
|
6375
6428
|
expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0, 100]);
|
|
6376
6429
|
expect(typedCall.mock.calls.map(call => call[3])).toEqual([
|
|
6377
|
-
{
|
|
6378
|
-
|
|
6430
|
+
expect.objectContaining({
|
|
6431
|
+
writeWithResponse: false,
|
|
6432
|
+
onWriteCompleted: expect.any(Function),
|
|
6433
|
+
}),
|
|
6434
|
+
expect.objectContaining({
|
|
6435
|
+
writeWithResponse: false,
|
|
6436
|
+
onWriteCompleted: expect.any(Function),
|
|
6437
|
+
}),
|
|
6379
6438
|
]);
|
|
6380
6439
|
});
|
|
6381
6440
|
|
|
@@ -6941,7 +7000,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
|
|
|
6941
7000
|
resourcesSpy.mockRestore();
|
|
6942
7001
|
});
|
|
6943
7002
|
|
|
6944
|
-
test('does not resolve boot resources
|
|
7003
|
+
test('does not resolve boot resources when no resource target is selected', async () => {
|
|
6945
7004
|
const method = new FirmwareUpdateV4({
|
|
6946
7005
|
id: 1,
|
|
6947
7006
|
payload: { method: 'firmwareUpdateV4', platform: 'web' },
|
|
@@ -6956,7 +7015,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
|
|
|
6956
7015
|
expect(downloadSpy).not.toHaveBeenCalled();
|
|
6957
7016
|
});
|
|
6958
7017
|
|
|
6959
|
-
test('
|
|
7018
|
+
test('includes startup resources in the complete resource target', async () => {
|
|
6960
7019
|
const bytes = new Uint8Array([1, 2, 3, 4]);
|
|
6961
7020
|
const binary = bytes.buffer as ArrayBuffer;
|
|
6962
7021
|
const fileHash = Array.from(sha256(bytes), byte => byte.toString(16).padStart(2, '0')).join('');
|
|
@@ -6978,7 +7037,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
|
|
|
6978
7037
|
payload: {
|
|
6979
7038
|
method: 'firmwareUpdateV4',
|
|
6980
7039
|
platform: 'web',
|
|
6981
|
-
targetsToUpdate: ['
|
|
7040
|
+
targetsToUpdate: ['resource'],
|
|
6982
7041
|
},
|
|
6983
7042
|
});
|
|
6984
7043
|
method.init();
|
|
@@ -7921,7 +7980,10 @@ describe('Protocol V2 file write method', () => {
|
|
|
7921
7980
|
append: false,
|
|
7922
7981
|
ui_percentage: 100,
|
|
7923
7982
|
},
|
|
7924
|
-
{
|
|
7983
|
+
expect.objectContaining({
|
|
7984
|
+
timeoutMs: undefined,
|
|
7985
|
+
onWriteCompleted: expect.any(Function),
|
|
7986
|
+
})
|
|
7925
7987
|
);
|
|
7926
7988
|
expect(method.postMessage).toHaveBeenCalledWith({
|
|
7927
7989
|
event: 'UI_EVENT',
|
|
@@ -7970,7 +8032,10 @@ describe('Protocol V2 file write method', () => {
|
|
|
7970
8032
|
append: false,
|
|
7971
8033
|
ui_percentage: 0,
|
|
7972
8034
|
},
|
|
7973
|
-
{
|
|
8035
|
+
expect.objectContaining({
|
|
8036
|
+
timeoutMs: undefined,
|
|
8037
|
+
onWriteCompleted: expect.any(Function),
|
|
8038
|
+
})
|
|
7974
8039
|
);
|
|
7975
8040
|
expect(typedCall).toHaveBeenNthCalledWith(
|
|
7976
8041
|
2,
|
|
@@ -7987,7 +8052,10 @@ describe('Protocol V2 file write method', () => {
|
|
|
7987
8052
|
append: false,
|
|
7988
8053
|
ui_percentage: 100,
|
|
7989
8054
|
},
|
|
7990
|
-
{
|
|
8055
|
+
expect.objectContaining({
|
|
8056
|
+
timeoutMs: undefined,
|
|
8057
|
+
onWriteCompleted: expect.any(Function),
|
|
8058
|
+
})
|
|
7991
8059
|
);
|
|
7992
8060
|
expect(result).toMatchObject({
|
|
7993
8061
|
path: 'vol1:test.bin',
|
|
@@ -131,10 +131,43 @@ describe('writeProtocolV2File', () => {
|
|
|
131
131
|
'FilesystemFileWrite',
|
|
132
132
|
'FilesystemFile',
|
|
133
133
|
expect.objectContaining({ ui_percentage: 42 }),
|
|
134
|
-
{
|
|
134
|
+
expect.objectContaining({
|
|
135
|
+
writeWithResponse: true,
|
|
136
|
+
onWriteCompleted: expect.any(Function),
|
|
137
|
+
})
|
|
135
138
|
);
|
|
136
139
|
});
|
|
137
140
|
|
|
141
|
+
test('记录主机整帧写入与设备响应等待的分段耗时', async () => {
|
|
142
|
+
const log = getLogger(LoggerNames.Core);
|
|
143
|
+
const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
|
|
144
|
+
const typedCall = jest.fn().mockImplementation((_type, _resType, _request, options) => {
|
|
145
|
+
options.onWriteCompleted({ elapsedMs: 25, frameBytes: 128 });
|
|
146
|
+
return Promise.resolve({ message: { processed_byte: 3 } });
|
|
147
|
+
});
|
|
148
|
+
const dateNowSpy = jest
|
|
149
|
+
.spyOn(Date, 'now')
|
|
150
|
+
.mockReturnValueOnce(1_000)
|
|
151
|
+
.mockReturnValueOnce(1_010)
|
|
152
|
+
.mockReturnValueOnce(1_040)
|
|
153
|
+
.mockReturnValueOnce(1_050);
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
await writeProtocolV2File({
|
|
157
|
+
commands: { typedCall } as any,
|
|
158
|
+
path: 'vol0:/firmware.bin',
|
|
159
|
+
data: new Uint8Array([1, 2, 3]),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(logSpy).toHaveBeenLastCalledWith(
|
|
163
|
+
'[FileWrite] metrics transport=unknown status=completed path=vol0:/firmware.bin bytes=3/3 elapsed=0.05s speed=0.06 KiB/s hostWriteTotal=0.03s responseWaitTotal=0.03s measuredAttempts=1'
|
|
164
|
+
);
|
|
165
|
+
} finally {
|
|
166
|
+
dateNowSpy.mockRestore();
|
|
167
|
+
logSpy.mockRestore();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
138
171
|
test('按确认分片的时间窗口记录实时传输速率', async () => {
|
|
139
172
|
const data = new Uint8Array(4097);
|
|
140
173
|
const typedCall = jest.fn().mockResolvedValue({ message: {} });
|
|
@@ -175,7 +208,7 @@ describe('writeProtocolV2File', () => {
|
|
|
175
208
|
});
|
|
176
209
|
|
|
177
210
|
test('通过 Core Log 每十秒输出一次 BLE 传输关键指标', async () => {
|
|
178
|
-
const log = getLogger(LoggerNames.
|
|
211
|
+
const log = getLogger(LoggerNames.Core);
|
|
179
212
|
const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
|
|
180
213
|
const getSettingsSpy = jest
|
|
181
214
|
.spyOn(DataManager, 'getSettings')
|
|
@@ -197,14 +230,18 @@ describe('writeProtocolV2File', () => {
|
|
|
197
230
|
data,
|
|
198
231
|
});
|
|
199
232
|
|
|
200
|
-
expect(logSpy).toHaveBeenCalledTimes(
|
|
233
|
+
expect(logSpy).toHaveBeenCalledTimes(3);
|
|
201
234
|
expect(logSpy).toHaveBeenNthCalledWith(
|
|
202
235
|
1,
|
|
203
|
-
'[FileWrite]
|
|
236
|
+
'[FileWrite] started transport=BLE path=vol1:/wallpapers/test.bin bytes=5400 offset=0 chunk=1800'
|
|
204
237
|
);
|
|
205
238
|
expect(logSpy).toHaveBeenNthCalledWith(
|
|
206
239
|
2,
|
|
207
|
-
'[FileWrite] metrics transport=BLE status=
|
|
240
|
+
'[FileWrite] metrics transport=BLE status=progress path=vol1:/wallpapers/test.bin bytes=3600/5400 elapsed=10.00s speed=0.35 KiB/s'
|
|
241
|
+
);
|
|
242
|
+
expect(logSpy).toHaveBeenNthCalledWith(
|
|
243
|
+
3,
|
|
244
|
+
'[FileWrite] metrics transport=BLE status=completed path=vol1:/wallpapers/test.bin bytes=5400/5400 elapsed=14.00s speed=0.44 KiB/s'
|
|
208
245
|
);
|
|
209
246
|
} finally {
|
|
210
247
|
dateNowSpy.mockRestore();
|
|
@@ -215,7 +252,7 @@ describe('writeProtocolV2File', () => {
|
|
|
215
252
|
});
|
|
216
253
|
|
|
217
254
|
test('写入失败时通过 Core Log 输出已传输字节和平均速率', async () => {
|
|
218
|
-
const log = getLogger(LoggerNames.
|
|
255
|
+
const log = getLogger(LoggerNames.Core);
|
|
219
256
|
const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
|
|
220
257
|
const typedCall = jest.fn().mockRejectedValue(new Error('write failed'));
|
|
221
258
|
const dateNowSpy = jest
|
|
@@ -234,7 +271,11 @@ describe('writeProtocolV2File', () => {
|
|
|
234
271
|
|
|
235
272
|
expect(logSpy).toHaveBeenNthCalledWith(
|
|
236
273
|
1,
|
|
237
|
-
'[FileWrite]
|
|
274
|
+
'[FileWrite] started transport=unknown path=vol1:/wallpapers/test.bin bytes=4000 offset=0 chunk=4000'
|
|
275
|
+
);
|
|
276
|
+
expect(logSpy).toHaveBeenNthCalledWith(
|
|
277
|
+
2,
|
|
278
|
+
'[FileWrite] metrics transport=unknown status=failed path=vol1:/wallpapers/test.bin bytes=0/4000 elapsed=1.00s speed=0.00 KiB/s'
|
|
238
279
|
);
|
|
239
280
|
} finally {
|
|
240
281
|
dateNowSpy.mockRestore();
|
|
@@ -13,13 +13,14 @@ type ProtocolV2FirmwareReleasePlan = {
|
|
|
13
13
|
targetsToUpdate: FirmwareUpdateV4Target[];
|
|
14
14
|
release: IFirmwareReleaseInfo | undefined;
|
|
15
15
|
};
|
|
16
|
-
export declare function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification, checkFirmwareHash, remotePayloadHashes, firmwareType, release, }: {
|
|
16
|
+
export declare function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification, checkFirmwareHash, remotePayloadHashes, firmwareType, release, deviceType, }: {
|
|
17
17
|
currentVersions: DeviceStateVersions;
|
|
18
18
|
currentVerification?: Partial<DeviceFeaturesVerify>;
|
|
19
19
|
checkFirmwareHash?: boolean;
|
|
20
20
|
remotePayloadHashes?: Readonly<Record<string, string | null>>;
|
|
21
21
|
firmwareType: EFirmwareType;
|
|
22
22
|
release: IFirmwareReleaseInfo | undefined;
|
|
23
|
+
deviceType?: 'pro2' | 'neo';
|
|
23
24
|
}): ProtocolV2FirmwareReleasePlan;
|
|
24
25
|
export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
25
26
|
getSupportedProtocols(): readonly ["V1", "V2"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAyB1C,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,KAAK,6BAA6B,GAAG;IACnC,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,
|
|
1
|
+
{"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAyB1C,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,KAAK,6BAA6B,GAAG;IACnC,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CA4F5B"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { EDeviceType } from '@onekeyfe/hd-shared';
|
|
1
2
|
import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
|
|
2
3
|
import type { FirmwareUpdateV4Params } from '../types/api/firmwareUpdate';
|
|
4
|
+
export declare function assertProtocolV2FirmwareTargetsSupported(deviceType: EDeviceType | string | undefined, params: FirmwareUpdateV4Params): void;
|
|
3
5
|
export declare const isProtocolV2FirmwareFingerprintValid: (binary: ArrayBuffer | Uint8Array, fingerprint: string | undefined) => boolean;
|
|
4
6
|
export declare const assertProtocolV2ReconnectIdentity: (expectedSerialNumber?: string, actualSerialNumber?: string, expectedPath?: string, actualPath?: string) => void;
|
|
5
7
|
export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAwBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAwB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA2CrC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAkB/B;AA0TD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAoHJ,OAAO,CAAC,8BAA8B;IAoBhC,GAAG;;;;;YAKK,aAAa;YAuHb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqD/B,gCAAgC;YAmDhC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAmCjC,+BAA+B;IAqD7C,OAAO,CAAC,uBAAuB;YAMjB,8BAA8B;IA4B5C,OAAO,CAAC,sCAAsC;YAmChC,gCAAgC;YAqChC,0BAA0B;IAexC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA8C9B,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA0CvB,8BAA8B;YA2D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocolV2FileWrite.d.ts","sourceRoot":"","sources":["../../../src/api/helpers/protocolV2FileWrite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,MAAM,GAAG,SAAS,CAAC;IACnF,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC9D,CAAC;
|
|
1
|
+
{"version":3,"file":"protocolV2FileWrite.d.ts","sourceRoot":"","sources":["../../../src/api/helpers/protocolV2FileWrite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,MAAM,GAAG,SAAS,CAAC;IACnF,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC9D,CAAC;AAyDF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,WASzD;AA8CD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;;;;;;GAoO5E"}
|
package/dist/index.d.ts
CHANGED
|
@@ -211,7 +211,7 @@ type IProtocolV2FirmwareComponent = {
|
|
|
211
211
|
expectedSize?: number;
|
|
212
212
|
version?: IVersionArray;
|
|
213
213
|
};
|
|
214
|
-
type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto';
|
|
214
|
+
type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto' | 'firmware_logo';
|
|
215
215
|
/** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
|
|
216
216
|
type IProtocolV2Resource = {
|
|
217
217
|
type: IProtocolV2ResourceType;
|
package/dist/index.js
CHANGED
|
@@ -40511,6 +40511,7 @@ const PROTOCOL_V2_RESOURCE_TYPES = [
|
|
|
40511
40511
|
'translations',
|
|
40512
40512
|
'roobert',
|
|
40513
40513
|
'noto',
|
|
40514
|
+
'firmware_logo',
|
|
40514
40515
|
];
|
|
40515
40516
|
const PROTOCOL_V2_RESOURCE_DEVICE_PATHS = {
|
|
40516
40517
|
images: 'vol0:/bundles/images/images.okpkg',
|
|
@@ -40519,6 +40520,7 @@ const PROTOCOL_V2_RESOURCE_DEVICE_PATHS = {
|
|
|
40519
40520
|
translations: 'vol0:/bundles/translations/translations.okpkg',
|
|
40520
40521
|
roobert: 'vol0:/bundles/font/roobert.okpkg',
|
|
40521
40522
|
noto: 'vol0:/bundles/font/noto.okpkg',
|
|
40523
|
+
firmware_logo: 'vol0:/bundles/firmware_logo.okpkg',
|
|
40522
40524
|
};
|
|
40523
40525
|
const RESOURCE_TYPE_SET = new Set(PROTOCOL_V2_RESOURCE_TYPES);
|
|
40524
40526
|
const SHA256_HEX_LENGTH = 64;
|
|
@@ -40725,7 +40727,7 @@ function parseProtocolV2Resources(value) {
|
|
|
40725
40727
|
const stable = config.stable.map(validateResource);
|
|
40726
40728
|
const types = new Set(stable.map(resource => resource.type));
|
|
40727
40729
|
if (stable.length !== PROTOCOL_V2_RESOURCE_TYPES.length || types.size !== stable.length) {
|
|
40728
|
-
throw new Error(
|
|
40730
|
+
throw new Error(`Invalid Pro2 resources config: stable must contain ${PROTOCOL_V2_RESOURCE_TYPES.length} unique resource types`);
|
|
40729
40731
|
}
|
|
40730
40732
|
for (const type of PROTOCOL_V2_RESOURCE_TYPES) {
|
|
40731
40733
|
if (!types.has(type)) {
|
|
@@ -47498,7 +47500,7 @@ function buildComponentRelease({ configKey, component, currentVersions, currentV
|
|
|
47498
47500
|
required: releaseRequired && status === 'outdated',
|
|
47499
47501
|
};
|
|
47500
47502
|
}
|
|
47501
|
-
function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification = {}, checkFirmwareHash = false, remotePayloadHashes = {}, firmwareType, release, }) {
|
|
47503
|
+
function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification = {}, checkFirmwareHash = false, remotePayloadHashes = {}, firmwareType, release, deviceType, }) {
|
|
47502
47504
|
if (!release) {
|
|
47503
47505
|
return {
|
|
47504
47506
|
firmwareType,
|
|
@@ -47511,17 +47513,24 @@ function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification =
|
|
|
47511
47513
|
release: undefined,
|
|
47512
47514
|
};
|
|
47513
47515
|
}
|
|
47514
|
-
let components = getOrderedComponentEntries(release).map(([configKey, component]) =>
|
|
47515
|
-
|
|
47516
|
-
|
|
47517
|
-
|
|
47518
|
-
|
|
47519
|
-
|
|
47520
|
-
|
|
47521
|
-
|
|
47522
|
-
|
|
47523
|
-
|
|
47524
|
-
|
|
47516
|
+
let components = getOrderedComponentEntries(release).map(([configKey, component]) => {
|
|
47517
|
+
const result = buildComponentRelease({
|
|
47518
|
+
configKey,
|
|
47519
|
+
component,
|
|
47520
|
+
currentVersions,
|
|
47521
|
+
currentVerification,
|
|
47522
|
+
checkFirmwareHash,
|
|
47523
|
+
remotePayloadHash: Object.prototype.hasOwnProperty.call(remotePayloadHashes, configKey)
|
|
47524
|
+
? remotePayloadHashes[configKey]
|
|
47525
|
+
: normalizeHex(component.payloadHash),
|
|
47526
|
+
releaseRequired: release.required,
|
|
47527
|
+
});
|
|
47528
|
+
if (deviceType === 'neo' &&
|
|
47529
|
+
(result.componentTarget === 'SE03' || result.componentTarget === 'SE04')) {
|
|
47530
|
+
return Object.assign(Object.assign({}, result), { updateTarget: null, status: 'unsupported', required: false });
|
|
47531
|
+
}
|
|
47532
|
+
return result;
|
|
47533
|
+
});
|
|
47525
47534
|
if (!currentVersions.applicationP2) {
|
|
47526
47535
|
const applicationP1 = components.find(component => component.componentTarget === 'APPLICATION_P1');
|
|
47527
47536
|
if (applicationP1) {
|
|
@@ -47663,6 +47672,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
47663
47672
|
checkFirmwareHash,
|
|
47664
47673
|
firmwareType,
|
|
47665
47674
|
release,
|
|
47675
|
+
deviceType: state.identity.deviceType,
|
|
47666
47676
|
});
|
|
47667
47677
|
const resourceDeviceType = state.identity.deviceType === 'neo' ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2;
|
|
47668
47678
|
const resources = DataManager.getProtocolV2Resources(resourceDeviceType);
|
|
@@ -50939,6 +50949,20 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
|
|
|
50939
50949
|
const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
50940
50950
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
50941
50951
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
50952
|
+
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
|
|
50953
|
+
function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
|
|
50954
|
+
var _a;
|
|
50955
|
+
if (deviceType !== hdShared.EDeviceType.Neo)
|
|
50956
|
+
return;
|
|
50957
|
+
const unsupportedTargets = new Set(((_a = params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target)));
|
|
50958
|
+
if (params.se03Binary)
|
|
50959
|
+
unsupportedTargets.add('se03');
|
|
50960
|
+
if (params.se04Binary)
|
|
50961
|
+
unsupportedTargets.add('se04');
|
|
50962
|
+
if (unsupportedTargets.size) {
|
|
50963
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Neo only supports SE01 and SE02; unsupported firmware targets: ${Array.from(unsupportedTargets).join(', ')}`);
|
|
50964
|
+
}
|
|
50965
|
+
}
|
|
50942
50966
|
const getProtocolV2DeviceTransferProgress = (bytesBeforeChunk, bytesAfterChunk, totalBytes) => {
|
|
50943
50967
|
if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
|
|
50944
50968
|
return 100;
|
|
@@ -51292,10 +51316,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51292
51316
|
});
|
|
51293
51317
|
}
|
|
51294
51318
|
runProtocolV2() {
|
|
51295
|
-
var _a, _b, _c, _d, _e;
|
|
51319
|
+
var _a, _b, _c, _d, _e, _f;
|
|
51296
51320
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51297
51321
|
yield this.captureProtocolV2PhysicalIdentity();
|
|
51298
51322
|
const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
|
|
51323
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
51324
|
+
const capabilityDeviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
|
|
51325
|
+
? currentDeviceType
|
|
51326
|
+
: getDeviceType(deviceFeatures);
|
|
51327
|
+
assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
|
|
51299
51328
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
51300
51329
|
const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
|
|
51301
51330
|
this.validateExpectedTargetVersions();
|
|
@@ -51304,7 +51333,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51304
51333
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
51305
51334
|
}
|
|
51306
51335
|
const needsRemoteResources = !((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length) && !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
|
|
51307
|
-
const needsRemoteBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('
|
|
51336
|
+
const needsRemoteBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('resource')) ||
|
|
51337
|
+
!!((_f = this.params.targetsToUpdate) === null || _f === void 0 ? void 0 : _f.includes('boot_resources'));
|
|
51308
51338
|
let fwBinaryMap = [];
|
|
51309
51339
|
let bootloaderBinary = null;
|
|
51310
51340
|
let installItems;
|
|
@@ -51787,10 +51817,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51787
51817
|
throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
|
|
51788
51818
|
}
|
|
51789
51819
|
prepareProtocolV2BootResources() {
|
|
51790
|
-
var _a, _b, _c;
|
|
51820
|
+
var _a, _b, _c, _d;
|
|
51791
51821
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51792
|
-
if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('
|
|
51822
|
+
if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) &&
|
|
51823
|
+
!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('boot_resources'))) {
|
|
51793
51824
|
return undefined;
|
|
51825
|
+
}
|
|
51794
51826
|
const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
|
|
51795
51827
|
if (!resource)
|
|
51796
51828
|
throw new Error('Missing Protocol V2 boot resources configuration');
|
|
@@ -51802,7 +51834,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
51802
51834
|
throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
|
|
51803
51835
|
}
|
|
51804
51836
|
files.push({
|
|
51805
|
-
name: (
|
|
51837
|
+
name: (_d = (_c = file.name) !== null && _c !== void 0 ? _c : file.devicePath.split('/').pop()) !== null && _d !== void 0 ? _d : file.devicePath,
|
|
51806
51838
|
binary,
|
|
51807
51839
|
devicePath: file.devicePath,
|
|
51808
51840
|
});
|
|
@@ -52623,7 +52655,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52623
52655
|
});
|
|
52624
52656
|
}
|
|
52625
52657
|
isProtocolV2ReconnectIdentityError(error) {
|
|
52626
|
-
return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
|
|
52658
|
+
return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity mismatch');
|
|
52627
52659
|
}
|
|
52628
52660
|
fileWriteChunk(filePath, totalFileSize, offset, chunk, overwrite, progress) {
|
|
52629
52661
|
var _a;
|
|
@@ -52639,7 +52671,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
|
|
|
52639
52671
|
overwrite,
|
|
52640
52672
|
append: false,
|
|
52641
52673
|
ui_percentage: progress !== null && progress !== void 0 ? progress : undefined,
|
|
52642
|
-
}, {
|
|
52674
|
+
}, {
|
|
52675
|
+
writeWithResponse: false,
|
|
52676
|
+
onWriteCompleted: () => undefined,
|
|
52677
|
+
});
|
|
52643
52678
|
if (writeRes.type !== 'FilesystemFile') {
|
|
52644
52679
|
if (writeRes.type === 'CallMethodError') {
|
|
52645
52680
|
if (((_a = writeRes.message.error) !== null && _a !== void 0 ? _a : '').indexOf(SESSION_ERROR) > -1) {
|
|
@@ -52808,7 +52843,7 @@ class DeviceGetOnboardingStatus extends BaseMethod {
|
|
|
52808
52843
|
}
|
|
52809
52844
|
}
|
|
52810
52845
|
|
|
52811
|
-
const Log$4 = getLogger(exports.LoggerNames.
|
|
52846
|
+
const Log$4 = getLogger(exports.LoggerNames.Core);
|
|
52812
52847
|
const MIN_FILE_CHUNK_SIZE = 64;
|
|
52813
52848
|
const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
|
|
52814
52849
|
const FILE_TRANSFER_LOG_INTERVAL_MS = 10000;
|
|
@@ -52825,8 +52860,11 @@ function getFileTransferTransport() {
|
|
|
52825
52860
|
const env = DataManager.getSettings('env');
|
|
52826
52861
|
return env && DataManager.isBleConnect(env) ? 'BLE' : String(env !== null && env !== void 0 ? env : 'unknown');
|
|
52827
52862
|
}
|
|
52828
|
-
function logFileTransferMetrics({ transport, status, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, }) {
|
|
52829
|
-
|
|
52863
|
+
function logFileTransferMetrics({ transport, status, path, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, hostWriteElapsedMs, responseWaitElapsedMs, measuredAttempts, }) {
|
|
52864
|
+
const segmentedMetrics = measuredAttempts > 0
|
|
52865
|
+
? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(responseWaitElapsedMs / 1000).toFixed(2)}s measuredAttempts=${measuredAttempts}`
|
|
52866
|
+
: '';
|
|
52867
|
+
Log$4.log(`[FileWrite] metrics transport=${transport} status=${status} path=${path} bytes=${transferredBytes}/${totalBytes} elapsed=${(elapsedMs / 1000).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s${segmentedMetrics}`);
|
|
52830
52868
|
}
|
|
52831
52869
|
function isProtocolV2ResponseTimeout(error) {
|
|
52832
52870
|
var _a, _b;
|
|
@@ -52908,7 +52946,11 @@ function writeProtocolV2File(options) {
|
|
|
52908
52946
|
let lastConfirmedAt = startTime;
|
|
52909
52947
|
let logWindowStartedAt = startTime;
|
|
52910
52948
|
let logWindowStartedBytes = 0;
|
|
52949
|
+
let hostWriteElapsedMs = 0;
|
|
52950
|
+
let responseWaitElapsedMs = 0;
|
|
52951
|
+
let measuredAttempts = 0;
|
|
52911
52952
|
const transport = getFileTransferTransport();
|
|
52953
|
+
Log$4.log(`[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`);
|
|
52912
52954
|
try {
|
|
52913
52955
|
while (written < dataLength) {
|
|
52914
52956
|
(_c = options.throwIfAborted) === null || _c === void 0 ? void 0 : _c.call(options);
|
|
@@ -52930,10 +52972,21 @@ function writeProtocolV2File(options) {
|
|
|
52930
52972
|
let response;
|
|
52931
52973
|
let isWritePending = true;
|
|
52932
52974
|
while (isWritePending) {
|
|
52975
|
+
let currentHostWriteElapsedMs;
|
|
52976
|
+
let responseWaitStartedAt;
|
|
52933
52977
|
try {
|
|
52934
52978
|
const callOptions = options.writeWithResponse === undefined
|
|
52935
|
-
? {
|
|
52936
|
-
|
|
52979
|
+
? {
|
|
52980
|
+
timeoutMs: options.timeoutMs,
|
|
52981
|
+
onWriteCompleted: ({ elapsedMs }) => {
|
|
52982
|
+
currentHostWriteElapsedMs = elapsedMs;
|
|
52983
|
+
responseWaitStartedAt = Date.now();
|
|
52984
|
+
},
|
|
52985
|
+
}
|
|
52986
|
+
: Object.assign(Object.assign({}, (options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })), { writeWithResponse: options.writeWithResponse, onWriteCompleted: ({ elapsedMs }) => {
|
|
52987
|
+
currentHostWriteElapsedMs = elapsedMs;
|
|
52988
|
+
responseWaitStartedAt = Date.now();
|
|
52989
|
+
} });
|
|
52937
52990
|
response = yield options.commands.typedCall('FilesystemFileWrite', 'FilesystemFile', request, callOptions);
|
|
52938
52991
|
isWritePending = false;
|
|
52939
52992
|
}
|
|
@@ -52943,6 +52996,13 @@ function writeProtocolV2File(options) {
|
|
|
52943
52996
|
retryCount += 1;
|
|
52944
52997
|
(_k = options.throwIfAborted) === null || _k === void 0 ? void 0 : _k.call(options);
|
|
52945
52998
|
}
|
|
52999
|
+
finally {
|
|
53000
|
+
if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
|
|
53001
|
+
hostWriteElapsedMs += currentHostWriteElapsedMs;
|
|
53002
|
+
responseWaitElapsedMs += Math.max(Date.now() - responseWaitStartedAt, 0);
|
|
53003
|
+
measuredAttempts += 1;
|
|
53004
|
+
}
|
|
53005
|
+
}
|
|
52946
53006
|
}
|
|
52947
53007
|
if (!response) {
|
|
52948
53008
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite completed without a response');
|
|
@@ -52995,10 +53055,14 @@ function writeProtocolV2File(options) {
|
|
|
52995
53055
|
logFileTransferMetrics({
|
|
52996
53056
|
transport,
|
|
52997
53057
|
status: 'progress',
|
|
53058
|
+
path: options.path,
|
|
52998
53059
|
transferredBytes,
|
|
52999
53060
|
totalBytes: dataLength,
|
|
53000
53061
|
elapsedMs,
|
|
53001
53062
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
53063
|
+
hostWriteElapsedMs,
|
|
53064
|
+
responseWaitElapsedMs,
|
|
53065
|
+
measuredAttempts,
|
|
53002
53066
|
});
|
|
53003
53067
|
logWindowStartedAt = now;
|
|
53004
53068
|
logWindowStartedBytes = transferredBytes;
|
|
@@ -53018,10 +53082,14 @@ function writeProtocolV2File(options) {
|
|
|
53018
53082
|
logFileTransferMetrics({
|
|
53019
53083
|
transport,
|
|
53020
53084
|
status: 'failed',
|
|
53085
|
+
path: options.path,
|
|
53021
53086
|
transferredBytes: written,
|
|
53022
53087
|
totalBytes: dataLength,
|
|
53023
53088
|
elapsedMs,
|
|
53024
53089
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
53090
|
+
hostWriteElapsedMs,
|
|
53091
|
+
responseWaitElapsedMs,
|
|
53092
|
+
measuredAttempts,
|
|
53025
53093
|
});
|
|
53026
53094
|
throw error;
|
|
53027
53095
|
}
|
|
@@ -53031,10 +53099,14 @@ function writeProtocolV2File(options) {
|
|
|
53031
53099
|
logFileTransferMetrics({
|
|
53032
53100
|
transport,
|
|
53033
53101
|
status: 'completed',
|
|
53102
|
+
path: options.path,
|
|
53034
53103
|
transferredBytes: written,
|
|
53035
53104
|
totalBytes: dataLength,
|
|
53036
53105
|
elapsedMs,
|
|
53037
53106
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
53107
|
+
hostWriteElapsedMs,
|
|
53108
|
+
responseWaitElapsedMs,
|
|
53109
|
+
measuredAttempts,
|
|
53038
53110
|
});
|
|
53039
53111
|
return Object.assign(Object.assign({}, lastMessage), { path: options.path, offset: startOffset, total_size: totalSize, processed_byte: startOffset + written, chunks });
|
|
53040
53112
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IProtocolV2Resource, IProtocolV2ResourceFile, IProtocolV2ResourceType, IProtocolV2Resources } from '../../types';
|
|
2
2
|
import type { DeviceCommands } from '../../device/DeviceCommands';
|
|
3
|
-
export declare const PROTOCOL_V2_RESOURCE_TYPES: readonly ["images", "animation", "wallpaper", "translations", "roobert", "noto"];
|
|
3
|
+
export declare const PROTOCOL_V2_RESOURCE_TYPES: readonly ["images", "animation", "wallpaper", "translations", "roobert", "noto", "firmware_logo"];
|
|
4
4
|
export declare const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2ResourceType, string>>;
|
|
5
5
|
export declare const PROTOCOL_V2_RESOURCE_INVENTORY_TIMEOUT_MS: number;
|
|
6
6
|
export type ProtocolV2ResourceInventoryItem = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/resources.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,eAAO,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/resources.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,eAAO,MAAM,0BAA0B,mGAQgB,CAAC;AAExD,eAAO,MAAM,iCAAiC,EAAE,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAS7F,CAAC;AAaJ,eAAO,MAAM,yCAAyC,QAAW,CAAC;AAElE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,aAAa,GAAG,qBAAqB,CAAC;AAEjF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACzC,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC,CAAC;AAwHF,wBAAsB,+BAA+B,CAAC,EACpD,QAAQ,EACR,SAAS,EACT,SAAgD,EAChD,SAAqD,GACtD,EAAE;IACD,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAmB7C;AAiGD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAkCzF;AAGD,wBAAgB,iCAAiC,CAAC,EAChD,SAAS,EACT,SAAS,EACT,IAAI,EACJ,MAAc,GACf,EAAE;IACD,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,SAAS,+BAA+B,EAAE,CAAC;IACvD,IAAI,EAAE,4BAA4B,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,4BAA4B,CA8B/B;AAOD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,UAAU,CAAC,GAC3D,OAAO,CAGT"}
|
package/dist/types/settings.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type IProtocolV2FirmwareComponent = {
|
|
|
35
35
|
expectedSize?: number;
|
|
36
36
|
version?: IVersionArray;
|
|
37
37
|
};
|
|
38
|
-
export type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto';
|
|
38
|
+
export type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto' | 'firmware_logo';
|
|
39
39
|
export type IProtocolV2Resource = {
|
|
40
40
|
type: IProtocolV2ResourceType;
|
|
41
41
|
url: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,KAAK,GACL,cAAc,GACd,UAAU,GACV,cAAc,GACd,QAAQ,GACR,gBAAgB,GAChB,iBAAiB,GACjB,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AACf,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,GAAG,EAAE,YAAY,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC;IACvD,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;CACvE,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAExC,MAAM,MAAM,kCAAkC,GAC1C,WAAW,GACX,YAAY,GACZ,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,kCAAkC,CAAC;IAC3C,GAAG,EAAE,MAAM,CAAC;IAEZ,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,WAAW,GACX,WAAW,GACX,cAAc,GACd,SAAS,GACT,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.71",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.71",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.71",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"bytebuffer": "^5.0.1",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@types/w3c-web-usb": "^1.0.10",
|
|
45
45
|
"@types/web-bluetooth": "^0.0.21"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "c58f39f2e5c54a98faa8844cd8b6b0453a17d80c"
|
|
48
48
|
}
|
|
@@ -191,6 +191,7 @@ export function buildProtocolV2FirmwareRelease({
|
|
|
191
191
|
remotePayloadHashes = {},
|
|
192
192
|
firmwareType,
|
|
193
193
|
release,
|
|
194
|
+
deviceType,
|
|
194
195
|
}: {
|
|
195
196
|
currentVersions: DeviceStateVersions;
|
|
196
197
|
currentVerification?: Partial<DeviceFeaturesVerify>;
|
|
@@ -198,6 +199,7 @@ export function buildProtocolV2FirmwareRelease({
|
|
|
198
199
|
remotePayloadHashes?: Readonly<Record<string, string | null>>;
|
|
199
200
|
firmwareType: EFirmwareType;
|
|
200
201
|
release: IFirmwareReleaseInfo | undefined;
|
|
202
|
+
deviceType?: 'pro2' | 'neo';
|
|
201
203
|
}): ProtocolV2FirmwareReleasePlan {
|
|
202
204
|
if (!release) {
|
|
203
205
|
return {
|
|
@@ -212,8 +214,8 @@ export function buildProtocolV2FirmwareRelease({
|
|
|
212
214
|
};
|
|
213
215
|
}
|
|
214
216
|
|
|
215
|
-
let components = getOrderedComponentEntries(release).map(([configKey, component]) =>
|
|
216
|
-
buildComponentRelease({
|
|
217
|
+
let components = getOrderedComponentEntries(release).map(([configKey, component]) => {
|
|
218
|
+
const result = buildComponentRelease({
|
|
217
219
|
configKey,
|
|
218
220
|
component,
|
|
219
221
|
currentVersions,
|
|
@@ -223,8 +225,20 @@ export function buildProtocolV2FirmwareRelease({
|
|
|
223
225
|
? remotePayloadHashes[configKey]
|
|
224
226
|
: normalizeHex(component.payloadHash),
|
|
225
227
|
releaseRequired: release.required,
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
+
});
|
|
229
|
+
if (
|
|
230
|
+
deviceType === 'neo' &&
|
|
231
|
+
(result.componentTarget === 'SE03' || result.componentTarget === 'SE04')
|
|
232
|
+
) {
|
|
233
|
+
return {
|
|
234
|
+
...result,
|
|
235
|
+
updateTarget: null,
|
|
236
|
+
status: 'unsupported' as const,
|
|
237
|
+
required: false,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return result;
|
|
241
|
+
});
|
|
228
242
|
if (!currentVersions.applicationP2) {
|
|
229
243
|
const applicationP1 = components.find(
|
|
230
244
|
component => component.componentTarget === 'APPLICATION_P1'
|
|
@@ -401,6 +415,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
|
|
|
401
415
|
checkFirmwareHash,
|
|
402
416
|
firmwareType,
|
|
403
417
|
release,
|
|
418
|
+
deviceType: state.identity.deviceType,
|
|
404
419
|
});
|
|
405
420
|
const resourceDeviceType =
|
|
406
421
|
state.identity.deviceType === 'neo' ? EDeviceType.Neo : EDeviceType.Pro2;
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getDeviceBLEFirmwareVersion,
|
|
16
16
|
getDeviceBootloaderVersion,
|
|
17
17
|
getDeviceFirmwareVersion,
|
|
18
|
+
getDeviceType,
|
|
18
19
|
getFirmwareType,
|
|
19
20
|
getLogger,
|
|
20
21
|
} from '../utils';
|
|
@@ -90,6 +91,30 @@ const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
|
|
|
90
91
|
const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
|
|
91
92
|
const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
|
|
92
93
|
|
|
94
|
+
const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set<FirmwareUpdateV4Target>(['se03', 'se04']);
|
|
95
|
+
|
|
96
|
+
export function assertProtocolV2FirmwareTargetsSupported(
|
|
97
|
+
deviceType: EDeviceType | string | undefined,
|
|
98
|
+
params: FirmwareUpdateV4Params
|
|
99
|
+
) {
|
|
100
|
+
if (deviceType !== EDeviceType.Neo) return;
|
|
101
|
+
|
|
102
|
+
const unsupportedTargets = new Set(
|
|
103
|
+
(params.targetsToUpdate ?? []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target))
|
|
104
|
+
);
|
|
105
|
+
if (params.se03Binary) unsupportedTargets.add('se03');
|
|
106
|
+
if (params.se04Binary) unsupportedTargets.add('se04');
|
|
107
|
+
|
|
108
|
+
if (unsupportedTargets.size) {
|
|
109
|
+
throw ERRORS.TypedError(
|
|
110
|
+
HardwareErrorCode.RuntimeError,
|
|
111
|
+
`Neo only supports SE01 and SE02; unsupported firmware targets: ${Array.from(
|
|
112
|
+
unsupportedTargets
|
|
113
|
+
).join(', ')}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
93
118
|
const getProtocolV2DeviceTransferProgress = (
|
|
94
119
|
bytesBeforeChunk: number,
|
|
95
120
|
bytesAfterChunk: number,
|
|
@@ -610,6 +635,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
610
635
|
private async runProtocolV2() {
|
|
611
636
|
await this.captureProtocolV2PhysicalIdentity();
|
|
612
637
|
const deviceFeatures = await this.getProtocolV2DeviceFeatures();
|
|
638
|
+
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
639
|
+
const capabilityDeviceType =
|
|
640
|
+
currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
|
|
641
|
+
? currentDeviceType
|
|
642
|
+
: getDeviceType(deviceFeatures);
|
|
643
|
+
assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
|
|
613
644
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
614
645
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
615
646
|
this.validateExpectedTargetVersions();
|
|
@@ -622,7 +653,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
622
653
|
}
|
|
623
654
|
const needsRemoteResources =
|
|
624
655
|
!this.params.resourceFiles?.length && !!this.params.targetsToUpdate?.includes('resource');
|
|
625
|
-
const needsRemoteBootResources =
|
|
656
|
+
const needsRemoteBootResources =
|
|
657
|
+
!!this.params.targetsToUpdate?.includes('resource') ||
|
|
658
|
+
!!this.params.targetsToUpdate?.includes('boot_resources');
|
|
626
659
|
|
|
627
660
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
628
661
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
@@ -1223,7 +1256,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1223
1256
|
private async prepareProtocolV2BootResources(): Promise<
|
|
1224
1257
|
ProtocolV2ResourceBundleBinary[] | undefined
|
|
1225
1258
|
> {
|
|
1226
|
-
if (
|
|
1259
|
+
if (
|
|
1260
|
+
!this.params.targetsToUpdate?.includes('resource') &&
|
|
1261
|
+
!this.params.targetsToUpdate?.includes('boot_resources')
|
|
1262
|
+
) {
|
|
1263
|
+
return undefined;
|
|
1264
|
+
}
|
|
1227
1265
|
const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
|
|
1228
1266
|
if (!resource) throw new Error('Missing Protocol V2 boot resources configuration');
|
|
1229
1267
|
|
|
@@ -2289,7 +2327,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2289
2327
|
}
|
|
2290
2328
|
|
|
2291
2329
|
private isProtocolV2ReconnectIdentityError(error: unknown) {
|
|
2292
|
-
|
|
2330
|
+
// A serial can be temporarily unavailable while Loader starts, and BLE has no stable path.
|
|
2331
|
+
// Keep polling unless the device explicitly reports a different serial.
|
|
2332
|
+
return this.normalizeErrorMessage(error).includes(
|
|
2333
|
+
'Protocol V2 reconnect physical identity mismatch'
|
|
2334
|
+
);
|
|
2293
2335
|
}
|
|
2294
2336
|
|
|
2295
2337
|
private async fileWriteChunk(
|
|
@@ -2315,7 +2357,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2315
2357
|
append: false,
|
|
2316
2358
|
ui_percentage: progress ?? undefined,
|
|
2317
2359
|
},
|
|
2318
|
-
{
|
|
2360
|
+
{
|
|
2361
|
+
writeWithResponse: false,
|
|
2362
|
+
onWriteCompleted: () => undefined,
|
|
2363
|
+
}
|
|
2319
2364
|
);
|
|
2320
2365
|
if (writeRes.type !== 'FilesystemFile') {
|
|
2321
2366
|
if ((writeRes as any).type === 'CallMethodError') {
|
|
@@ -9,7 +9,7 @@ import { LoggerNames, getLogger } from '../../utils/logger';
|
|
|
9
9
|
|
|
10
10
|
import type { DeviceCommands } from '../../device/DeviceCommands';
|
|
11
11
|
|
|
12
|
-
const Log = getLogger(LoggerNames.
|
|
12
|
+
const Log = getLogger(LoggerNames.Core);
|
|
13
13
|
|
|
14
14
|
export type ProtocolV2FileWriteData = ArrayBuffer | Uint8Array | Blob | string;
|
|
15
15
|
|
|
@@ -69,22 +69,36 @@ function getFileTransferTransport() {
|
|
|
69
69
|
function logFileTransferMetrics({
|
|
70
70
|
transport,
|
|
71
71
|
status,
|
|
72
|
+
path,
|
|
72
73
|
transferredBytes,
|
|
73
74
|
totalBytes,
|
|
74
75
|
elapsedMs,
|
|
75
76
|
rateBytesPerSecond,
|
|
77
|
+
hostWriteElapsedMs,
|
|
78
|
+
responseWaitElapsedMs,
|
|
79
|
+
measuredAttempts,
|
|
76
80
|
}: {
|
|
77
81
|
transport: string;
|
|
78
82
|
status: 'progress' | 'completed' | 'failed';
|
|
83
|
+
path: string;
|
|
79
84
|
transferredBytes: number;
|
|
80
85
|
totalBytes: number;
|
|
81
86
|
elapsedMs: number;
|
|
82
87
|
rateBytesPerSecond: number;
|
|
88
|
+
hostWriteElapsedMs: number;
|
|
89
|
+
responseWaitElapsedMs: number;
|
|
90
|
+
measuredAttempts: number;
|
|
83
91
|
}) {
|
|
92
|
+
const segmentedMetrics =
|
|
93
|
+
measuredAttempts > 0
|
|
94
|
+
? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(
|
|
95
|
+
responseWaitElapsedMs / 1000
|
|
96
|
+
).toFixed(2)}s measuredAttempts=${measuredAttempts}`
|
|
97
|
+
: '';
|
|
84
98
|
Log.log(
|
|
85
|
-
`[FileWrite] metrics transport=${transport} status=${status} bytes=${transferredBytes}/${totalBytes} elapsed=${(
|
|
99
|
+
`[FileWrite] metrics transport=${transport} status=${status} path=${path} bytes=${transferredBytes}/${totalBytes} elapsed=${(
|
|
86
100
|
elapsedMs / 1000
|
|
87
|
-
).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s`
|
|
101
|
+
).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s${segmentedMetrics}`
|
|
88
102
|
);
|
|
89
103
|
}
|
|
90
104
|
|
|
@@ -177,7 +191,13 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
177
191
|
let lastConfirmedAt = startTime;
|
|
178
192
|
let logWindowStartedAt = startTime;
|
|
179
193
|
let logWindowStartedBytes = 0;
|
|
194
|
+
let hostWriteElapsedMs = 0;
|
|
195
|
+
let responseWaitElapsedMs = 0;
|
|
196
|
+
let measuredAttempts = 0;
|
|
180
197
|
const transport = getFileTransferTransport();
|
|
198
|
+
Log.log(
|
|
199
|
+
`[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`
|
|
200
|
+
);
|
|
181
201
|
|
|
182
202
|
try {
|
|
183
203
|
while (written < dataLength) {
|
|
@@ -203,13 +223,25 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
203
223
|
let response;
|
|
204
224
|
let isWritePending = true;
|
|
205
225
|
while (isWritePending) {
|
|
226
|
+
let currentHostWriteElapsedMs: number | undefined;
|
|
227
|
+
let responseWaitStartedAt: number | undefined;
|
|
206
228
|
try {
|
|
207
229
|
const callOptions =
|
|
208
230
|
options.writeWithResponse === undefined
|
|
209
|
-
? {
|
|
231
|
+
? {
|
|
232
|
+
timeoutMs: options.timeoutMs,
|
|
233
|
+
onWriteCompleted: ({ elapsedMs }: { elapsedMs: number }) => {
|
|
234
|
+
currentHostWriteElapsedMs = elapsedMs;
|
|
235
|
+
responseWaitStartedAt = Date.now();
|
|
236
|
+
},
|
|
237
|
+
}
|
|
210
238
|
: {
|
|
211
239
|
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
212
240
|
writeWithResponse: options.writeWithResponse,
|
|
241
|
+
onWriteCompleted: ({ elapsedMs }: { elapsedMs: number }) => {
|
|
242
|
+
currentHostWriteElapsedMs = elapsedMs;
|
|
243
|
+
responseWaitStartedAt = Date.now();
|
|
244
|
+
},
|
|
213
245
|
};
|
|
214
246
|
response = await options.commands.typedCall(
|
|
215
247
|
'FilesystemFileWrite',
|
|
@@ -222,6 +254,12 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
222
254
|
if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
|
|
223
255
|
retryCount += 1;
|
|
224
256
|
options.throwIfAborted?.();
|
|
257
|
+
} finally {
|
|
258
|
+
if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
|
|
259
|
+
hostWriteElapsedMs += currentHostWriteElapsedMs;
|
|
260
|
+
responseWaitElapsedMs += Math.max(Date.now() - responseWaitStartedAt, 0);
|
|
261
|
+
measuredAttempts += 1;
|
|
262
|
+
}
|
|
225
263
|
}
|
|
226
264
|
}
|
|
227
265
|
if (!response) {
|
|
@@ -285,10 +323,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
285
323
|
logFileTransferMetrics({
|
|
286
324
|
transport,
|
|
287
325
|
status: 'progress',
|
|
326
|
+
path: options.path,
|
|
288
327
|
transferredBytes,
|
|
289
328
|
totalBytes: dataLength,
|
|
290
329
|
elapsedMs,
|
|
291
330
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
331
|
+
hostWriteElapsedMs,
|
|
332
|
+
responseWaitElapsedMs,
|
|
333
|
+
measuredAttempts,
|
|
292
334
|
});
|
|
293
335
|
logWindowStartedAt = now;
|
|
294
336
|
logWindowStartedBytes = transferredBytes;
|
|
@@ -307,10 +349,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
307
349
|
logFileTransferMetrics({
|
|
308
350
|
transport,
|
|
309
351
|
status: 'failed',
|
|
352
|
+
path: options.path,
|
|
310
353
|
transferredBytes: written,
|
|
311
354
|
totalBytes: dataLength,
|
|
312
355
|
elapsedMs,
|
|
313
356
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
357
|
+
hostWriteElapsedMs,
|
|
358
|
+
responseWaitElapsedMs,
|
|
359
|
+
measuredAttempts,
|
|
314
360
|
});
|
|
315
361
|
throw error;
|
|
316
362
|
}
|
|
@@ -321,10 +367,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
321
367
|
logFileTransferMetrics({
|
|
322
368
|
transport,
|
|
323
369
|
status: 'completed',
|
|
370
|
+
path: options.path,
|
|
324
371
|
transferredBytes: written,
|
|
325
372
|
totalBytes: dataLength,
|
|
326
373
|
elapsedMs,
|
|
327
374
|
rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
|
|
375
|
+
hostWriteElapsedMs,
|
|
376
|
+
responseWaitElapsedMs,
|
|
377
|
+
measuredAttempts,
|
|
328
378
|
});
|
|
329
379
|
|
|
330
380
|
return {
|
|
@@ -17,6 +17,7 @@ export const PROTOCOL_V2_RESOURCE_TYPES = [
|
|
|
17
17
|
'translations',
|
|
18
18
|
'roobert',
|
|
19
19
|
'noto',
|
|
20
|
+
'firmware_logo',
|
|
20
21
|
] as const satisfies readonly IProtocolV2ResourceType[];
|
|
21
22
|
|
|
22
23
|
export const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2ResourceType, string>> =
|
|
@@ -27,6 +28,7 @@ export const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2Resou
|
|
|
27
28
|
translations: 'vol0:/bundles/translations/translations.okpkg',
|
|
28
29
|
roobert: 'vol0:/bundles/font/roobert.okpkg',
|
|
29
30
|
noto: 'vol0:/bundles/font/noto.okpkg',
|
|
31
|
+
firmware_logo: 'vol0:/bundles/firmware_logo.okpkg',
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
const RESOURCE_TYPE_SET = new Set<string>(PROTOCOL_V2_RESOURCE_TYPES);
|
|
@@ -313,7 +315,9 @@ export function parseProtocolV2Resources(value: unknown): IProtocolV2Resources |
|
|
|
313
315
|
const stable = config.stable.map(validateResource);
|
|
314
316
|
const types = new Set(stable.map(resource => resource.type));
|
|
315
317
|
if (stable.length !== PROTOCOL_V2_RESOURCE_TYPES.length || types.size !== stable.length) {
|
|
316
|
-
throw new Error(
|
|
318
|
+
throw new Error(
|
|
319
|
+
`Invalid Pro2 resources config: stable must contain ${PROTOCOL_V2_RESOURCE_TYPES.length} unique resource types`
|
|
320
|
+
);
|
|
317
321
|
}
|
|
318
322
|
for (const type of PROTOCOL_V2_RESOURCE_TYPES) {
|
|
319
323
|
if (!types.has(type)) {
|
package/src/types/settings.ts
CHANGED
|
@@ -70,7 +70,8 @@ export type IProtocolV2ResourceType =
|
|
|
70
70
|
| 'wallpaper'
|
|
71
71
|
| 'translations'
|
|
72
72
|
| 'roobert'
|
|
73
|
-
| 'noto'
|
|
73
|
+
| 'noto'
|
|
74
|
+
| 'firmware_logo';
|
|
74
75
|
|
|
75
76
|
/** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
|
|
76
77
|
export type IProtocolV2Resource = {
|