@onekeyfe/hd-core 1.2.0-alpha.27 → 1.2.0-alpha.29

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.
@@ -1,4 +1,4 @@
1
- import { ERRORS, EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import CheckAllFirmwareRelease from '../../src/api/CheckAllFirmwareRelease';
4
4
  import { buildFirmwareUpdatePlan } from '../../src/api/firmware/FirmwareUpdatePlan';
@@ -15,6 +15,7 @@ jest.mock('../../src/data/config', () => ({
15
15
 
16
16
  jest.mock('../../src/api/firmware/FirmwareUpdatePlan', () => ({
17
17
  buildFirmwareUpdatePlan: jest.fn(),
18
+ validateFirmwareUpdatePlanForceTargets: jest.fn(value => value ?? []),
18
19
  }));
19
20
 
20
21
  jest.mock('../../src/api/firmware/releaseHelper', () => ({
@@ -147,6 +148,21 @@ describe('CheckAllFirmwareRelease', () => {
147
148
  );
148
149
  });
149
150
 
151
+ test('does not hide a Plan failure for an explicitly forced target', async () => {
152
+ const planError = ERRORS.TypedError(
153
+ HardwareErrorCode.RuntimeError,
154
+ 'Forced firmware target is unavailable',
155
+ {
156
+ firmwareUpdateCode: 'FirmwarePlanInvalid',
157
+ }
158
+ );
159
+ mockBuildFirmwareUpdatePlan.mockImplementation(() => {
160
+ throw planError;
161
+ });
162
+
163
+ await expect(createMethodWithForceTargets().run()).rejects.toBe(planError);
164
+ });
165
+
150
166
  test('does not hide unexpected Plan builder failures', async () => {
151
167
  const unexpectedError = new Error('unexpected builder failure');
152
168
  mockBuildFirmwareUpdatePlan.mockImplementation(() => {
@@ -0,0 +1,27 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import { normalizeFirmwarePreparationError } from '../../src/api/firmware/FirmwarePreparationError';
4
+
5
+ describe('normalizeFirmwarePreparationError', () => {
6
+ test('preserves structured firmware invariant errors', () => {
7
+ const error = ERRORS.TypedError(
8
+ HardwareErrorCode.RuntimeError,
9
+ 'Firmware must be prepared by the external firmware host',
10
+ {
11
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
12
+ artifactName: 'firmware',
13
+ }
14
+ );
15
+
16
+ expect(normalizeFirmwarePreparationError(error)).toBe(error);
17
+ });
18
+
19
+ test('wraps ordinary preparation failures as firmware download errors', () => {
20
+ const error = normalizeFirmwarePreparationError(new Error('request failed'));
21
+
22
+ expect(error).toMatchObject({
23
+ errorCode: HardwareErrorCode.FirmwareUpdateDownloadFailed,
24
+ message: 'request failed',
25
+ });
26
+ });
27
+ });
@@ -25,6 +25,63 @@ const noUpdate = {
25
25
  release: undefined,
26
26
  };
27
27
 
28
+ const expectFirmwarePlanInvalid = (build: () => unknown, expectedMessage?: string) => {
29
+ let thrown: unknown;
30
+ try {
31
+ build();
32
+ } catch (error) {
33
+ thrown = error;
34
+ }
35
+ expect(thrown).toMatchObject({
36
+ params: {
37
+ firmwareUpdateCode: 'FirmwarePlanInvalid',
38
+ },
39
+ });
40
+ if (expectedMessage) {
41
+ expect(thrown).toBeInstanceOf(Error);
42
+ expect((thrown as Error).message).toContain(expectedMessage);
43
+ }
44
+ };
45
+
46
+ type BuildPlanInput = Parameters<typeof buildFirmwareUpdatePlan>[0];
47
+
48
+ const createLegacyForceInput = (
49
+ forceUpdateTargets: unknown,
50
+ release: Record<string, unknown> = {
51
+ url: 'https://firmware.onekey.so/pro/firmware.bin',
52
+ version: [4, 21, 0],
53
+ }
54
+ ): BuildPlanInput => ({
55
+ features: createFeatures({
56
+ deviceType: EDeviceType.Pro,
57
+ firmwareVersion: '4.21.0',
58
+ bootloaderVersion: '2.8.4',
59
+ }),
60
+ firmwareType: EFirmwareType.Universal,
61
+ platform: 'desktop',
62
+ firmware: { status: 'valid', release },
63
+ ble: noUpdate,
64
+ bootloader: noUpdate,
65
+ forceUpdateTargets: forceUpdateTargets as BuildPlanInput['forceUpdateTargets'],
66
+ });
67
+
68
+ const createProtocolV2ForceInput = (
69
+ forceUpdateTargets: unknown,
70
+ release: Record<string, unknown>
71
+ ): BuildPlanInput => ({
72
+ features: createFeatures({
73
+ deviceType: EDeviceType.Pro2,
74
+ firmwareVersion: '1.0.0',
75
+ bootloaderVersion: '1.0.0',
76
+ }),
77
+ firmwareType: EFirmwareType.Universal,
78
+ platform: 'desktop',
79
+ firmware: { status: 'valid', release },
80
+ ble: noUpdate,
81
+ bootloader: noUpdate,
82
+ forceUpdateTargets: forceUpdateTargets as BuildPlanInput['forceUpdateTargets'],
83
+ });
84
+
28
85
  describe('buildFirmwareUpdatePlan', () => {
29
86
  test('selects all legacy artifacts before execution and chooses the desktop full resource', () => {
30
87
  const plan = buildFirmwareUpdatePlan({
@@ -192,6 +249,118 @@ describe('buildFirmwareUpdatePlan', () => {
192
249
  expect(plan.targetsToUpdate).toEqual(['firmware']);
193
250
  });
194
251
 
252
+ test.each([
253
+ {
254
+ label: 'a non-array value',
255
+ forceUpdateTargets: 'firmware',
256
+ },
257
+ {
258
+ label: 'an unknown target',
259
+ forceUpdateTargets: ['firmware', 'unknown'],
260
+ },
261
+ {
262
+ label: 'a duplicate target',
263
+ forceUpdateTargets: ['firmware', 'firmware'],
264
+ },
265
+ ])('rejects $label in forceUpdateTargets', ({ forceUpdateTargets }) => {
266
+ expectFirmwarePlanInvalid(() =>
267
+ buildFirmwareUpdatePlan(createLegacyForceInput(forceUpdateTargets))
268
+ );
269
+ });
270
+
271
+ test('rejects an explicitly forced legacy resource without a resource artifact', () => {
272
+ expectFirmwarePlanInvalid(() => buildFirmwareUpdatePlan(createLegacyForceInput(['resource'])));
273
+ });
274
+
275
+ test.each(['ble', 'bootloader'] as const)(
276
+ 'rejects the unsupported Pro2 %s force target',
277
+ forceTarget => {
278
+ expectFirmwarePlanInvalid(
279
+ () =>
280
+ buildFirmwareUpdatePlan(
281
+ createProtocolV2ForceInput([forceTarget], {
282
+ components: {
283
+ applicationP1: {
284
+ target: 'APPLICATION_P1',
285
+ url: 'https://firmware.onekey.so/pro2/application-p1.bin',
286
+ },
287
+ },
288
+ })
289
+ ),
290
+ 'does not support forced'
291
+ );
292
+ }
293
+ );
294
+
295
+ test.each([
296
+ {
297
+ forceTarget: 'firmware' as const,
298
+ release: {
299
+ components: {},
300
+ resourceBundles: [
301
+ {
302
+ name: 'images',
303
+ url: 'https://firmware.onekey.so/pro2/images.okpkg',
304
+ },
305
+ ],
306
+ },
307
+ },
308
+ {
309
+ forceTarget: 'resource' as const,
310
+ release: {
311
+ components: {
312
+ applicationP1: {
313
+ target: 'APPLICATION_P1',
314
+ url: 'https://firmware.onekey.so/pro2/application-p1.bin',
315
+ },
316
+ },
317
+ },
318
+ },
319
+ ])(
320
+ 'rejects a Pro2 $forceTarget force target not represented by an artifact',
321
+ ({ forceTarget, release }) => {
322
+ expectFirmwarePlanInvalid(() =>
323
+ buildFirmwareUpdatePlan(createProtocolV2ForceInput([forceTarget], release))
324
+ );
325
+ }
326
+ );
327
+
328
+ test.each([
329
+ {
330
+ forceTarget: 'firmware' as const,
331
+ expectedArtifactIds: ['component:app_v1'],
332
+ expectedTargets: ['app_v1'],
333
+ },
334
+ {
335
+ forceTarget: 'resource' as const,
336
+ expectedArtifactIds: ['resourceBundle:images'],
337
+ expectedTargets: ['resource'],
338
+ },
339
+ ])(
340
+ 'limits a Pro2 $forceTarget force to the selected artifact role',
341
+ ({ forceTarget, expectedArtifactIds, expectedTargets }) => {
342
+ const plan = buildFirmwareUpdatePlan(
343
+ createProtocolV2ForceInput([forceTarget], {
344
+ components: {
345
+ applicationP1: {
346
+ target: 'APPLICATION_P1',
347
+ url: 'https://firmware.onekey.so/pro2/application-p1.bin',
348
+ },
349
+ },
350
+ resourceBundles: [
351
+ {
352
+ name: 'images',
353
+ url: 'https://firmware.onekey.so/pro2/images.okpkg',
354
+ },
355
+ ],
356
+ })
357
+ );
358
+
359
+ expect(plan.artifacts.map(artifact => artifact.artifactId)).toEqual(expectedArtifactIds);
360
+ expect(plan.targetsToUpdate).toEqual(expectedTargets);
361
+ }
362
+ );
363
+
195
364
  test('rejects a prepared native plan without a stable device identity', () => {
196
365
  const features = createFeatures({
197
366
  deviceType: EDeviceType.Classic1s,
@@ -1,4 +1,4 @@
1
- import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
4
4
  import { getBinary } from '../../src/api/firmware/getBinary';
@@ -181,6 +181,25 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
181
181
  expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
182
182
  });
183
183
 
184
+ it('preserves structured preparation errors before any firmware mutation', async () => {
185
+ const preparationError = ERRORS.TypedError(
186
+ HardwareErrorCode.RuntimeError,
187
+ 'Firmware must be prepared by the external firmware host',
188
+ {
189
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
190
+ artifactName: 'firmware',
191
+ }
192
+ );
193
+ mockGetBinary.mockRejectedValue(preparationError);
194
+ const { method, typedCall, acquire } = createMethod();
195
+
196
+ await expect(method.run()).rejects.toBe(preparationError);
197
+
198
+ expectNoFirmwareMutationCalls(typedCall);
199
+ expect(acquire).not.toHaveBeenCalled();
200
+ expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
201
+ });
202
+
184
203
  it.each([
185
204
  {
186
205
  mode: 'firmware release.url',
@@ -184,7 +184,6 @@ describe('openWalletSession', () => {
184
184
  walletType: 'standard',
185
185
  deviceId: 'device-1',
186
186
  passphraseState: null,
187
- sessionId: 'main-wallet-session',
188
187
  resumed: false,
189
188
  });
190
189
  expect(method.payload.useEmptyPassphrase).toBe(true);
@@ -261,7 +260,6 @@ describe('openWalletSession', () => {
261
260
  walletType: 'hidden',
262
261
  deviceId: 'device-1',
263
262
  passphraseState: 'hidden-state-after-unlock',
264
- sessionId: 'hidden-session-after-unlock',
265
263
  resumed: false,
266
264
  });
267
265
  expect(device.unlockDevice).toHaveBeenCalledWith(DeviceSessionPinType.Main);
@@ -295,7 +293,6 @@ describe('openWalletSession', () => {
295
293
  walletType: 'hidden',
296
294
  deviceId: 'device-1',
297
295
  passphraseState: 'new-hidden-state',
298
- sessionId: 'new-hidden-session',
299
296
  resumed: false,
300
297
  });
301
298
  expect(typedCall).toHaveBeenCalledWith('ProtocolInfoRequest', 'ProtocolInfo', {
@@ -369,7 +366,6 @@ describe('openWalletSession', () => {
369
366
  walletType: 'hidden',
370
367
  deviceId: 'device-1',
371
368
  passphraseState: 'hidden-state',
372
- sessionId: 'renewed-session',
373
369
  resumed: true,
374
370
  });
375
371
  expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
@@ -567,7 +563,7 @@ describe('openWalletSession', () => {
567
563
  expect(device.clearInternalState).toHaveBeenCalled();
568
564
  });
569
565
 
570
- test('selects a hidden wallet and returns the CLI compatibility session', async () => {
566
+ test('selects a hidden wallet without exposing the internal device session', async () => {
571
567
  const typedCall = jest
572
568
  .fn()
573
569
  .mockResolvedValueOnce({ message: { version: 2 } })
@@ -592,7 +588,6 @@ describe('openWalletSession', () => {
592
588
  walletType: 'hidden',
593
589
  deviceId: 'device-1',
594
590
  passphraseState: 'hidden-state',
595
- sessionId: 'hidden-session',
596
591
  resumed: false,
597
592
  });
598
593
  expect(typedCall).toHaveBeenCalledWith('DeviceSessionAskPassphrase', 'Success', {});
@@ -759,7 +754,6 @@ describe('openWalletSession', () => {
759
754
  walletType: 'hidden',
760
755
  deviceId: 'device-1',
761
756
  passphraseState: 'hidden-state',
762
- sessionId: 'renewed-session',
763
757
  resumed: true,
764
758
  });
765
759
  expect(typedCall).toHaveBeenCalledWith('DeviceSessionGet', 'DeviceSession', {
@@ -1 +1 @@
1
- {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiB1C,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,sCAAsC,CAAC;AAK9C,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,IAAI;IAME,GAAG;CAgFV"}
1
+ {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAoB1C,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,sCAAsC,CAAC;AAK9C,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,IAAI;IAME,GAAG;CAkFV"}
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAsB1C,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,KAAK,MAAM,GAAG;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAC7C,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAkFF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI;IA6EJ,cAAc,YAAa,MAAM,UAS/B;YAEY,qCAAqC;IAkBnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YAkFvC,4BAA4B;IAuB1C,qBAAqB;IAUrB,uBAAuB,CAAC,UAAU,EAAE,MAAM;IAc1C,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,YAAY,EAAE,aAAa;IAwBtF,GAAG;CA4QV"}
1
+ {"version":3,"file":"FirmwareUpdateV2.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV2.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EAEb,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAuB1C,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,UAAU,CAAC;AAEtD,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AAE1F,KAAK,MAAM,GAAG;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAC7C,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B,CAAC;AAkFF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI;IA6EJ,cAAc,YAAa,MAAM,UAS/B;YAEY,qCAAqC;IAkBnD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YAkFvC,4BAA4B;IAuB1C,qBAAqB;IAUrB,uBAAuB,CAAC,UAAU,EAAE,MAAM;IAc1C,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,YAAY,EAAE,aAAa;IAwBtF,GAAG;CAyQV"}
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV3.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV3.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAY/E,OAAO,KAAK,EAEV,sBAAsB,EACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,qBAAqB,CAAC;AAMnE,eAAO,MAAM,gCAAgC,UAAU,CAAC;AAaxD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe,CAA4B;IAEnD,IAAI;IAmFE,GAAG;;;;;YAQK,aAAa;IA6D3B,OAAO,CAAC,wBAAwB;YAiBlB,kBAAkB;YAelB,oBAAoB;IAKlC,OAAO,CAAC,wBAAwB;YAgBlB,oBAAoB;YA2DpB,uBAAuB;YAuBvB,4BAA4B;YA+E5B,aAAa;IAwN3B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,sCAAsC;IAexC,sBAAsB,CAAC,OAAO,EAAE,MAAM;CAuE7C"}
1
+ {"version":3,"file":"FirmwareUpdateV3.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV3.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAY/E,OAAO,KAAK,EAEV,sBAAsB,EACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,qBAAqB,CAAC;AAMnE,eAAO,MAAM,gCAAgC,UAAU,CAAC;AAaxD,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,OAAO,CAAC,gBAAgB,CAAS;IAEjC,OAAO,CAAC,eAAe,CAA4B;IAEnD,IAAI;IAmFE,GAAG;;;;;YAQK,aAAa;IA6D3B,OAAO,CAAC,wBAAwB;YAiBlB,kBAAkB;YAelB,oBAAoB;IAKlC,OAAO,CAAC,wBAAwB;YAgBlB,oBAAoB;YA2DpB,uBAAuB;YAuBvB,4BAA4B;YA+E5B,aAAa;IAwN3B,OAAO,CAAC,yBAAyB;IAajC,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAmB7B,OAAO,CAAC,sCAAsC;IAexC,sBAAsB,CAAC,OAAO,EAAE,MAAM;CAuE7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAkB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA4VrC,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,SAc5B,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,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;YAsEb,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;YAO5B,iCAAiC;YAOjC,iCAAiC;YAgBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA6C9B,iCAAiC;YAmBjC,+BAA+B;IA+D7C,OAAO,CAAC,gCAAgC;YAyC1B,oCAAoC;YAkCpC,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAO5B,6BAA6B;YA0BrB,+BAA+B;IA4C7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA6CvB,8BAA8B;YA2D9B,6BAA6B;IA0D3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;YA+FtB,uCAAuC;YA4GvC,gCAAgC;YAShC,8BAA8B;YAsB9B,mCAAmC;YAWnC,qCAAqC;YA2CrC,yBAAyB;YAiDzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAI5B,cAAc;YA+Bd,6BAA6B;YAU7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
1
+ {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAkB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA4VrC,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,SAc5B,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,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;YAsEb,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;YAO5B,iCAAiC;YAOjC,iCAAiC;YAgBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;IAkBhC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA6C9B,iCAAiC;YAmBjC,+BAA+B;IA+D7C,OAAO,CAAC,gCAAgC;YAyC1B,oCAAoC;YAkCpC,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAO5B,6BAA6B;YA0BrB,+BAA+B;IA4C7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA6CvB,8BAA8B;YA2D9B,6BAA6B;IA0D3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;YA+FtB,uCAAuC;YA4GvC,gCAAgC;YAShC,8BAA8B;YAsB9B,mCAAmC;YAWnC,qCAAqC;YA2CrC,yBAAyB;YAiDzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAI5B,cAAc;YA+Bd,6BAA6B;YAU7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"OpenWalletSession.d.ts","sourceRoot":"","sources":["../../src/api/OpenWalletSession.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,gCAAgC,CAAC;AAsExC,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,UAAU,CAAC,uBAAuB,CAAC;IAChF,qBAAqB;IAIrB,IAAI;IAOE,GAAG,IAAI,OAAO,CAAC,wBAAwB,CAAC;CAqH/C"}
1
+ {"version":3,"file":"OpenWalletSession.d.ts","sourceRoot":"","sources":["../../src/api/OpenWalletSession.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,gCAAgC,CAAC;AA+DxC,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,UAAU,CAAC,uBAAuB,CAAC;IAChF,qBAAqB;IAIrB,IAAI;IAOE,GAAG,IAAI,OAAO,CAAC,wBAAwB,CAAC;CAmH/C"}
@@ -0,0 +1,3 @@
1
+ import { HardwareError } from '@onekeyfe/hd-shared';
2
+ export declare const normalizeFirmwarePreparationError: (error: unknown) => HardwareError;
3
+ //# sourceMappingURL=FirmwarePreparationError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FirmwarePreparationError.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwarePreparationError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AAE/E,eAAO,MAAM,iCAAiC,UAAW,OAAO,kBAS/D,CAAC"}
@@ -8,6 +8,7 @@ type ReleaseSelection = {
8
8
  release?: unknown;
9
9
  };
10
10
  export declare const digestFirmwareUpdateContract: (value: unknown) => string;
11
+ export declare const validateFirmwareUpdatePlanForceTargets: (value: unknown) => FirmwareUpdatePlanForceTarget[];
11
12
  export declare const FIRMWARE_UPDATE_PLAN_TARGETS: Set<FirmwareUpdatePlanTarget>;
12
13
  export declare const FIRMWARE_UPDATE_PLAN_ROLES: Set<string>;
13
14
  export declare const assertFirmwareUpdatePlan: (value: unknown) => FirmwareUpdatePlan;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAS5F,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAyBjF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;AAgCJ,eAAO,MAAM,4BAA4B,+BAavC,CAAC;AAEH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAYH,eAAO,MAAM,wBAAwB,UAAW,OAAO,KAAG,kBAoHzD,CAAC;AA2JF,eAAO,MAAM,uBAAuB;cASxB,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;cACtB,gBAAgB;SACrB,gBAAgB;;;MAGnB,kBA+HH,CAAC"}
1
+ {"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAS5F,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAyBjF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;AAkBJ,eAAO,MAAM,sCAAsC,UAC1C,OAAO,KACb,6BAA6B,EAa/B,CAAC;AAuBF,eAAO,MAAM,4BAA4B,+BAavC,CAAC;AAEH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAYH,eAAO,MAAM,wBAAwB,UAAW,OAAO,KAAG,kBAoHzD,CAAC;AA4NF,eAAO,MAAM,uBAAuB;cASxB,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;cACtB,gBAAgB;SACrB,gBAAgB;;;MAGnB,kBAiJH,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1423,8 +1423,6 @@ type OpenWalletSessionPayloadBase = {
1423
1423
  protocol: 'V1' | 'V2';
1424
1424
  deviceId: string;
1425
1425
  resumed: boolean;
1426
- /** Forwarded only when the firmware response contains a wallet session id. */
1427
- sessionId?: string;
1428
1426
  };
1429
1427
  type OpenWalletSessionPayload = OpenWalletSessionPayloadBase & ({
1430
1428
  walletType: 'standard';
package/dist/index.js CHANGED
@@ -564,6 +564,24 @@ const planError = (message) => {
564
564
  firmwareUpdateCode: 'FirmwarePlanInvalid',
565
565
  });
566
566
  };
567
+ const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set([
568
+ 'firmware',
569
+ 'ble',
570
+ 'bootloader',
571
+ 'resource',
572
+ ]);
573
+ const validateFirmwareUpdatePlanForceTargets = (value) => {
574
+ if (value === undefined) {
575
+ return [];
576
+ }
577
+ if (!Array.isArray(value) ||
578
+ value.length > FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.size ||
579
+ value.some(target => !FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.has(target)) ||
580
+ new Set(value).size !== value.length) {
581
+ return planError('Firmware update force targets are invalid');
582
+ }
583
+ return [...value];
584
+ };
567
585
  const assertExactKeys = (value, required, optional = []) => {
568
586
  const allowed = new Set([...required, ...optional]);
569
587
  if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
@@ -736,24 +754,23 @@ const getExecutor = (features) => {
736
754
  }
737
755
  return 'v2';
738
756
  };
739
- const buildProtocolV2Artifacts = (release) => {
757
+ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, } = {}) => {
740
758
  var _a;
741
759
  const components = asRecord(release.components);
742
- if (!components) {
760
+ if (includeComponents && !components) {
743
761
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 release has no component set', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
744
762
  }
745
763
  const installOrder = Array.isArray(release.installOrder)
746
764
  ? release.installOrder.filter((key) => typeof key === 'string')
747
765
  : [];
748
- const componentKeys = [
749
- ...installOrder,
750
- ...Object.keys(components).filter(key => !installOrder.includes(key)),
751
- ];
766
+ const componentKeys = includeComponents && components
767
+ ? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
768
+ : [];
752
769
  const artifacts = [];
753
770
  const targets = [];
754
771
  const componentTargets = new Set();
755
772
  for (const key of componentKeys) {
756
- const component = asRecord(components[key]);
773
+ const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
757
774
  const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
758
775
  if (targetName === 'ROMLOADER') {
759
776
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
@@ -772,7 +789,7 @@ const buildProtocolV2Artifacts = (release) => {
772
789
  })), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
773
790
  targets.push(target);
774
791
  }
775
- const bundles = Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
792
+ const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
776
793
  const resourceBundleNames = new Set();
777
794
  for (const value of bundles) {
778
795
  const bundle = asRecord(value);
@@ -794,17 +811,51 @@ const buildProtocolV2Artifacts = (release) => {
794
811
  }
795
812
  return { artifacts, targets: [...new Set(targets)] };
796
813
  };
814
+ const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
815
+ if (executor !== 'v4') {
816
+ return artifacts.some(artifact => artifact.target === forcedTarget && targetsToUpdate.includes(forcedTarget));
817
+ }
818
+ if (forcedTarget === 'firmware') {
819
+ return artifacts.some(artifact => artifact.role === 'component' && targetsToUpdate.includes(artifact.target));
820
+ }
821
+ if (forcedTarget === 'resource') {
822
+ return artifacts.some(artifact => artifact.role === 'resourceBundle' &&
823
+ artifact.target === 'resource' &&
824
+ targetsToUpdate.includes('resource'));
825
+ }
826
+ return false;
827
+ };
828
+ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, targetsToUpdate, }) => {
829
+ for (const forcedTarget of forcedTargets) {
830
+ if (!isForcedTargetRepresented({
831
+ executor,
832
+ forcedTarget,
833
+ artifacts,
834
+ targetsToUpdate,
835
+ })) {
836
+ planError(`Forced firmware update target ${forcedTarget} is not represented by the plan`);
837
+ }
838
+ }
839
+ };
797
840
  const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
798
841
  var _a, _b, _c, _d, _e, _f, _g;
799
842
  const executor = getExecutor(features);
800
843
  let artifacts = [];
801
844
  let targetsToUpdate = [];
802
845
  const firmwareRelease = asRelease(firmware);
803
- const forcedTargets = new Set(forceUpdateTargets);
846
+ const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
847
+ const forcedTargets = new Set(validatedForceTargets);
804
848
  const shouldUpdateFirmware = isUpgrade(firmware) || forcedTargets.has('firmware');
805
849
  const shouldUpdateResource = isUpgrade(firmware) || forcedTargets.has('resource');
850
+ if (executor === 'v4' &&
851
+ validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
852
+ planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
853
+ }
806
854
  if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
807
- const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {});
855
+ const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
856
+ includeComponents: shouldUpdateFirmware,
857
+ includeResources: shouldUpdateResource,
858
+ });
808
859
  artifacts = protocolV2.artifacts;
809
860
  targetsToUpdate = protocolV2.targets;
810
861
  }
@@ -862,6 +913,12 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
862
913
  }
863
914
  targetsToUpdate = [...new Set(artifacts.map(artifact => artifact.target))];
864
915
  }
916
+ assertForcedTargetsRepresented({
917
+ executor,
918
+ forcedTargets: validatedForceTargets,
919
+ artifacts,
920
+ targetsToUpdate,
921
+ });
865
922
  const deviceIdentity = getDeviceUUID(features);
866
923
  if (artifacts.length > 0 &&
867
924
  (platform === 'native' || platform === 'desktop') &&
@@ -878,7 +935,7 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
878
935
  artifacts,
879
936
  targetsToUpdate,
880
937
  };
881
- return Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) });
938
+ return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
882
939
  };
883
940
 
884
941
  const preparedPlanError = (message) => {
@@ -45796,12 +45853,13 @@ const wasResumed = (session) => !!session &&
45796
45853
  typeof session === 'object' &&
45797
45854
  'resumed' in session &&
45798
45855
  session.resumed === true;
45799
- const forwardSessionId = (session) => session.newSession ? { sessionId: session.newSession } : {};
45800
45856
  const requireHiddenWalletResponse = (session) => {
45801
45857
  if (!session.passphraseState) {
45802
45858
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, 'Hidden wallet response is missing passphraseState');
45803
45859
  }
45804
- return Object.assign({ passphraseState: session.passphraseState }, forwardSessionId(session));
45860
+ return {
45861
+ passphraseState: session.passphraseState,
45862
+ };
45805
45863
  };
45806
45864
  const normalizeParams = (payload) => {
45807
45865
  if (payload.mode === undefined) {
@@ -45873,7 +45931,13 @@ class OpenWalletSession extends BaseMethod {
45873
45931
  this.device.clearInternalState();
45874
45932
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceCheckUnlockTypeError);
45875
45933
  }
45876
- return Object.assign(Object.assign({ protocol, walletType: 'standard', deviceId, passphraseState: null }, forwardSessionId(session)), { resumed: wasResumed(session) });
45934
+ return {
45935
+ protocol,
45936
+ walletType: 'standard',
45937
+ deviceId,
45938
+ passphraseState: null,
45939
+ resumed: wasResumed(session),
45940
+ };
45877
45941
  }
45878
45942
  if (this.params.mode === 'resume-hidden') {
45879
45943
  if (isProtocolV2) {
@@ -45925,7 +45989,7 @@ class OpenWalletSession extends BaseMethod {
45925
45989
  resumed: wasResumed(session),
45926
45990
  };
45927
45991
  return this.device.getCurrentPassphraseProtection() === false
45928
- ? Object.assign(Object.assign(Object.assign({}, responseBase), { walletType: 'standard', passphraseState: null }), forwardSessionId(session)) : Object.assign(Object.assign(Object.assign({}, responseBase), { walletType: 'hidden' }), requireHiddenWalletResponse(session));
45992
+ ? Object.assign(Object.assign({}, responseBase), { walletType: 'standard', passphraseState: null }) : Object.assign(Object.assign(Object.assign({}, responseBase), { walletType: 'hidden' }), requireHiddenWalletResponse(session));
45929
45993
  });
45930
45994
  }
45931
45995
  }
@@ -46172,6 +46236,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
46172
46236
  return __awaiter(this, void 0, void 0, function* () {
46173
46237
  const { features } = this.device;
46174
46238
  const { checkBridgeRelease, firmwareType: firmwareTypeParams, platform, forceUpdateTargets, } = this.payload;
46239
+ const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
46175
46240
  if (!features) {
46176
46241
  return Promise.resolve(null);
46177
46242
  }
@@ -46205,11 +46270,12 @@ class CheckAllFirmwareRelease extends BaseMethod {
46205
46270
  firmware: firmwareRelease,
46206
46271
  ble: bleFirmwareReleaseInfo,
46207
46272
  bootloader: bootloaderRelease,
46208
- forceUpdateTargets,
46273
+ forceUpdateTargets: validatedForceUpdateTargets,
46209
46274
  });
46210
46275
  }
46211
46276
  catch (error) {
46212
- if (!(error instanceof hdShared.HardwareError) ||
46277
+ if (validatedForceUpdateTargets.length > 0 ||
46278
+ !(error instanceof hdShared.HardwareError) ||
46213
46279
  ((_c = error.params) === null || _c === void 0 ? void 0 : _c.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
46214
46280
  throw error;
46215
46281
  }
@@ -48369,6 +48435,14 @@ class FirmwareUpdate extends BaseMethod {
48369
48435
  }
48370
48436
  }
48371
48437
 
48438
+ const normalizeFirmwarePreparationError = (error) => {
48439
+ var _a;
48440
+ if (error instanceof hdShared.HardwareError && ((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode)) {
48441
+ return error;
48442
+ }
48443
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, error instanceof Error ? error.message : String(error));
48444
+ };
48445
+
48372
48446
  const Log$7 = getLogger(exports.LoggerNames.Method);
48373
48447
  const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
48374
48448
  connectTimeoutMs: 60000,
@@ -48651,7 +48725,6 @@ class FirmwareUpdateV2 extends BaseMethod {
48651
48725
  let preparedSource;
48652
48726
  try {
48653
48727
  const acquireFirmwareSource = () => __awaiter(this, void 0, void 0, function* () {
48654
- var _k;
48655
48728
  try {
48656
48729
  if (preparedSource) {
48657
48730
  return preparedSource;
@@ -48715,7 +48788,7 @@ class FirmwareUpdateV2 extends BaseMethod {
48715
48788
  return source;
48716
48789
  }
48717
48790
  catch (err) {
48718
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, (_k = err.message) !== null && _k !== void 0 ? _k : err);
48791
+ throw normalizeFirmwarePreparationError(err);
48719
48792
  }
48720
48793
  });
48721
48794
  if (!device.isBootloader() && features) {
@@ -48916,7 +48989,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
48916
48989
  });
48917
48990
  }
48918
48991
  runProtocolV1() {
48919
- var _a, _b, _c;
48992
+ var _a, _b;
48920
48993
  return __awaiter(this, void 0, void 0, function* () {
48921
48994
  const { device } = this;
48922
48995
  const { features } = device;
@@ -48950,7 +49023,7 @@ class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod {
48950
49023
  }
48951
49024
  catch (err) {
48952
49025
  yield this.closeArtifactSources();
48953
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, (_c = err.message) !== null && _c !== void 0 ? _c : err);
49026
+ throw normalizeFirmwarePreparationError(err);
48954
49027
  }
48955
49028
  if (!bootloaderSource && fwSources.length === 0) {
48956
49029
  yield this.closeArtifactSources();
@@ -49874,7 +49947,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
49874
49947
  });
49875
49948
  }
49876
49949
  runProtocolV2() {
49877
- var _a, _b, _c;
49950
+ var _a, _b;
49878
49951
  return __awaiter(this, void 0, void 0, function* () {
49879
49952
  yield this.captureProtocolV2PhysicalIdentity();
49880
49953
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
@@ -49912,7 +49985,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
49912
49985
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
49913
49986
  }
49914
49987
  catch (err) {
49915
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, (_c = err.message) !== null && _c !== void 0 ? _c : err);
49988
+ throw normalizeFirmwarePreparationError(err);
49916
49989
  }
49917
49990
  if (!bootloaderBinary && fwBinaryMap.length === 0 && !(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
49918
49991
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
@@ -16,7 +16,6 @@ type OpenWalletSessionPayloadBase = {
16
16
  protocol: 'V1' | 'V2';
17
17
  deviceId: string;
18
18
  resumed: boolean;
19
- sessionId?: string;
20
19
  };
21
20
  export type OpenWalletSessionPayload = OpenWalletSessionPayloadBase & ({
22
21
  walletType: 'standard';
@@ -1 +1 @@
1
- {"version":3,"file":"openWalletSession.d.ts","sourceRoot":"","sources":["../../../src/types/api/openWalletSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN,KAAK,4BAA4B,GAAG;IAClC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IAEjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GACjE,CACI;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,IAAI,CAAC;CACvB,GACD;IACE,UAAU,EAAE,QAAQ,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CACJ,CAAC;AAMJ,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GAAG,uBAAuB,GAC7C,QAAQ,CAAC,wBAAwB,CAAC,CAAC"}
1
+ {"version":3,"file":"openWalletSession.d.ts","sourceRoot":"","sources":["../../../src/types/api/openWalletSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAExD,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;CACzB,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN,KAAK,4BAA4B,GAAG;IAClC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GACjE,CACI;IACE,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,IAAI,CAAC;CACvB,GACD;IACE,UAAU,EAAE,QAAQ,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,CACJ,CAAC;AAMJ,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,GAAG,uBAAuB,GAC7C,QAAQ,CAAC,wBAAwB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.27",
3
+ "version": "1.2.0-alpha.29",
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.27",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.27",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.29",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.29",
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": "ea3c188364a6fb968875484805085e4466d3ef99"
47
+ "gitHead": "4a4019e439cc472f89fd15ab47e84ef0ed43166a"
48
48
  }
@@ -7,7 +7,10 @@ import {
7
7
  getBootloaderReleaseInfo,
8
8
  getFirmwareReleaseInfo,
9
9
  } from './firmware/releaseHelper';
10
- import { buildFirmwareUpdatePlan } from './firmware/FirmwareUpdatePlan';
10
+ import {
11
+ buildFirmwareUpdatePlan,
12
+ validateFirmwareUpdatePlanForceTargets,
13
+ } from './firmware/FirmwareUpdatePlan';
11
14
  import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
12
15
  import {
13
16
  LoggerNames,
@@ -40,6 +43,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
40
43
  platform,
41
44
  forceUpdateTargets,
42
45
  } = this.payload as CheckAllFirmwareReleaseParams;
46
+ const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
43
47
 
44
48
  if (!features) {
45
49
  return Promise.resolve(null);
@@ -79,10 +83,11 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
79
83
  firmware: firmwareRelease,
80
84
  ble: bleFirmwareReleaseInfo,
81
85
  bootloader: bootloaderRelease,
82
- forceUpdateTargets,
86
+ forceUpdateTargets: validatedForceUpdateTargets,
83
87
  });
84
88
  } catch (error) {
85
89
  if (
90
+ validatedForceUpdateTargets.length > 0 ||
86
91
  !(error instanceof HardwareError) ||
87
92
  error.params?.firmwareUpdateCode !== 'FirmwarePlanInvalid'
88
93
  ) {
@@ -14,6 +14,7 @@ import { BaseMethod } from './BaseMethod';
14
14
  import { validateParams } from './helpers/paramsValidator';
15
15
  import { DevicePool } from '../device/DevicePool';
16
16
  import { getBinary, getInfo, getSysResourceBinary } from './firmware/getBinary';
17
+ import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
17
18
  import {
18
19
  updateResources,
19
20
  updateResourcesFromSources,
@@ -27,8 +28,8 @@ import { DEVICE } from '../events';
27
28
  import { type FirmwareByteSource, openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
28
29
  import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
29
30
  import {
30
- assertFirmwareUpdatePreparedPlanDeviceIdentity,
31
31
  assertFirmwareUpdatePreparedPlanBinding,
32
+ assertFirmwareUpdatePreparedPlanDeviceIdentity,
32
33
  getFirmwareUpdateResourceName,
33
34
  } from './firmware/FirmwareUpdatePreparedPlan';
34
35
 
@@ -503,10 +504,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
503
504
  this.postTipMessage('DownloadFirmwareSuccess');
504
505
  return source;
505
506
  } catch (err) {
506
- throw ERRORS.TypedError(
507
- HardwareErrorCode.FirmwareUpdateDownloadFailed,
508
- err.message ?? err
509
- );
507
+ throw normalizeFirmwarePreparationError(err);
510
508
  }
511
509
  };
512
510
 
@@ -13,6 +13,7 @@ import {
13
13
  getLogger,
14
14
  } from '../utils';
15
15
  import { getBinary, getSysResourceBinary } from './firmware/getBinary';
16
+ import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
16
17
  import { DataManager } from '../data-manager';
17
18
  import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
18
19
  import { DevicePool } from '../device/DevicePool';
@@ -21,8 +22,8 @@ import { buildProtocolV1FeaturesPayload } from '../deviceProfile';
21
22
  import { openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
22
23
  import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
23
24
  import {
24
- assertFirmwareUpdatePreparedPlanDeviceIdentity,
25
25
  assertFirmwareUpdatePreparedPlanBinding,
26
+ assertFirmwareUpdatePreparedPlanDeviceIdentity,
26
27
  getFirmwareUpdateResourceName,
27
28
  } from './firmware/FirmwareUpdatePreparedPlan';
28
29
 
@@ -184,7 +185,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
184
185
  this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
185
186
  } catch (err) {
186
187
  await this.closeArtifactSources();
187
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
188
+ throw normalizeFirmwarePreparationError(err);
188
189
  }
189
190
 
190
191
  if (!bootloaderSource && fwSources.length === 0) {
@@ -18,6 +18,7 @@ import {
18
18
  getLogger,
19
19
  } from '../utils';
20
20
  import { getSysResourceBinary } from './firmware/getBinary';
21
+ import { normalizeFirmwarePreparationError } from './firmware/FirmwarePreparationError';
21
22
  import { DataManager } from '../data-manager';
22
23
  import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
23
24
  import { DevicePool } from '../device/DevicePool';
@@ -625,7 +626,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
625
626
  : undefined;
626
627
  this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
627
628
  } catch (err) {
628
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
629
+ throw normalizeFirmwarePreparationError(err);
629
630
  }
630
631
 
631
632
  if (!bootloaderBinary && fwBinaryMap.length === 0 && !resourceBundles?.length) {
@@ -27,13 +27,7 @@ const wasResumed = (session: unknown) =>
27
27
  'resumed' in session &&
28
28
  (session as { resumed?: unknown }).resumed === true;
29
29
 
30
- const forwardSessionId = (session: { newSession?: string }) =>
31
- session.newSession ? { sessionId: session.newSession } : {};
32
-
33
- const requireHiddenWalletResponse = (session: {
34
- passphraseState?: string;
35
- newSession?: string;
36
- }) => {
30
+ const requireHiddenWalletResponse = (session: { passphraseState?: string }) => {
37
31
  if (!session.passphraseState) {
38
32
  throw ERRORS.TypedError(
39
33
  HardwareErrorCode.DeviceInitializeFailed,
@@ -42,7 +36,6 @@ const requireHiddenWalletResponse = (session: {
42
36
  }
43
37
  return {
44
38
  passphraseState: session.passphraseState,
45
- ...forwardSessionId(session),
46
39
  };
47
40
  };
48
41
 
@@ -132,7 +125,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
132
125
  walletType: 'standard',
133
126
  deviceId,
134
127
  passphraseState: null,
135
- ...forwardSessionId(session),
136
128
  resumed: wasResumed(session),
137
129
  };
138
130
  }
@@ -200,7 +192,6 @@ export default class OpenWalletSession extends BaseMethod<OpenWalletSessionParam
200
192
  ...responseBase,
201
193
  walletType: 'standard',
202
194
  passphraseState: null,
203
- ...forwardSessionId(session),
204
195
  }
205
196
  : {
206
197
  ...responseBase,
@@ -0,0 +1,12 @@
1
+ import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ export const normalizeFirmwarePreparationError = (error: unknown) => {
4
+ if (error instanceof HardwareError && error.params?.firmwareUpdateCode) {
5
+ return error;
6
+ }
7
+
8
+ return ERRORS.TypedError(
9
+ HardwareErrorCode.FirmwareUpdateDownloadFailed,
10
+ error instanceof Error ? error.message : String(error)
11
+ );
12
+ };
@@ -166,6 +166,30 @@ const planError = (message: string): never => {
166
166
  });
167
167
  };
168
168
 
169
+ const FIRMWARE_UPDATE_PLAN_FORCE_TARGETS = new Set<FirmwareUpdatePlanForceTarget>([
170
+ 'firmware',
171
+ 'ble',
172
+ 'bootloader',
173
+ 'resource',
174
+ ]);
175
+
176
+ export const validateFirmwareUpdatePlanForceTargets = (
177
+ value: unknown
178
+ ): FirmwareUpdatePlanForceTarget[] => {
179
+ if (value === undefined) {
180
+ return [];
181
+ }
182
+ if (
183
+ !Array.isArray(value) ||
184
+ value.length > FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.size ||
185
+ value.some(target => !FIRMWARE_UPDATE_PLAN_FORCE_TARGETS.has(target)) ||
186
+ new Set(value).size !== value.length
187
+ ) {
188
+ return planError('Firmware update force targets are invalid');
189
+ }
190
+ return [...value] as FirmwareUpdatePlanForceTarget[];
191
+ };
192
+
169
193
  const assertExactKeys = (
170
194
  value: Record<string, unknown>,
171
195
  required: readonly string[],
@@ -388,13 +412,20 @@ const getExecutor = (features: Features): FirmwareUpdatePlan['executor'] => {
388
412
  };
389
413
 
390
414
  const buildProtocolV2Artifacts = (
391
- release: ReleaseRecord
415
+ release: ReleaseRecord,
416
+ {
417
+ includeComponents = true,
418
+ includeResources = true,
419
+ }: {
420
+ includeComponents?: boolean;
421
+ includeResources?: boolean;
422
+ } = {}
392
423
  ): {
393
424
  artifacts: FirmwareUpdatePlanArtifact[];
394
425
  targets: FirmwareUpdatePlanTarget[];
395
426
  } => {
396
427
  const components = asRecord(release.components);
397
- if (!components) {
428
+ if (includeComponents && !components) {
398
429
  throw ERRORS.TypedError(
399
430
  HardwareErrorCode.RuntimeError,
400
431
  'Protocol V2 release has no component set',
@@ -404,15 +435,15 @@ const buildProtocolV2Artifacts = (
404
435
  const installOrder = Array.isArray(release.installOrder)
405
436
  ? release.installOrder.filter((key): key is string => typeof key === 'string')
406
437
  : [];
407
- const componentKeys = [
408
- ...installOrder,
409
- ...Object.keys(components).filter(key => !installOrder.includes(key)),
410
- ];
438
+ const componentKeys =
439
+ includeComponents && components
440
+ ? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
441
+ : [];
411
442
  const artifacts: FirmwareUpdatePlanArtifact[] = [];
412
443
  const targets: FirmwareUpdatePlanTarget[] = [];
413
444
  const componentTargets = new Set<FirmwareUpdatePlanTarget>();
414
445
  for (const key of componentKeys) {
415
- const component = asRecord(components[key]);
446
+ const component = asRecord(components?.[key]);
416
447
  const targetName = asString(component?.target)?.toUpperCase();
417
448
  if (targetName === 'ROMLOADER') {
418
449
  throw ERRORS.TypedError(
@@ -453,7 +484,8 @@ const buildProtocolV2Artifacts = (
453
484
  targets.push(target);
454
485
  }
455
486
 
456
- const bundles = Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
487
+ const bundles =
488
+ includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
457
489
  const resourceBundleNames = new Set<string>();
458
490
  for (const value of bundles) {
459
491
  const bundle = asRecord(value);
@@ -492,6 +524,63 @@ const buildProtocolV2Artifacts = (
492
524
  return { artifacts, targets: [...new Set(targets)] };
493
525
  };
494
526
 
527
+ const isForcedTargetRepresented = ({
528
+ executor,
529
+ forcedTarget,
530
+ artifacts,
531
+ targetsToUpdate,
532
+ }: {
533
+ executor: FirmwareUpdatePlan['executor'];
534
+ forcedTarget: FirmwareUpdatePlanForceTarget;
535
+ artifacts: readonly FirmwareUpdatePlanArtifact[];
536
+ targetsToUpdate: readonly FirmwareUpdatePlanTarget[];
537
+ }): boolean => {
538
+ if (executor !== 'v4') {
539
+ return artifacts.some(
540
+ artifact => artifact.target === forcedTarget && targetsToUpdate.includes(forcedTarget)
541
+ );
542
+ }
543
+ if (forcedTarget === 'firmware') {
544
+ return artifacts.some(
545
+ artifact => artifact.role === 'component' && targetsToUpdate.includes(artifact.target)
546
+ );
547
+ }
548
+ if (forcedTarget === 'resource') {
549
+ return artifacts.some(
550
+ artifact =>
551
+ artifact.role === 'resourceBundle' &&
552
+ artifact.target === 'resource' &&
553
+ targetsToUpdate.includes('resource')
554
+ );
555
+ }
556
+ return false;
557
+ };
558
+
559
+ const assertForcedTargetsRepresented = ({
560
+ executor,
561
+ forcedTargets,
562
+ artifacts,
563
+ targetsToUpdate,
564
+ }: {
565
+ executor: FirmwareUpdatePlan['executor'];
566
+ forcedTargets: readonly FirmwareUpdatePlanForceTarget[];
567
+ artifacts: readonly FirmwareUpdatePlanArtifact[];
568
+ targetsToUpdate: readonly FirmwareUpdatePlanTarget[];
569
+ }) => {
570
+ for (const forcedTarget of forcedTargets) {
571
+ if (
572
+ !isForcedTargetRepresented({
573
+ executor,
574
+ forcedTarget,
575
+ artifacts,
576
+ targetsToUpdate,
577
+ })
578
+ ) {
579
+ planError(`Forced firmware update target ${forcedTarget} is not represented by the plan`);
580
+ }
581
+ }
582
+ };
583
+
495
584
  export const buildFirmwareUpdatePlan = ({
496
585
  features,
497
586
  firmwareType,
@@ -513,12 +602,23 @@ export const buildFirmwareUpdatePlan = ({
513
602
  let artifacts: FirmwareUpdatePlanArtifact[] = [];
514
603
  let targetsToUpdate: FirmwareUpdatePlanTarget[] = [];
515
604
  const firmwareRelease = asRelease(firmware);
516
- const forcedTargets = new Set(forceUpdateTargets);
605
+ const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
606
+ const forcedTargets = new Set(validatedForceTargets);
517
607
  const shouldUpdateFirmware = isUpgrade(firmware) || forcedTargets.has('firmware');
518
608
  const shouldUpdateResource = isUpgrade(firmware) || forcedTargets.has('resource');
519
609
 
610
+ if (
611
+ executor === 'v4' &&
612
+ validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')
613
+ ) {
614
+ planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
615
+ }
616
+
520
617
  if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
521
- const protocolV2 = buildProtocolV2Artifacts(firmwareRelease ?? {});
618
+ const protocolV2 = buildProtocolV2Artifacts(firmwareRelease ?? {}, {
619
+ includeComponents: shouldUpdateFirmware,
620
+ includeResources: shouldUpdateResource,
621
+ });
522
622
  artifacts = protocolV2.artifacts;
523
623
  targetsToUpdate = protocolV2.targets;
524
624
  } else {
@@ -609,6 +709,13 @@ export const buildFirmwareUpdatePlan = ({
609
709
  targetsToUpdate = [...new Set(artifacts.map(artifact => artifact.target))];
610
710
  }
611
711
 
712
+ assertForcedTargetsRepresented({
713
+ executor,
714
+ forcedTargets: validatedForceTargets,
715
+ artifacts,
716
+ targetsToUpdate,
717
+ });
718
+
612
719
  const deviceIdentity = getDeviceUUID(features);
613
720
  if (
614
721
  artifacts.length > 0 &&
@@ -631,8 +738,8 @@ export const buildFirmwareUpdatePlan = ({
631
738
  artifacts,
632
739
  targetsToUpdate,
633
740
  };
634
- return {
741
+ return assertFirmwareUpdatePlan({
635
742
  ...planWithoutDigest,
636
743
  planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
637
- };
744
+ });
638
745
  };
@@ -21,8 +21,6 @@ type OpenWalletSessionPayloadBase = {
21
21
  protocol: 'V1' | 'V2';
22
22
  deviceId: string;
23
23
  resumed: boolean;
24
- /** Forwarded only when the firmware response contains a wallet session id. */
25
- sessionId?: string;
26
24
  };
27
25
 
28
26
  export type OpenWalletSessionPayload = OpenWalletSessionPayloadBase &