@onekeyfe/hd-core 1.2.0-alpha.128 → 1.2.0-alpha.129

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.
@@ -114,7 +114,6 @@ describe('DeviceUploadNft', () => {
114
114
  chunkSize: 2048,
115
115
  paceMs: 0,
116
116
  });
117
- expect(method.unlockPolicy).toBe('unlock-before-run');
118
117
  });
119
118
 
120
119
  test('rejects invalid image Base64 before device communication', () => {
@@ -105,6 +105,27 @@ const createPreparedResourcePlan = ({
105
105
  };
106
106
 
107
107
  describe.each(['v2', 'v3'] as const)('%s prepared resource archive binding', executor => {
108
+ test('rejects a missing artifact reader', async () => {
109
+ const entryBinary = Uint8Array.from([1, 2, 3, 4]).buffer;
110
+ const zip = new JSZip();
111
+ zip.file('images/logo.bin', entryBinary);
112
+ const archiveBinary = await zip.generateAsync({ type: 'arraybuffer' });
113
+ const { preparedPlan } = createPreparedResourcePlan({
114
+ executor,
115
+ archiveBinary,
116
+ entryBinary,
117
+ });
118
+
119
+ await expect(
120
+ readVerifiedPreparedResourceArchive({
121
+ preparedPlan,
122
+ reader: undefined,
123
+ })
124
+ ).rejects.toMatchObject({
125
+ params: { firmwareUpdateCode: 'FirmwareArtifactReaderInvalid' },
126
+ });
127
+ });
128
+
108
129
  test('uses canonical bytes extracted from the approved ZIP', async () => {
109
130
  const entryBinary = Uint8Array.from([1, 2, 3, 4]).buffer;
110
131
  const zip = new JSZip();
@@ -42,7 +42,12 @@ describe('FirmwareUpdateV4 install polling', () => {
42
42
 
43
43
  method.device = {
44
44
  getCommands: () => ({ typedCall, call }),
45
+ createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
46
+ toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2-ble' }),
47
+ setCancelableAction: jest.fn(),
48
+ clearCancelableAction: jest.fn(),
45
49
  } as unknown as Device;
50
+ method.postMessage = jest.fn();
46
51
  method.postTipMessage = jest.fn();
47
52
  method.postProgressMessage = jest.fn();
48
53
 
@@ -31,25 +31,6 @@ const neoResourceSource = {
31
31
  archiveSize: 12_345_678,
32
32
  };
33
33
 
34
- const pro2Features = {
35
- deviceType: EDeviceType.Pro2,
36
- firmwareVersion: '1.0.0',
37
- } as unknown as Features;
38
-
39
- const neoFeatures = {
40
- deviceType: EDeviceType.Neo,
41
- firmwareVersion: '1.0.0',
42
- } as unknown as Features;
43
-
44
- const createProtocolV2Release = (source: typeof resourceSource) => ({
45
- required: false,
46
- version: [1, 0, 0],
47
- url: 'https://example.com/firmware.okpkg',
48
- fingerprint: 'c'.repeat(64),
49
- changelog: {},
50
- resources: { source },
51
- });
52
-
53
34
  const manifestFiles = [
54
35
  ['bundles/firmware_logo-build.okpkg', 'firmware_logo.okpkg', 'vol0:/bundles/firmware_logo.okpkg'],
55
36
  ['bundles/font/noto-build.okpkg', 'noto.okpkg', 'vol0:/bundles/font/noto.okpkg'],
@@ -127,11 +108,38 @@ const createRemoteConfig = (): RemoteConfigResponse =>
127
108
  mini: { firmware: [], ble: [] },
128
109
  touch: { firmware: [], ble: [] },
129
110
  pro: { firmware: [], ble: [] },
130
- pro2: { 'firmware-v1': [createProtocolV2Release(resourceSource)] },
131
- neo: { 'firmware-v1': [createProtocolV2Release(neoResourceSource)] },
111
+ pro2: {
112
+ 'firmware-v1': [
113
+ {
114
+ required: false,
115
+ version: [1, 0, 0],
116
+ url: 'https://example.com/pro2.okpkg',
117
+ fingerprint: 'a'.repeat(64),
118
+ changelog: { 'zh-CN': 'Pro2', 'en-US': 'Pro2' },
119
+ resources: { source: resourceSource },
120
+ },
121
+ ],
122
+ ble: [],
123
+ },
124
+ neo: {
125
+ 'firmware-v1': [
126
+ {
127
+ required: false,
128
+ version: [1, 0, 0],
129
+ url: 'https://example.com/neo.okpkg',
130
+ fingerprint: 'b'.repeat(64),
131
+ changelog: { 'zh-CN': 'Neo', 'en-US': 'Neo' },
132
+ resources: { source: neoResourceSource },
133
+ },
134
+ ],
135
+ ble: [],
136
+ },
132
137
  bridge: {},
133
138
  } as unknown as RemoteConfigResponse);
134
139
 
140
+ const getProtocolV2Release = (deviceType: EDeviceType.Pro2 | EDeviceType.Neo) =>
141
+ DataManager.deviceMap[deviceType]?.['firmware-v1']?.[0];
142
+
135
143
  describe('Pro2 resource configuration', () => {
136
144
  beforeEach(() => {
137
145
  jest.clearAllMocks();
@@ -203,52 +211,68 @@ describe('Pro2 resource configuration', () => {
203
211
  expect(configFetcher).toHaveBeenCalledWith(
204
212
  expect.stringMatching(/^https:\/\/data\.onekey\.so\/pre-config\.json\?noCache=/)
205
213
  );
206
- expect(DataManager.getProtocolV2ResourceSource(pro2Features, EFirmwareType.Universal)).toEqual(
214
+ expect(DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Pro2))).toEqual(
207
215
  resourceSource
208
216
  );
209
217
  expect(DataManager.lastCheckTimestamp).toBeGreaterThan(0);
210
218
  });
211
219
 
212
- test('does not use a device-level resource archive outside the selected firmware release', async () => {
213
- const remoteConfig = createRemoteConfig();
214
- const pro2Config = remoteConfig.pro2 as {
215
- resources?: unknown;
216
- 'firmware-v1': Array<{ resources?: unknown }>;
220
+ test('uses the resource archive bound to the selected firmware release', async () => {
221
+ const newerResourceSource = {
222
+ archiveUrl: 'https://example.com/resource/pro2-resource-v2.zip',
223
+ archiveSha256: 'c'.repeat(64),
224
+ archiveSize: 20_000_000,
217
225
  };
218
- pro2Config.resources = { source: resourceSource };
219
- delete pro2Config['firmware-v1'][0].resources;
226
+ const remoteConfig = createRemoteConfig();
227
+ remoteConfig.pro2['firmware-v1']?.push({
228
+ ...remoteConfig.pro2['firmware-v1'][0],
229
+ version: [2, 0, 0],
230
+ resources: { source: newerResourceSource },
231
+ });
220
232
 
221
233
  await expect(
222
234
  DataManager.load(createSettings(jest.fn().mockResolvedValue(remoteConfig)))
223
235
  ).resolves.toBe(true);
224
236
 
225
- expect(
226
- DataManager.getProtocolV2ResourceSource(pro2Features, EFirmwareType.Universal)
227
- ).toBeUndefined();
237
+ const selectedRelease = DataManager.getFirmwareLatestRelease(
238
+ { deviceType: 'pro2', firmwareVersion: '1.0.0' } as Features,
239
+ EFirmwareType.Universal
240
+ );
241
+ expect(selectedRelease?.version).toEqual([2, 0, 0]);
242
+ expect(DataManager.getProtocolV2ResourceSource(selectedRelease)).toEqual(newerResourceSource);
228
243
  });
229
244
 
230
- test('uses the resource archive from the selected latest firmware release', async () => {
245
+ test('does not use a device-level Protocol V2 resource archive', async () => {
231
246
  const remoteConfig = createRemoteConfig();
232
- const olderRelease = {
233
- ...createProtocolV2Release(resourceSource),
234
- version: [0, 9, 0],
235
- };
236
- const latestRelease = {
237
- ...createProtocolV2Release(neoResourceSource),
238
- version: [1, 1, 0],
247
+ delete remoteConfig.pro2['firmware-v1']?.[0].resources;
248
+ (remoteConfig.pro2 as unknown as { resources: unknown }).resources = {
249
+ source: resourceSource,
239
250
  };
240
- (remoteConfig.pro2 as { 'firmware-v1': unknown[] })['firmware-v1'] = [
241
- olderRelease,
242
- latestRelease,
243
- ];
244
251
 
245
252
  await expect(
246
253
  DataManager.load(createSettings(jest.fn().mockResolvedValue(remoteConfig)))
247
254
  ).resolves.toBe(true);
248
255
 
249
- expect(DataManager.getProtocolV2ResourceSource(pro2Features, EFirmwareType.Universal)).toEqual(
250
- neoResourceSource
251
- );
256
+ expect(
257
+ DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Pro2))
258
+ ).toBeUndefined();
259
+ });
260
+
261
+ test('does not block the latest release when an older release has invalid resources', async () => {
262
+ const remoteConfig = createRemoteConfig();
263
+ (remoteConfig.pro2['firmware-v1']?.[0] as { resources?: unknown }).resources = { source: {} };
264
+ remoteConfig.pro2['firmware-v1']?.push({
265
+ ...remoteConfig.pro2['firmware-v1'][0],
266
+ version: [2, 0, 0],
267
+ resources: { source: resourceSource },
268
+ });
269
+ const configFetcher = jest.fn().mockResolvedValue(remoteConfig);
270
+
271
+ await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
272
+ await expect(DataManager.forceReloadData({ requireResources: true })).resolves.toBeUndefined();
273
+
274
+ const latestRelease = DataManager.deviceMap[EDeviceType.Pro2]?.['firmware-v1']?.[1];
275
+ expect(DataManager.getProtocolV2ResourceSource(latestRelease)).toEqual(resourceSource);
252
276
  });
253
277
 
254
278
  test('reuses the configuration fetched during SDK initialization for an immediate update', async () => {
@@ -263,40 +287,32 @@ describe('Pro2 resource configuration', () => {
263
287
 
264
288
  test('keeps base SDK initialization available when remote Pro2 resources are invalid', async () => {
265
289
  const remoteConfig = createRemoteConfig();
266
- (
267
- remoteConfig.pro2 as {
268
- 'firmware-v1': Array<{ resources?: unknown }>;
269
- }
270
- )['firmware-v1'][0].resources = { source: {} };
290
+ (remoteConfig.pro2['firmware-v1']?.[0] as { resources?: unknown }).resources = { source: {} };
271
291
  const configFetcher = jest.fn().mockResolvedValue(remoteConfig);
272
292
 
273
293
  await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
274
294
 
275
295
  expect(
276
- DataManager.getProtocolV2ResourceSource(pro2Features, EFirmwareType.Universal)
296
+ DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Pro2))
277
297
  ).toBeUndefined();
278
298
  expect(DataManager.protocolV2ResourcesConfigError).toBeInstanceOf(Error);
279
- expect(DataManager.getProtocolV2ResourceSource(neoFeatures, EFirmwareType.Universal)).toEqual(
299
+ expect(DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Neo))).toEqual(
280
300
  neoResourceSource
281
301
  );
282
302
  });
283
303
 
284
304
  test('keeps Pro2 resources available when remote Neo resources are invalid', async () => {
285
305
  const remoteConfig = createRemoteConfig();
286
- (
287
- remoteConfig.neo as {
288
- 'firmware-v1': Array<{ resources?: unknown }>;
289
- }
290
- )['firmware-v1'][0].resources = { source: {} };
306
+ (remoteConfig.neo?.['firmware-v1']?.[0] as { resources?: unknown }).resources = { source: {} };
291
307
  const configFetcher = jest.fn().mockResolvedValue(remoteConfig);
292
308
 
293
309
  await expect(DataManager.load(createSettings(configFetcher))).resolves.toBe(true);
294
310
 
295
- expect(DataManager.getProtocolV2ResourceSource(pro2Features, EFirmwareType.Universal)).toEqual(
311
+ expect(DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Pro2))).toEqual(
296
312
  resourceSource
297
313
  );
298
314
  expect(
299
- DataManager.getProtocolV2ResourceSource(neoFeatures, EFirmwareType.Universal)
315
+ DataManager.getProtocolV2ResourceSource(getProtocolV2Release(EDeviceType.Neo))
300
316
  ).toBeUndefined();
301
317
  await expect(
302
318
  DataManager.forceReloadData({
@@ -317,11 +333,7 @@ describe('Pro2 resource configuration', () => {
317
333
 
318
334
  test('only blocks resource mutation when the refreshed Pro2 resources are invalid', async () => {
319
335
  const remoteConfig = createRemoteConfig();
320
- (
321
- remoteConfig.pro2 as {
322
- 'firmware-v1': Array<{ resources?: unknown }>;
323
- }
324
- )['firmware-v1'][0].resources = { source: {} };
336
+ (remoteConfig.pro2['firmware-v1']?.[0] as { resources?: unknown }).resources = { source: {} };
325
337
  const settings = createSettings(jest.fn().mockResolvedValue(remoteConfig));
326
338
  DataManager.settings = settings;
327
339
 
@@ -335,11 +347,7 @@ describe('Pro2 resource configuration', () => {
335
347
 
336
348
  test('checks resource configuration errors for the requested device only', async () => {
337
349
  const remoteConfig = createRemoteConfig();
338
- (
339
- remoteConfig.pro2 as {
340
- 'firmware-v1': Array<{ resources?: unknown }>;
341
- }
342
- )['firmware-v1'][0].resources = { source: {} };
350
+ (remoteConfig.pro2['firmware-v1']?.[0] as { resources?: unknown }).resources = { source: {} };
343
351
  const settings = createSettings(jest.fn().mockResolvedValue(remoteConfig));
344
352
  DataManager.settings = settings;
345
353
 
@@ -211,7 +211,7 @@ describe('DeviceUploadWallpaper', () => {
211
211
  const result = await method.run();
212
212
 
213
213
  expect(method.getSupportedProtocols()).toEqual(['V2']);
214
- expect(method.unlockPolicy).toBe('unlock-before-run');
214
+ expect(method.unlockPolicy).toBe('none');
215
215
  expect(typedCall).toHaveBeenNthCalledWith(1, 'FilesystemDirMake', 'Success', {
216
216
  path: 'vol1:/wallpapers',
217
217
  });
@@ -514,6 +514,10 @@ function stubDevice<T extends Record<string, any>>(device: T): T {
514
514
  const d = device as any;
515
515
  d.updateState ??= jest.fn();
516
516
  d.markProtocolV2Reboot ??= jest.fn();
517
+ d.setCancelableAction ??= jest.fn();
518
+ d.clearCancelableAction ??= jest.fn();
519
+ d.toMessageObject ??= jest.fn(() => ({ connectId: d.originalDescriptor?.id }));
520
+ d.createProtocolV2UiPhaseMetadata ??= jest.fn(() => undefined);
517
521
  d.isProtocolV2 ??= () => d.originalDescriptor?.protocolType === 'V2';
518
522
  d.isBootloader ??= () => d.features?.mode === 'bootloader';
519
523
  d.isRomloader ??= () => d.features?.mode === 'romloader';
@@ -4271,7 +4275,7 @@ describe('Protocol V2 firmware update targets', () => {
4271
4275
  });
4272
4276
  (method as any).protocolV2Reboot = jest.fn();
4273
4277
  (method as any).enterProtocolV2BootloaderMode = jest.fn().mockResolvedValue(true);
4274
- method.postTipMessage = jest.fn();
4278
+ method.postMessage = jest.fn();
4275
4279
 
4276
4280
  await method.run();
4277
4281
 
@@ -5254,10 +5258,26 @@ describe('Protocol V2 firmware update targets', () => {
5254
5258
  const targets = [{ target_id: 4, path: 'vol1:firmware.bin' }];
5255
5259
  const typedCall = jest.fn().mockResolvedValue({ type: 'Success', message: {} });
5256
5260
  const call = jest.fn().mockResolvedValue({ type: 'WriteCompleted', message: {} });
5261
+ const cancelDevice = jest.fn().mockResolvedValue(undefined);
5262
+ let cancelableAction: (() => Promise<unknown>) | undefined;
5263
+ const interaction = {
5264
+ interactionId: 'firmware-update',
5265
+ phaseId: 'firmware-update:phase-1',
5266
+ sequence: 1,
5267
+ phase: 'button',
5268
+ transition: 'start',
5269
+ protocol: 'V2',
5270
+ };
5257
5271
 
5258
5272
  (method as any).device = stubDevice({
5259
- getCommands: () => ({ typedCall, call }),
5273
+ getCommands: () => ({ typedCall, call, cancelDevice }),
5274
+ createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(interaction),
5275
+ toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
5276
+ setCancelableAction: jest.fn(action => {
5277
+ cancelableAction = action;
5278
+ }),
5260
5279
  });
5280
+ method.postMessage = jest.fn();
5261
5281
  method.postTipMessage = jest.fn();
5262
5282
  method.postProgressMessage = jest.fn();
5263
5283
 
@@ -5266,14 +5286,32 @@ describe('Protocol V2 firmware update targets', () => {
5266
5286
  ).resolves.toBeUndefined();
5267
5287
 
5268
5288
  expect(typedCall).toHaveBeenCalledWith('DeviceFirmwareUpdateStage', 'Success', { targets });
5289
+ expect(method.postMessage).toHaveBeenCalledWith({
5290
+ event: 'UI_EVENT',
5291
+ type: UI_REQUEST.REQUEST_BUTTON,
5292
+ payload: {
5293
+ device: { connectId: 'pro2' },
5294
+ source: 'method-lifecycle',
5295
+ reason: 'firmware-update',
5296
+ completion: 'operation-completed',
5297
+ deviceOnly: true,
5298
+ operation: 'firmwareUpdateV4',
5299
+ interaction,
5300
+ },
5301
+ });
5269
5302
  expect(call).toHaveBeenCalledWith(
5270
5303
  'DeviceFirmwareUpdateRequest',
5271
5304
  {},
5272
5305
  { returnAfterWrite: true }
5273
5306
  );
5274
5307
  expect(typedCall.mock.invocationCallOrder[0]).toBeLessThan(call.mock.invocationCallOrder[0]);
5275
- expect(method.postTipMessage).toHaveBeenCalledWith('ConfirmOnDevice');
5308
+ expect((method.postMessage as jest.Mock).mock.invocationCallOrder[0]).toBeLessThan(
5309
+ call.mock.invocationCallOrder[0]
5310
+ );
5311
+ expect(method.postTipMessage).not.toHaveBeenCalled();
5276
5312
  expect(method.postProgressMessage).not.toHaveBeenCalled();
5313
+ await cancelableAction?.();
5314
+ expect(cancelDevice).toHaveBeenCalledTimes(1);
5277
5315
  });
5278
5316
 
5279
5317
  test('does not send the install request when Protocol V2 staging fails', async () => {
@@ -5289,6 +5327,7 @@ describe('Protocol V2 firmware update targets', () => {
5289
5327
  (method as any).device = stubDevice({
5290
5328
  getCommands: () => ({ typedCall, call }),
5291
5329
  });
5330
+ method.postMessage = jest.fn();
5292
5331
  method.postTipMessage = jest.fn();
5293
5332
  method.postProgressMessage = jest.fn();
5294
5333
 
@@ -5299,6 +5338,7 @@ describe('Protocol V2 firmware update targets', () => {
5299
5338
  ).rejects.toThrow('stage failed');
5300
5339
 
5301
5340
  expect(call).not.toHaveBeenCalled();
5341
+ expect(method.postMessage).not.toHaveBeenCalled();
5302
5342
  expect(method.postTipMessage).not.toHaveBeenCalled();
5303
5343
  expect(method.postProgressMessage).not.toHaveBeenCalled();
5304
5344
  });
@@ -5315,7 +5355,10 @@ describe('Protocol V2 firmware update targets', () => {
5315
5355
 
5316
5356
  (method as any).device = stubDevice({
5317
5357
  getCommands: () => ({ typedCall, call }),
5358
+ createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
5359
+ toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
5318
5360
  });
5361
+ method.postMessage = jest.fn();
5319
5362
  method.postTipMessage = jest.fn();
5320
5363
  method.postProgressMessage = jest.fn();
5321
5364
 
@@ -5347,16 +5390,14 @@ describe('Protocol V2 firmware update targets', () => {
5347
5390
  type: 'DeviceFirmwareUpdateStatus',
5348
5391
  message: { records: [{ target_id: 4, status: 2 }] },
5349
5392
  });
5350
- const reconnectProtocolV2Device = jest
5351
- .fn()
5352
- .mockRejectedValueOnce(new Error('Device rebooting'))
5353
- .mockResolvedValue(undefined);
5393
+ const reconnectProtocolV2Device = jest.fn();
5394
+ const verifyProtocolV2ReconnectIdentity = jest.fn();
5354
5395
 
5355
5396
  (method as any).device = stubDevice({
5356
5397
  getCommands: () => ({ typedCall }),
5357
5398
  });
5358
5399
  (method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
5359
- (method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
5400
+ (method as any).verifyProtocolV2ReconnectIdentity = verifyProtocolV2ReconnectIdentity;
5360
5401
  method.postProgressMessage = jest.fn();
5361
5402
  method.postTipMessage = jest.fn();
5362
5403
 
@@ -5364,7 +5405,8 @@ describe('Protocol V2 firmware update targets', () => {
5364
5405
  { target_id: 4, path: 'vol0:/application_p1.bin' },
5365
5406
  ]);
5366
5407
 
5367
- expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(2);
5408
+ expect(reconnectProtocolV2Device).not.toHaveBeenCalled();
5409
+ expect(verifyProtocolV2ReconnectIdentity).not.toHaveBeenCalled();
5368
5410
  expect(typedCall.mock.calls.map(call => call[0])).toEqual([
5369
5411
  'DeviceFirmwareUpdateStatusGet',
5370
5412
  'DeviceFirmwareUpdateStatusGet',
@@ -5410,7 +5452,6 @@ describe('Protocol V2 firmware update targets', () => {
5410
5452
  (method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
5411
5453
  (method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
5412
5454
  method.postProgressMessage = jest.fn();
5413
- method.postTipMessage = jest.fn();
5414
5455
 
5415
5456
  try {
5416
5457
  await (method as any).waitForProtocolV2FirmwareUpdateComplete([
@@ -5420,7 +5461,7 @@ describe('Protocol V2 firmware update targets', () => {
5420
5461
  setTimeoutSpy.mockRestore();
5421
5462
  }
5422
5463
 
5423
- expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
5464
+ expect(reconnectProtocolV2Device).not.toHaveBeenCalled();
5424
5465
  expect(typedCall.mock.calls.map(call => call[0])).toEqual([
5425
5466
  'DeviceFirmwareUpdateStatusGet',
5426
5467
  'DeviceFirmwareUpdateStatusGet',
@@ -5465,7 +5506,6 @@ describe('Protocol V2 firmware update targets', () => {
5465
5506
  (method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
5466
5507
  (method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
5467
5508
  method.postProgressMessage = jest.fn();
5468
- method.postTipMessage = jest.fn();
5469
5509
 
5470
5510
  try {
5471
5511
  await (method as any).waitForProtocolV2FirmwareUpdateComplete(
@@ -5477,50 +5517,9 @@ describe('Protocol V2 firmware update targets', () => {
5477
5517
  }
5478
5518
 
5479
5519
  expect(typedCall).toHaveBeenCalledTimes(3);
5480
- expect(method.postTipMessage).toHaveBeenCalledTimes(1);
5481
- expect(method.postTipMessage).toHaveBeenCalledWith('FirmwareUpdating');
5482
5520
  expect(method.postProgressMessage).toHaveBeenCalledWith(100, 'installingFirmware');
5483
5521
  });
5484
5522
 
5485
- test('reports missing current target records as unconfirmed device installation', async () => {
5486
- const method = new FirmwareUpdateV4({
5487
- id: 1,
5488
- payload: {
5489
- method: 'firmwareUpdateV4',
5490
- },
5491
- });
5492
- const typedCall = jest.fn().mockResolvedValue({
5493
- type: 'DeviceFirmwareUpdateStatus',
5494
- message: {
5495
- records: [{ target_id: 7, status: 2 }],
5496
- },
5497
- });
5498
- let now = 0;
5499
- jest.spyOn(Date, 'now').mockImplementation(() => now);
5500
- jest.spyOn(global, 'setTimeout').mockImplementation(((callback: () => void) => {
5501
- now += 31 * 1000;
5502
- callback();
5503
- return 0 as any;
5504
- }) as typeof setTimeout);
5505
-
5506
- (method as any).device = stubDevice({
5507
- getCommands: () => ({ typedCall }),
5508
- });
5509
- (method as any).reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
5510
- (method as any).verifyProtocolV2ReconnectIdentity = jest.fn().mockResolvedValue(undefined);
5511
-
5512
- await expect(
5513
- (method as any).waitForProtocolV2FirmwareUpdateComplete(
5514
- [{ target_id: 4, path: 'vol0:/application_p1.bin' }],
5515
- true
5516
- )
5517
- ).rejects.toMatchObject({
5518
- errorCode: HardwareErrorCode.FirmwareError,
5519
- message: expect.stringContaining('was not confirmed on the device'),
5520
- });
5521
- expect(typedCall).toHaveBeenCalledTimes(2);
5522
- });
5523
-
5524
5523
  test('ignores stale finished records until the current install starts', async () => {
5525
5524
  const method = new FirmwareUpdateV4({
5526
5525
  id: 1,
@@ -5750,7 +5749,9 @@ describe('Protocol V2 firmware update targets', () => {
5750
5749
  'DeviceFirmwareUpdateStatusGet',
5751
5750
  'DeviceFirmwareUpdateStatusGet',
5752
5751
  ]);
5753
- expect((method as any).probeProtocolV2NormalMode).toHaveBeenCalledWith(deviceInfo);
5752
+ expect((method as any).reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
5753
+ expect((method as any).verifyProtocolV2ReconnectIdentity).toHaveBeenCalledTimes(1);
5754
+ expect((method as any).probeProtocolV2NormalMode).not.toHaveBeenCalled();
5754
5755
  });
5755
5756
 
5756
5757
  test('rejects a finished target whose payload version conflicts with the plan', () => {
@@ -5960,7 +5961,7 @@ describe('Protocol V2 firmware update targets', () => {
5960
5961
  ])
5961
5962
  ).resolves.toBeUndefined();
5962
5963
 
5963
- expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
5964
+ expect(reconnectProtocolV2Device).not.toHaveBeenCalled();
5964
5965
  expect(typedCall).toHaveBeenCalledWith(
5965
5966
  'DeviceFirmwareUpdateStatusGet',
5966
5967
  ['DeviceFirmwareUpdateStatus', 'Success'],
@@ -6059,7 +6060,7 @@ describe('Protocol V2 firmware update targets', () => {
6059
6060
  { target_id: 4, path: 'vol0:/application_p1.bin' },
6060
6061
  ])
6061
6062
  ).resolves.toBeUndefined();
6062
- expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(2);
6063
+ expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(1);
6063
6064
  expect(typedCall).toHaveBeenCalledTimes(4);
6064
6065
  });
6065
6066
 
@@ -8470,7 +8471,7 @@ describe('Protocol V2 firmware update targets', () => {
8470
8471
  expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1960, 1]);
8471
8472
  });
8472
8473
 
8473
- test('starts install progress only after Stage and the empty Request are written', async () => {
8474
+ test('keeps the confirmation UI active after Stage and the empty Request are written', async () => {
8474
8475
  const method = new FirmwareUpdateV4({
8475
8476
  id: 1,
8476
8477
  payload: {
@@ -8488,7 +8489,10 @@ describe('Protocol V2 firmware update targets', () => {
8488
8489
 
8489
8490
  (method as any).device = stubDevice({
8490
8491
  getCommands: () => ({ typedCall, call }),
8492
+ createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
8493
+ toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
8491
8494
  });
8495
+ method.postMessage = jest.fn();
8492
8496
  method.postProgressMessage = jest.fn();
8493
8497
  method.postTipMessage = jest.fn();
8494
8498
 
@@ -8514,9 +8518,8 @@ describe('Protocol V2 firmware update targets', () => {
8514
8518
 
8515
8519
  resolveWrite?.({ type: 'WriteCompleted', message: {} });
8516
8520
  await startPromise;
8517
- expect(method.postTipMessage).toHaveBeenCalledWith('ConfirmOnDevice');
8521
+ expect(method.postTipMessage).not.toHaveBeenCalled();
8518
8522
  expect(method.postProgressMessage).not.toHaveBeenCalled();
8519
- expect(method.postTipMessage).toHaveBeenCalledTimes(1);
8520
8523
  });
8521
8524
 
8522
8525
  test('sends an empty Protocol V2 firmware install request without waiting for its response', async () => {
@@ -8534,7 +8537,10 @@ describe('Protocol V2 firmware update targets', () => {
8534
8537
 
8535
8538
  (method as any).device = stubDevice({
8536
8539
  getCommands: () => ({ typedCall, call }),
8540
+ createProtocolV2UiPhaseMetadata: jest.fn().mockReturnValue(undefined),
8541
+ toMessageObject: jest.fn().mockReturnValue({ connectId: 'pro2' }),
8537
8542
  });
8543
+ method.postMessage = jest.fn();
8538
8544
  method.postProgressMessage = jest.fn();
8539
8545
  method.postTipMessage = jest.fn();
8540
8546
 
@@ -8548,7 +8554,7 @@ describe('Protocol V2 firmware update targets', () => {
8548
8554
  {},
8549
8555
  { returnAfterWrite: true }
8550
8556
  );
8551
- expect(method.postTipMessage).toHaveBeenCalledWith('ConfirmOnDevice');
8557
+ expect(method.postTipMessage).not.toHaveBeenCalled();
8552
8558
  });
8553
8559
  });
8554
8560
 
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwarePreparedResourceArchive.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwarePreparedResourceArchive.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAY7F,MAAM,MAAM,6BAA6B,GAAG;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAgCF,eAAO,MAAM,mCAAmC;kBAIhC,0BAA0B;YAChC,sBAAsB,GAAG,SAAS;MACxC,QAAQ,6BAA6B,EAAE,CA4H1C,CAAC"}
1
+ {"version":3,"file":"FirmwarePreparedResourceArchive.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwarePreparedResourceArchive.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AAY7F,MAAM,MAAM,6BAA6B,GAAG;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAmCF,eAAO,MAAM,mCAAmC;kBAIhC,0BAA0B;YAChC,sBAAsB,GAAG,SAAS;MACxC,QAAQ,6BAA6B,EAAE,CAkI1C,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { EDeviceType, EFirmwareType } from '@onekeyfe/hd-shared';
2
- import type { AssetsMap, ConnectSettings, DeviceTypeMap, Features, IDeviceBLEFirmwareStatus, IDeviceFirmwareStatus, ITransportStatus, IVersionArray } from '../types';
2
+ import type { AssetsMap, ConnectSettings, DeviceTypeMap, Features, IDeviceBLEFirmwareStatus, IDeviceFirmwareStatus, IFirmwareReleaseInfo, ITransportStatus, IVersionArray } from '../types';
3
3
  export declare const FIRMWARE_FIELDS: readonly ["firmware", "firmware-v1", "firmware-v2", "firmware-v8", "firmware-btc-v8"];
4
4
  export type IFirmwareField = (typeof FIRMWARE_FIELDS)[number];
5
5
  export type ProtocolV1MessageSchema = 'v1CurrentSchema' | 'v1LegacySchema';
@@ -30,7 +30,7 @@ export default class DataManager {
30
30
  "zh-CN": string;
31
31
  "en-US": string;
32
32
  }[];
33
- static getFirmwareLatestRelease: (features: Features, firmwareType: EFirmwareType) => import("../types").IFirmwareReleaseInfo | undefined;
33
+ static getFirmwareLatestRelease: (features: Features, firmwareType: EFirmwareType) => IFirmwareReleaseInfo | undefined;
34
34
  static getBLEFirmwareStatus: (features: Features) => IDeviceBLEFirmwareStatus;
35
35
  static getBleFirmwareChangelog: (features: Features) => {
36
36
  "zh-CN": string;
@@ -52,7 +52,7 @@ export default class DataManager {
52
52
  requireResources?: boolean;
53
53
  resourceDeviceType?: EDeviceType.Pro2 | EDeviceType.Neo;
54
54
  }): Promise<void>;
55
- static getProtocolV2ResourceSource(features: Features, firmwareType: EFirmwareType): import("../types").IProtocolV2ResourceSource | undefined;
55
+ static getProtocolV2ResourceSource(release: IFirmwareReleaseInfo | undefined): import("../types").IProtocolV2ResourceSource | undefined;
56
56
  static getProtobufMessages(schema?: ProtobufMessageSchema): JSON;
57
57
  static getSettings(key?: undefined): ConnectSettings;
58
58
  static getSettings<T extends keyof ConnectSettings>(key: T): ConnectSettings[T];
@@ -1 +1 @@
1
- {"version":3,"file":"DataManager.d.ts","sourceRoot":"","sources":["../../src/data-manager/DataManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DataManager.d.ts","sourceRoot":"","sources":["../../src/data-manager/DataManager.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -259,7 +259,7 @@ type IFirmwareReleaseInfo = {
259
259
  upgradeType?: 'payload-package-set' | string;
260
260
  components?: Record<string, IProtocolV2FirmwareComponent>;
261
261
  installOrder?: string[];
262
- /** Resource archive released together with this Protocol V2 firmware release. */
262
+ /** Protocol V2 resources matched to this firmware release. */
263
263
  resources?: IProtocolV2Resources;
264
264
  bootloaderChangelog?: {
265
265
  [k in ILocale]: string;
@@ -4735,7 +4735,7 @@ declare class DataManager {
4735
4735
  requireResources?: boolean;
4736
4736
  resourceDeviceType?: EDeviceType.Pro2 | EDeviceType.Neo;
4737
4737
  }): Promise<void>;
4738
- static getProtocolV2ResourceSource(features: Features, firmwareType: EFirmwareType): IProtocolV2ResourceSource | undefined;
4738
+ static getProtocolV2ResourceSource(release: IFirmwareReleaseInfo | undefined): IProtocolV2ResourceSource | undefined;
4739
4739
  static getProtobufMessages(schema?: ProtobufMessageSchema): JSON;
4740
4740
  static getSettings(key?: undefined): ConnectSettings;
4741
4741
  static getSettings<T extends keyof ConnectSettings>(key: T): ConnectSettings[T];
package/dist/index.js CHANGED
@@ -40850,24 +40850,23 @@ class DataManager {
40850
40850
  });
40851
40851
  return enrichedData;
40852
40852
  }
40853
- static enrichProtocolV2FirmwareReleaseInfo(deviceData, deviceName, onResourcesConfigError) {
40853
+ static enrichProtocolV2FirmwareReleaseInfo(deviceData, onResourcesError) {
40854
40854
  const enrichedData = this.enrichFirmwareReleaseInfo(deviceData);
40855
- const _b = enrichedData, releaseScopedData = __rest(_b, ["resources"]);
40856
- const releases = releaseScopedData['firmware-v1'];
40855
+ const releases = enrichedData['firmware-v1'];
40857
40856
  if (!Array.isArray(releases)) {
40858
- return releaseScopedData;
40857
+ return enrichedData;
40859
40858
  }
40860
- return Object.assign(Object.assign({}, releaseScopedData), { 'firmware-v1': releases.map(release => {
40859
+ const latestRelease = findLatestRelease(releases);
40860
+ return Object.assign(Object.assign({}, enrichedData), { 'firmware-v1': releases.map(release => {
40861
40861
  const { resources: rawResources } = release, releaseWithoutResources = __rest(release, ["resources"]);
40862
40862
  try {
40863
40863
  const resources = parseProtocolV2Resources(rawResources);
40864
- return resources
40865
- ? Object.assign(Object.assign({}, releaseWithoutResources), { resources }) : releaseWithoutResources;
40864
+ return Object.assign(Object.assign({}, releaseWithoutResources), (resources ? { resources } : undefined));
40866
40865
  }
40867
40866
  catch (error) {
40868
- const resourcesError = error instanceof Error ? error : new Error(String(error));
40869
- onResourcesConfigError(resourcesError);
40870
- Log$k.warn(`[DataConfig] Ignoring invalid ${deviceName} release resources config:`, error);
40867
+ if (release === latestRelease) {
40868
+ onResourcesError(error instanceof Error ? error : new Error(String(error)));
40869
+ }
40871
40870
  return releaseWithoutResources;
40872
40871
  }
40873
40872
  }) });
@@ -40933,13 +40932,13 @@ class DataManager {
40933
40932
  });
40934
40933
  }
40935
40934
  static applyRemoteConfig(data) {
40936
- const pro2Config = this.enrichProtocolV2FirmwareReleaseInfo(data.pro2, 'Pro2', error => {
40937
- var _b;
40938
- (_b = this.protocolV2ResourcesConfigError) !== null && _b !== void 0 ? _b : (this.protocolV2ResourcesConfigError = error);
40935
+ const pro2Config = this.enrichProtocolV2FirmwareReleaseInfo(data.pro2, error => {
40936
+ this.protocolV2ResourcesConfigError = error;
40937
+ Log$k.warn('[DataConfig] Ignoring invalid Pro2 release resources config:', error);
40939
40938
  });
40940
- const neoConfig = this.enrichProtocolV2FirmwareReleaseInfo(data.neo, 'Neo', error => {
40941
- var _b;
40942
- (_b = this.protocolV2NeoResourcesConfigError) !== null && _b !== void 0 ? _b : (this.protocolV2NeoResourcesConfigError = error);
40939
+ const neoConfig = this.enrichProtocolV2FirmwareReleaseInfo(data.neo, error => {
40940
+ this.protocolV2NeoResourcesConfigError = error;
40941
+ Log$k.warn('[DataConfig] Ignoring invalid Neo release resources config:', error);
40943
40942
  });
40944
40943
  this.deviceMap = {
40945
40944
  [hdShared.EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
@@ -41003,9 +41002,9 @@ class DataManager {
41003
41002
  this.lastCheckTimestamp = getTimeStamp();
41004
41003
  });
41005
41004
  }
41006
- static getProtocolV2ResourceSource(features, firmwareType) {
41007
- var _b, _c;
41008
- return (_c = (_b = this.getFirmwareLatestRelease(features, firmwareType)) === null || _b === void 0 ? void 0 : _b.resources) === null || _c === void 0 ? void 0 : _c.source;
41005
+ static getProtocolV2ResourceSource(release) {
41006
+ var _b;
41007
+ return (_b = release === null || release === void 0 ? void 0 : release.resources) === null || _b === void 0 ? void 0 : _b.source;
41009
41008
  }
41010
41009
  static getProtobufMessages(schema = 'v1CurrentSchema') {
41011
41010
  return this.messages[schema];
@@ -47855,7 +47854,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47855
47854
  release,
47856
47855
  deviceType: state.identity.deviceType,
47857
47856
  });
47858
- const resourceSource = DataManager.getProtocolV2ResourceSource(features, firmwareType);
47857
+ const resourceSource = DataManager.getProtocolV2ResourceSource(release);
47859
47858
  const resourceStatus = 'unknown';
47860
47859
  const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
47861
47860
  ? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
@@ -50251,6 +50250,9 @@ const readVerifiedPreparedResourceArchive = ({ preparedPlan, reader, }) => __awa
50251
50250
  }
50252
50251
  return [];
50253
50252
  }
50253
+ if (!reader) {
50254
+ return resourceArchiveError('Firmware artifact reader is required for prepared resource archives', 'FirmwareArtifactReaderInvalid');
50255
+ }
50254
50256
  if (resourceArtifacts.length !== 1) {
50255
50257
  return resourceArchiveError('Firmware prepared plan must contain exactly one materialized resource ZIP', 'FirmwareArtifactsNotPrepared');
50256
50258
  }
@@ -52945,7 +52947,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52945
52947
  if (deviceType !== hdShared.EDeviceType.Pro2 && deviceType !== hdShared.EDeviceType.Neo) {
52946
52948
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive requires a Pro2 or Neo device');
52947
52949
  }
52948
- const source = DataManager.getProtocolV2ResourceSource(features, firmwareType);
52950
+ const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
52951
+ const source = DataManager.getProtocolV2ResourceSource(release);
52949
52952
  const expectedSha256 = normalizeProtocolV2Hex(source === null || source === void 0 ? void 0 : source.archiveSha256);
52950
52953
  if (!(source === null || source === void 0 ? void 0 : source.archiveUrl) ||
52951
52954
  !Number.isSafeInteger(source.archiveSize) ||
@@ -53276,6 +53279,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53276
53279
  });
53277
53280
  }
53278
53281
  executeProtocolV2TransferPhase({ installSources, resourceSources, }) {
53282
+ var _a;
53279
53283
  return __awaiter(this, void 0, void 0, function* () {
53280
53284
  let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
53281
53285
  const resourcesToSync = [];
@@ -53330,9 +53334,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53330
53334
  target_id: item.targetId,
53331
53335
  path: item.path,
53332
53336
  }));
53333
- yield this.protocolV2StartFirmwareUpdate({ targets });
53334
- yield hdShared.wait(PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY);
53335
- yield this.waitForProtocolV2FirmwareUpdateComplete(targets, true);
53337
+ try {
53338
+ yield this.protocolV2StartFirmwareUpdate({ targets });
53339
+ yield hdShared.wait(PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY);
53340
+ yield this.waitForProtocolV2FirmwareUpdateComplete(targets, true);
53341
+ }
53342
+ finally {
53343
+ (_a = this.device) === null || _a === void 0 ? void 0 : _a.clearCancelableAction();
53344
+ }
53336
53345
  });
53337
53346
  }
53338
53347
  protocolV2SourceUpdateProcess({ source, filePath, processedSize, totalSize, }) {
@@ -53506,14 +53515,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53506
53515
  const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
53507
53516
  const startTime = Date.now();
53508
53517
  let lastError;
53509
- let shouldReconnect = true;
53518
+ let shouldReconnect = false;
53510
53519
  let deviceInfo;
53511
53520
  let missingTargetStatusSince;
53512
53521
  let missingTargetStatusKey;
53513
53522
  let normalModeWithoutInstallEvidenceSince;
53514
53523
  let installEvidenceObserved = false;
53515
53524
  let currentInstallStatusObserved = false;
53516
- let firmwareUpdatingTipPosted = false;
53517
53525
  const resetMissingTargetStatusGrace = () => {
53518
53526
  missingTargetStatusSince = undefined;
53519
53527
  missingTargetStatusKey = undefined;
@@ -53543,18 +53551,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53543
53551
  const statusTargets = statusResponse.type === 'DeviceFirmwareUpdateStatus'
53544
53552
  ? ((_a = statusResponse.message.records) !== null && _a !== void 0 ? _a : [])
53545
53553
  : [];
53546
- const hasCurrentInstallStatus = statusTargets.some(target => {
53554
+ const hasInProgressTarget = statusTargets.some(target => {
53547
53555
  const targetId = normalizeProtocolV2TargetId(target.target_id);
53548
53556
  return (targetId !== undefined &&
53549
53557
  expectedTargetIds.has(targetId) &&
53550
53558
  isProtocolV2TargetStatusInProgress(target.status));
53551
53559
  });
53552
- if (hasCurrentInstallStatus) {
53560
+ if (hasInProgressTarget) {
53553
53561
  currentInstallStatusObserved = true;
53554
- if (!firmwareUpdatingTipPosted) {
53555
- this.postTipMessage(exports.FirmwareUpdateTipMessage.FirmwareUpdating);
53556
- firmwareUpdatingTipPosted = true;
53557
- }
53558
53562
  }
53559
53563
  const hasMatchingTargetStatus = statusTargets.some(target => {
53560
53564
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -53607,9 +53611,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53607
53611
  }
53608
53612
  else if (now - missingTargetStatusSince >=
53609
53613
  PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT) {
53610
- if (requireCurrentInstallStatus && !currentInstallStatusObserved) {
53611
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 firmware installation was not confirmed on the device');
53612
- }
53613
53614
  const reportedTargetIds = statusTargets
53614
53615
  .map(target => normalizeProtocolV2TargetId(target.target_id))
53615
53616
  .filter((targetId) => targetId !== undefined);
@@ -53889,8 +53890,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53889
53890
  this.protocolV2LastRuntimeProbeFeatures = undefined;
53890
53891
  const commands = this.device.getCommands();
53891
53892
  yield commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
53893
+ this.device.setCancelableAction(() => commands.cancelDevice());
53894
+ const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
53895
+ this.postMessage(createUiMessage(UI_REQUEST.REQUEST_BUTTON, Object.assign({ device: this.device.toMessageObject(), source: 'method-lifecycle', reason: 'firmware-update', completion: 'operation-completed', deviceOnly: true, operation: this.name }, (interaction ? { interaction } : {}))));
53892
53896
  yield commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
53893
- this.postTipMessage(exports.FirmwareUpdateTipMessage.ConfirmOnDevice);
53894
53897
  });
53895
53898
  }
53896
53899
  protocolV2Reboot(rebootType) {
@@ -54392,7 +54395,7 @@ class DeviceUploadWallpaper extends BaseMethod {
54392
54395
  });
54393
54396
  this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
54394
54397
  this.params = { jpegBase64, fileName, chunkSize };
54395
- this.unlockPolicy = 'unlock-before-run';
54398
+ this.unlockPolicy = 'none';
54396
54399
  this.skipForceUpdateCheck = true;
54397
54400
  this.useDevicePassphraseState = false;
54398
54401
  }
@@ -54540,7 +54543,7 @@ class DeviceUploadNft extends BaseMethod {
54540
54543
  paceMs,
54541
54544
  timeoutMs,
54542
54545
  };
54543
- this.unlockPolicy = 'unlock-before-run';
54546
+ this.unlockPolicy = 'none';
54544
54547
  this.skipForceUpdateCheck = true;
54545
54548
  this.useDevicePassphraseState = false;
54546
54549
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.128",
3
+ "version": "1.2.0-alpha.129",
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.128",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.128",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.129",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.129",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "buffer": "^6.0.3",
@@ -46,5 +46,5 @@
46
46
  "@types/w3c-web-usb": "^1.0.10",
47
47
  "@types/web-bluetooth": "^0.0.21"
48
48
  },
49
- "gitHead": "121180c237cddef9279041969d0d2394fac75a7a"
49
+ "gitHead": "d996758fef2d61a868b1989efcce1f04c8ef5e22"
50
50
  }
@@ -411,7 +411,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
411
411
  release,
412
412
  deviceType: state.identity.deviceType,
413
413
  });
414
- const resourceSource = DataManager.getProtocolV2ResourceSource(features, firmwareType);
414
+ const resourceSource = DataManager.getProtocolV2ResourceSource(release);
415
415
  const resourceStatus = 'unknown' as const;
416
416
  const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
417
417
  ? plan.components.flatMap(component =>
@@ -9,7 +9,7 @@ import {
9
9
  } from '@onekeyfe/hd-transport';
10
10
  import { sha256 } from '@noble/hashes/sha256';
11
11
 
12
- import { FirmwareUpdateTipMessage, UI_REQUEST } from '../events/ui-request';
12
+ import { FirmwareUpdateTipMessage, UI_REQUEST, createUiMessage } from '../events/ui-request';
13
13
  import { validateParams } from './helpers/paramsValidator';
14
14
  import {
15
15
  LoggerNames,
@@ -71,6 +71,7 @@ import type {
71
71
  IProtocolV2FirmwareComponent,
72
72
  IProtocolV2ResourceManifestFile,
73
73
  IVersionArray,
74
+ KnownDevice,
74
75
  } from '../types';
75
76
  import type { FirmwareByteSource } from './firmware/FirmwareArtifactSource';
76
77
  import type {
@@ -1891,7 +1892,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1891
1892
  'Protocol V2 resource archive requires a Pro2 or Neo device'
1892
1893
  );
1893
1894
  }
1894
- const source = DataManager.getProtocolV2ResourceSource(features, firmwareType);
1895
+ const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
1896
+ const source = DataManager.getProtocolV2ResourceSource(release);
1895
1897
  const expectedSha256 = normalizeProtocolV2Hex(source?.archiveSha256);
1896
1898
  if (
1897
1899
  !source?.archiveUrl ||
@@ -2379,9 +2381,13 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2379
2381
  target_id: item.targetId,
2380
2382
  path: item.path,
2381
2383
  }));
2382
- await this.protocolV2StartFirmwareUpdate({ targets });
2383
- await wait(PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY);
2384
- await this.waitForProtocolV2FirmwareUpdateComplete(targets, true);
2384
+ try {
2385
+ await this.protocolV2StartFirmwareUpdate({ targets });
2386
+ await wait(PROTOCOL_V2_INSTALL_STATUS_INITIAL_DELAY);
2387
+ await this.waitForProtocolV2FirmwareUpdateComplete(targets, true);
2388
+ } finally {
2389
+ this.device?.clearCancelableAction();
2390
+ }
2385
2391
  }
2386
2392
 
2387
2393
  private async protocolV2SourceUpdateProcess({
@@ -2641,14 +2647,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2641
2647
  const expectedPaths = new Map(targets.map(target => [target.target_id, target.path]));
2642
2648
  const startTime = Date.now();
2643
2649
  let lastError: unknown;
2644
- let shouldReconnect = true;
2650
+ // DeviceFirmwareUpdateRequest leaves the current loader link usable for status polling.
2651
+ // Reconnecting here probes DeviceInfo, which loaders reject while installation is active.
2652
+ let shouldReconnect = false;
2645
2653
  let deviceInfo: ProtocolV2DeviceInfo | undefined;
2646
2654
  let missingTargetStatusSince: number | undefined;
2647
2655
  let missingTargetStatusKey: string | undefined;
2648
2656
  let normalModeWithoutInstallEvidenceSince: number | undefined;
2649
2657
  let installEvidenceObserved = false;
2650
2658
  let currentInstallStatusObserved = false;
2651
- let firmwareUpdatingTipPosted = false;
2652
2659
  const resetMissingTargetStatusGrace = () => {
2653
2660
  missingTargetStatusSince = undefined;
2654
2661
  missingTargetStatusKey = undefined;
@@ -2689,7 +2696,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2689
2696
  statusResponse.type === 'DeviceFirmwareUpdateStatus'
2690
2697
  ? ((statusResponse.message.records ?? []) as ProtocolV2FirmwareUpdateStatusTarget[])
2691
2698
  : [];
2692
- const hasCurrentInstallStatus = statusTargets.some(target => {
2699
+ const hasInProgressTarget = statusTargets.some(target => {
2693
2700
  const targetId = normalizeProtocolV2TargetId(target.target_id);
2694
2701
  return (
2695
2702
  targetId !== undefined &&
@@ -2697,12 +2704,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2697
2704
  isProtocolV2TargetStatusInProgress(target.status)
2698
2705
  );
2699
2706
  });
2700
- if (hasCurrentInstallStatus) {
2707
+ if (hasInProgressTarget) {
2701
2708
  currentInstallStatusObserved = true;
2702
- if (!firmwareUpdatingTipPosted) {
2703
- this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
2704
- firmwareUpdatingTipPosted = true;
2705
- }
2706
2709
  }
2707
2710
  const hasMatchingTargetStatus = statusTargets.some(target => {
2708
2711
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -2776,12 +2779,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2776
2779
  now - missingTargetStatusSince >=
2777
2780
  PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
2778
2781
  ) {
2779
- if (requireCurrentInstallStatus && !currentInstallStatusObserved) {
2780
- throw ERRORS.TypedError(
2781
- HardwareErrorCode.FirmwareError,
2782
- 'Protocol V2 firmware installation was not confirmed on the device'
2783
- );
2784
- }
2785
2782
  const reportedTargetIds = statusTargets
2786
2783
  .map(target => normalizeProtocolV2TargetId(target.target_id))
2787
2784
  .filter((targetId): targetId is number => targetId !== undefined);
@@ -3152,8 +3149,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
3152
3149
  this.protocolV2LastRuntimeProbeFeatures = undefined;
3153
3150
  const commands = this.device.getCommands();
3154
3151
  await commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
3152
+ this.device.setCancelableAction(() => commands.cancelDevice());
3153
+ const interaction = this.device.createProtocolV2UiPhaseMetadata('button', 'start');
3154
+ this.postMessage(
3155
+ createUiMessage(UI_REQUEST.REQUEST_BUTTON, {
3156
+ device: this.device.toMessageObject() as KnownDevice,
3157
+ source: 'method-lifecycle',
3158
+ reason: 'firmware-update',
3159
+ completion: 'operation-completed',
3160
+ deviceOnly: true,
3161
+ operation: this.name,
3162
+ ...(interaction ? { interaction } : {}),
3163
+ })
3164
+ );
3155
3165
  await commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
3156
- this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
3157
3166
  }
3158
3167
 
3159
3168
  private async protocolV2Reboot(rebootType: DeviceRebootType) {
@@ -26,7 +26,10 @@ export type VerifiedPreparedResourceEntry = {
26
26
 
27
27
  const resourceArchiveError = (
28
28
  message: string,
29
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' | 'FirmwareArtifactReceiptMismatch'
29
+ firmwareUpdateCode:
30
+ | 'FirmwareArtifactsNotPrepared'
31
+ | 'FirmwareArtifactReceiptMismatch'
32
+ | 'FirmwareArtifactReaderInvalid'
30
33
  ): never => {
31
34
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, message, { firmwareUpdateCode });
32
35
  };
@@ -73,6 +76,12 @@ export const readVerifiedPreparedResourceArchive = async ({
73
76
  }
74
77
  return [];
75
78
  }
79
+ if (!reader) {
80
+ return resourceArchiveError(
81
+ 'Firmware artifact reader is required for prepared resource archives',
82
+ 'FirmwareArtifactReaderInvalid'
83
+ );
84
+ }
76
85
  if (resourceArtifacts.length !== 1) {
77
86
  return resourceArchiveError(
78
87
  'Firmware prepared plan must contain exactly one materialized resource ZIP',
@@ -129,7 +129,7 @@ export default class DeviceUploadNft extends BaseMethod<DeviceUploadNftParams> {
129
129
  paceMs,
130
130
  timeoutMs,
131
131
  };
132
- this.unlockPolicy = 'unlock-before-run';
132
+ this.unlockPolicy = 'none';
133
133
  this.skipForceUpdateCheck = true;
134
134
  this.useDevicePassphraseState = false;
135
135
  }
@@ -76,7 +76,7 @@ export default class DeviceUploadWallpaper extends BaseMethod<DeviceUploadWallpa
76
76
  });
77
77
  this.path = `${WALLPAPER_DIRECTORY}/${normalizeFileName(fileName, this.encoded.data)}`;
78
78
  this.params = { jpegBase64, fileName, chunkSize };
79
- this.unlockPolicy = 'unlock-before-run';
79
+ this.unlockPolicy = 'none';
80
80
  this.skipForceUpdateCheck = true;
81
81
  this.useDevicePassphraseState = false;
82
82
  }
@@ -26,6 +26,7 @@ import type {
26
26
  Features,
27
27
  IDeviceBLEFirmwareStatus,
28
28
  IDeviceFirmwareStatus,
29
+ IFirmwareReleaseInfo,
29
30
  ITransportStatus,
30
31
  IVersionArray,
31
32
  RemoteConfigResponse,
@@ -408,35 +409,29 @@ export default class DataManager {
408
409
 
409
410
  private static enrichProtocolV2FirmwareReleaseInfo(
410
411
  deviceData: DeviceTypeMap[keyof DeviceTypeMap] | undefined,
411
- deviceName: 'Pro2' | 'Neo',
412
- onResourcesConfigError: (error: Error) => void
412
+ onResourcesError: (error: Error) => void
413
413
  ): NonNullable<DeviceTypeMap[keyof DeviceTypeMap]> {
414
414
  const enrichedData = this.enrichFirmwareReleaseInfo(deviceData);
415
- const { resources: _legacyDeviceResources, ...releaseScopedData } =
416
- enrichedData as typeof enrichedData & {
417
- resources?: unknown;
418
- };
419
- const releases = releaseScopedData['firmware-v1'];
415
+ const releases = enrichedData['firmware-v1'];
420
416
  if (!Array.isArray(releases)) {
421
- return releaseScopedData;
417
+ return enrichedData;
422
418
  }
419
+ const latestRelease = findLatestRelease(releases);
423
420
 
424
421
  return {
425
- ...releaseScopedData,
422
+ ...enrichedData,
426
423
  'firmware-v1': releases.map(release => {
427
424
  const { resources: rawResources, ...releaseWithoutResources } = release;
428
425
  try {
429
426
  const resources = parseProtocolV2Resources(rawResources);
430
- return resources
431
- ? {
432
- ...releaseWithoutResources,
433
- resources,
434
- }
435
- : releaseWithoutResources;
427
+ return {
428
+ ...releaseWithoutResources,
429
+ ...(resources ? { resources } : undefined),
430
+ };
436
431
  } catch (error) {
437
- const resourcesError = error instanceof Error ? error : new Error(String(error));
438
- onResourcesConfigError(resourcesError);
439
- Log.warn(`[DataConfig] Ignoring invalid ${deviceName} release resources config:`, error);
432
+ if (release === latestRelease) {
433
+ onResourcesError(error instanceof Error ? error : new Error(String(error)));
434
+ }
440
435
  return releaseWithoutResources;
441
436
  }
442
437
  }),
@@ -507,11 +502,15 @@ export default class DataManager {
507
502
  }
508
503
 
509
504
  private static applyRemoteConfig(data: RemoteConfigResponse) {
510
- const pro2Config = this.enrichProtocolV2FirmwareReleaseInfo(data.pro2, 'Pro2', error => {
511
- this.protocolV2ResourcesConfigError ??= error;
505
+ const pro2Config = this.enrichProtocolV2FirmwareReleaseInfo(data.pro2, error => {
506
+ // Firmware resource metadata is not required for base communication. If the
507
+ // The selected release is incomplete, so disable its resource update only.
508
+ this.protocolV2ResourcesConfigError = error;
509
+ Log.warn('[DataConfig] Ignoring invalid Pro2 release resources config:', error);
512
510
  });
513
- const neoConfig = this.enrichProtocolV2FirmwareReleaseInfo(data.neo, 'Neo', error => {
514
- this.protocolV2NeoResourcesConfigError ??= error;
511
+ const neoConfig = this.enrichProtocolV2FirmwareReleaseInfo(data.neo, error => {
512
+ this.protocolV2NeoResourcesConfigError = error;
513
+ Log.warn('[DataConfig] Ignoring invalid Neo release resources config:', error);
515
514
  });
516
515
  this.deviceMap = {
517
516
  [EDeviceType.Classic]: this.enrichFirmwareReleaseInfo(data.classic),
@@ -599,8 +598,8 @@ export default class DataManager {
599
598
  this.lastCheckTimestamp = getTimeStamp();
600
599
  }
601
600
 
602
- static getProtocolV2ResourceSource(features: Features, firmwareType: EFirmwareType) {
603
- return this.getFirmwareLatestRelease(features, firmwareType)?.resources?.source;
601
+ static getProtocolV2ResourceSource(release: IFirmwareReleaseInfo | undefined) {
602
+ return release?.resources?.source;
604
603
  }
605
604
 
606
605
  static getProtobufMessages(schema: ProtobufMessageSchema = 'v1CurrentSchema'): JSON {
@@ -116,7 +116,7 @@ export type IFirmwareReleaseInfo = {
116
116
  upgradeType?: 'payload-package-set' | string;
117
117
  components?: Record<string, IProtocolV2FirmwareComponent>;
118
118
  installOrder?: string[];
119
- /** Resource archive released together with this Protocol V2 firmware release. */
119
+ /** Protocol V2 resources matched to this firmware release. */
120
120
  resources?: IProtocolV2Resources;
121
121
  bootloaderChangelog?: {
122
122
  [k in ILocale]: string;