@onekeyfe/hd-core 1.2.0-alpha.97 → 1.2.0-alpha.98

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.
Files changed (98) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +404 -84
  2. package/__tests__/check-firmware-release-protocol-v2.test.ts +199 -0
  3. package/__tests__/firmware-memory-host.test.ts +112 -0
  4. package/__tests__/firmware-update/device-update-bootloader.test.ts +13 -2
  5. package/__tests__/firmware-update/firmware-host-binding.test.ts +9 -0
  6. package/__tests__/firmware-update/firmware-prepared-host-digest.test.ts +573 -0
  7. package/__tests__/firmware-update/firmware-prepared-resource-archive.test.ts +150 -0
  8. package/__tests__/firmware-update/firmware-update-plan.test.ts +232 -70
  9. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
  10. package/__tests__/firmware-update/firmware-update-prepared-resource-executors.test.ts +326 -0
  11. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +2 -2
  12. package/__tests__/protocol-v2-resources.test.ts +148 -232
  13. package/__tests__/protocol-v2.test.ts +1236 -516
  14. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -3
  15. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  16. package/dist/api/CheckBLEFirmwareRelease.d.ts +3 -2
  17. package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
  18. package/dist/api/CheckBootloaderRelease.d.ts +2 -1
  19. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  20. package/dist/api/CheckFirmwareRelease.d.ts +3 -2
  21. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  22. package/dist/api/FirmwareUpdateV2.d.ts +1 -0
  23. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  24. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  25. package/dist/api/FirmwareUpdateV4.d.ts +8 -8
  26. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  27. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  28. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  29. package/dist/api/firmware/FirmwareHostBinding.d.ts +1 -1
  30. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -1
  31. package/dist/api/firmware/FirmwareMemoryHost.d.ts +22 -0
  32. package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
  33. package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts +11 -0
  34. package/dist/api/firmware/FirmwarePreparedResourceArchive.d.ts.map +1 -0
  35. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +48 -1
  36. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  37. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +6 -1
  38. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  39. package/dist/api/firmware/getBinary.d.ts +0 -1
  40. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  41. package/dist/api/firmware/protocolV2Release.d.ts +33 -0
  42. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -0
  43. package/dist/data-manager/DataManager.d.ts +4 -3
  44. package/dist/data-manager/DataManager.d.ts.map +1 -1
  45. package/dist/index.d.ts +108 -114
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1633 -967
  48. package/dist/protocols/protocol-v2/resources.d.ts +10 -28
  49. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  50. package/dist/types/api/checkAllFirmwareRelease.d.ts +20 -8
  51. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  52. package/dist/types/api/checkBLEFirmwareRelease.d.ts +2 -13
  53. package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
  54. package/dist/types/api/checkBootloaderRelease.d.ts +2 -6
  55. package/dist/types/api/checkBootloaderRelease.d.ts.map +1 -1
  56. package/dist/types/api/checkFirmwareRelease.d.ts +2 -13
  57. package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
  58. package/dist/types/api/checkFirmwareTypeAvailable.d.ts +2 -2
  59. package/dist/types/api/checkFirmwareTypeAvailable.d.ts.map +1 -1
  60. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  61. package/dist/types/api/export.d.ts +1 -1
  62. package/dist/types/api/export.d.ts.map +1 -1
  63. package/dist/types/api/firmwareUpdate.d.ts +4 -12
  64. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  65. package/dist/types/api/firmwareUpdatePlan.d.ts +2 -2
  66. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -1
  67. package/dist/types/settings.d.ts +35 -36
  68. package/dist/types/settings.d.ts.map +1 -1
  69. package/package.json +4 -4
  70. package/src/api/CheckAllFirmwareRelease.ts +108 -80
  71. package/src/api/CheckBLEFirmwareRelease.ts +37 -5
  72. package/src/api/CheckBootloaderRelease.ts +35 -3
  73. package/src/api/CheckFirmwareRelease.ts +35 -7
  74. package/src/api/FirmwareUpdateV2.ts +108 -73
  75. package/src/api/FirmwareUpdateV3.ts +101 -56
  76. package/src/api/FirmwareUpdateV4.ts +885 -403
  77. package/src/api/UploadPortfolio.ts +18 -0
  78. package/src/api/device/DeviceUpdateBootloader.ts +37 -11
  79. package/src/api/firmware/FirmwareHostBinding.ts +16 -3
  80. package/src/api/firmware/FirmwareMemoryHost.ts +142 -0
  81. package/src/api/firmware/FirmwarePreparedResourceArchive.ts +207 -0
  82. package/src/api/firmware/FirmwareUpdatePlan.ts +282 -122
  83. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +27 -3
  84. package/src/api/firmware/protocolV2Release.ts +168 -0
  85. package/src/data-manager/DataManager.ts +35 -19
  86. package/src/index.ts +10 -0
  87. package/src/protocols/protocol-v2/resources.ts +157 -341
  88. package/src/types/api/checkAllFirmwareRelease.ts +27 -12
  89. package/src/types/api/checkBLEFirmwareRelease.ts +4 -13
  90. package/src/types/api/checkBootloaderRelease.ts +2 -6
  91. package/src/types/api/checkFirmwareRelease.ts +2 -13
  92. package/src/types/api/checkFirmwareTypeAvailable.ts +2 -2
  93. package/src/types/api/deviceUpdateBootloader.ts +1 -0
  94. package/src/types/api/export.ts +6 -1
  95. package/src/types/api/firmwareUpdate.ts +12 -17
  96. package/src/types/api/firmwareUpdatePlan.ts +2 -2
  97. package/src/types/settings.ts +35 -61
  98. package/src/utils/deviceFeaturesUtils.ts +2 -2
@@ -29,10 +29,12 @@ import { DataManager } from '../data-manager';
29
29
  import { DEVICE } from '../events';
30
30
  import { type FirmwareByteSource, openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
31
31
  import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
32
+ import { readVerifiedPreparedResourceArchive } from './firmware/FirmwarePreparedResourceArchive';
32
33
  import {
33
34
  assertFirmwareUpdatePreparedPlanBinding,
34
35
  assertFirmwareUpdatePreparedPlanDeviceIdentity,
35
- getFirmwareUpdateResourceName,
36
+ getFirmwareUpdatePreparedRawArtifact,
37
+ validateFirmwareUpdatePreparedPlan,
36
38
  } from './firmware/FirmwareUpdatePreparedPlan';
37
39
 
38
40
  import type { Features, KnownDevice } from '../types';
@@ -46,6 +48,7 @@ import type { FirmwareUpdatePreparedPlan } from '../types/api/firmwareUpdatePrep
46
48
  type Params = {
47
49
  binary?: ArrayBuffer;
48
50
  artifact?: FirmwareArtifactReference;
51
+ hostBindingGeneration?: number;
49
52
  resourceEntries?: Array<{
50
53
  entryName: string;
51
54
  artifact: FirmwareArtifactReference;
@@ -159,15 +162,17 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
159
162
  { name: 'firmwareType', type: 'string' },
160
163
  ]);
161
164
 
162
- if (
163
- 'binary' in payload &&
164
- payload.binary !== undefined &&
165
- 'artifact' in payload &&
166
- payload.artifact !== undefined
167
- ) {
165
+ const hasPreparedPlan = payload.preparedPlan !== undefined;
166
+ if (hasPreparedPlan && (payload.binary !== undefined || payload.version !== undefined)) {
168
167
  throw ERRORS.TypedError(
169
168
  HardwareErrorCode.CallMethodInvalidParameter,
170
- 'Firmware update binary and artifact are mutually exclusive'
169
+ 'Prepared firmware plans cannot be combined with legacy firmware inputs'
170
+ );
171
+ }
172
+ if (!hasPreparedPlan && payload.artifact !== undefined) {
173
+ throw ERRORS.TypedError(
174
+ HardwareErrorCode.CallMethodInvalidParameter,
175
+ 'Firmware artifacts require a prepared plan'
171
176
  );
172
177
  }
173
178
 
@@ -184,7 +189,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
184
189
  isUpdateBootloader: payload.isUpdateBootloader,
185
190
  };
186
191
 
187
- if ('version' in payload) {
192
+ if (!hasPreparedPlan && 'version' in payload) {
188
193
  this.params = {
189
194
  ...this.params,
190
195
  version: payload.version,
@@ -192,16 +197,25 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
192
197
  };
193
198
  }
194
199
 
195
- if ('binary' in payload) {
200
+ if (!hasPreparedPlan && 'binary' in payload) {
196
201
  this.params = {
197
202
  ...this.params,
198
203
  binary: payload.binary,
199
204
  };
200
205
  }
201
206
 
202
- if ('artifact' in payload) {
203
- const hostBinding = resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration);
207
+ if (hasPreparedPlan) {
208
+ const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
209
+ const hostBinding = resolveFirmwareUpdateHostBinding(
210
+ payload.hostBindingGeneration,
211
+ preparedPlan.preparedPlanDigest
212
+ );
204
213
  const target = payload.isUpdateBootloader ? 'bootloader' : payload.updateType;
214
+ const plannedArtifact = getFirmwareUpdatePreparedRawArtifact({
215
+ preparedPlan,
216
+ target,
217
+ role: target,
218
+ }).artifact;
205
219
  const resourceBindings = (payload.resourceEntries ?? []).map(
206
220
  (entry: { entryName: string; artifact: FirmwareArtifactReference }) => ({
207
221
  target: 'resource' as const,
@@ -210,18 +224,21 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
210
224
  })
211
225
  );
212
226
  assertFirmwareUpdatePreparedPlanBinding({
213
- preparedPlan: payload.preparedPlan,
227
+ preparedPlan,
214
228
  executor: 'v2',
215
229
  platform: payload.platform,
216
- scopeTargets: [target, ...(target === 'firmware' ? (['resource'] as const) : [])],
217
- bindings: [{ target, artifact: payload.artifact }, ...resourceBindings],
230
+ scopeTargets: [
231
+ target,
232
+ ...(target === 'firmware' && resourceBindings.length ? (['resource'] as const) : []),
233
+ ],
234
+ bindings: [{ target, artifact: payload.artifact ?? plannedArtifact }, ...resourceBindings],
218
235
  });
219
236
  this.params = {
220
237
  ...this.params,
221
- preparedPlan: payload.preparedPlan,
222
- artifact: payload.artifact,
223
- resourceEntries: payload.resourceEntries,
238
+ preparedPlan,
239
+ artifact: plannedArtifact,
224
240
  artifactReader: hostBinding.artifactReader,
241
+ firmwareType: preparedPlan.firmwareType,
225
242
  };
226
243
  }
227
244
  }
@@ -531,6 +548,18 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
531
548
  }
532
549
  };
533
550
 
551
+ const preparedResourceRequested =
552
+ !params.isUpdateBootloader &&
553
+ params.updateType === 'firmware' &&
554
+ (params.preparedPlan?.targetsToUpdate.includes('resource') ?? false);
555
+ if (preparedResourceRequested && device.isBootloader()) {
556
+ throw ERRORS.TypedError(
557
+ HardwareErrorCode.RuntimeError,
558
+ 'Prepared firmware resources require the device application mode',
559
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' }
560
+ );
561
+ }
562
+
534
563
  if (!device.isBootloader() && features) {
535
564
  const serialNo = device.getCurrentSerialNo();
536
565
  // should go to bootloader mode manually
@@ -541,72 +570,78 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
541
570
  // All network-backed input must be ready before the first device mutation.
542
571
  await acquireFirmwareSource();
543
572
 
544
- // check & upgrade firmware resource
545
- if (this.isSupportResourceUpdate(params.updateType)) {
573
+ // PreparedPlan 资源只依赖获批 ZIP;live release 仅保留给非 prepared 旧流程。
574
+ if (preparedResourceRequested) {
575
+ if (!this.isSupportResourceUpdate(params.updateType)) {
576
+ throw ERRORS.TypedError(
577
+ HardwareErrorCode.RuntimeError,
578
+ 'Prepared firmware resources are not supported by this device',
579
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared', artifactName: 'resource' }
580
+ );
581
+ }
546
582
  this.postTipMessage('CheckLatestUiResource');
547
- const resourceUrl = DataManager.getSysResourcesLatestRelease({
548
- features,
549
- forcedUpdateRes: params.forcedUpdateRes,
550
- firmwareType,
583
+ this.postTipMessage('DownloadLatestUiResource');
584
+ const verifiedEntries = await readVerifiedPreparedResourceArchive({
585
+ preparedPlan: params.preparedPlan as FirmwareUpdatePreparedPlan,
586
+ reader: params.artifactReader,
551
587
  });
552
- if (resourceUrl) {
553
- this.postTipMessage('DownloadLatestUiResource');
554
- if (params.resourceEntries?.length) {
555
- const sources: Array<{
556
- entryName: string;
557
- source: FirmwareByteSource;
558
- }> = [];
559
- try {
560
- for (const entry of params.resourceEntries) {
561
- const resourceName = getFirmwareUpdateResourceName(entry.entryName);
562
- const source = await openFirmwareByteSource({
563
- artifact: entry.artifact,
564
- reader: params.artifactReader,
565
- });
566
- if (!source) {
567
- throw new Error('Firmware resource entry is not prepared');
568
- }
569
- sources.push({ entryName: resourceName, source });
570
- }
571
- await updateResourcesFromSources(
572
- this.device.getCommands().typedCall.bind(this.device.getCommands()),
573
- this.postMessage,
574
- device,
575
- sources.map(entry => ({
576
- entryName: entry.entryName,
577
- source: entry.source,
578
- }))
579
- );
580
- } finally {
581
- await Promise.all(
582
- sources.map(entry => entry.source.close().catch(() => undefined))
583
- );
584
- }
585
- this.postTipMessage('DownloadLatestUiResourceSuccess');
586
- } else {
587
- if (
588
- params.artifactReader ||
589
- DataManager.getSettings('firmwareManifestMode') === 'external-only'
590
- ) {
588
+ const sources: Array<{ entryName: string; source: FirmwareByteSource }> = [];
589
+ try {
590
+ for (const entry of verifiedEntries) {
591
+ const source = await openFirmwareByteSource({ binary: entry.binary });
592
+ if (!source) {
591
593
  throw ERRORS.TypedError(
592
594
  HardwareErrorCode.RuntimeError,
593
- 'Firmware resource must be prepared by the external firmware host',
595
+ `Firmware resource entry ${entry.entryName} is empty`,
594
596
  {
595
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
597
+ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
596
598
  artifactName: 'resource',
597
599
  }
598
600
  );
599
601
  }
600
- const resourceBinary: ArrayBuffer | Buffer = (await getSysResourceBinary(resourceUrl))
601
- .binary;
602
- this.postTipMessage('DownloadLatestUiResourceSuccess');
603
- await updateResources(
604
- this.device.getCommands().typedCall.bind(this.device.getCommands()),
605
- this.postMessage,
606
- device,
607
- resourceBinary
602
+ sources.push({ entryName: entry.entryName, source });
603
+ }
604
+ await updateResourcesFromSources(
605
+ this.device.getCommands().typedCall.bind(this.device.getCommands()),
606
+ this.postMessage,
607
+ device,
608
+ sources
609
+ );
610
+ } finally {
611
+ await Promise.all(sources.map(entry => entry.source.close().catch(() => undefined)));
612
+ }
613
+ this.postTipMessage('DownloadLatestUiResourceSuccess');
614
+ } else if (this.isSupportResourceUpdate(params.updateType)) {
615
+ this.postTipMessage('CheckLatestUiResource');
616
+ const resourceUrl = DataManager.getSysResourcesLatestRelease({
617
+ features,
618
+ forcedUpdateRes: params.forcedUpdateRes,
619
+ firmwareType,
620
+ });
621
+ if (resourceUrl) {
622
+ this.postTipMessage('DownloadLatestUiResource');
623
+ if (
624
+ params.artifactReader ||
625
+ DataManager.getSettings('firmwareManifestMode') === 'external-only'
626
+ ) {
627
+ throw ERRORS.TypedError(
628
+ HardwareErrorCode.RuntimeError,
629
+ 'Firmware resource must be prepared by the external firmware host',
630
+ {
631
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
632
+ artifactName: 'resource',
633
+ }
608
634
  );
609
635
  }
636
+ const resourceBinary: ArrayBuffer | Buffer = (await getSysResourceBinary(resourceUrl))
637
+ .binary;
638
+ this.postTipMessage('DownloadLatestUiResourceSuccess');
639
+ await updateResources(
640
+ this.device.getCommands().typedCall.bind(this.device.getCommands()),
641
+ this.postMessage,
642
+ device,
643
+ resourceBinary
644
+ );
610
645
  }
611
646
  }
612
647
 
@@ -21,10 +21,12 @@ import { DEVICE } from '../events';
21
21
  import { buildProtocolV1FeaturesPayload } from '../deviceProfile';
22
22
  import { openFirmwareByteSource } from './firmware/FirmwareArtifactSource';
23
23
  import { resolveFirmwareUpdateHostBinding } from './firmware/FirmwareHostBinding';
24
+ import { readVerifiedPreparedResourceArchive } from './firmware/FirmwarePreparedResourceArchive';
24
25
  import {
25
26
  assertFirmwareUpdatePreparedPlanBinding,
26
27
  assertFirmwareUpdatePreparedPlanDeviceIdentity,
27
- getFirmwareUpdateResourceName,
28
+ getFirmwareUpdatePreparedRawArtifact,
29
+ validateFirmwareUpdatePreparedPlan,
28
30
  } from './firmware/FirmwareUpdatePreparedPlan';
29
31
 
30
32
  import type {
@@ -77,54 +79,97 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
77
79
  { name: 'firmwareType', type: 'string' },
78
80
  { name: 'platform', type: 'string' },
79
81
  ]);
80
- const hostBinding =
81
- payload.artifacts || payload.preparedPlan
82
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
83
- : undefined;
84
- if (hostBinding) {
82
+ const hasPreparedPlan = payload.preparedPlan !== undefined;
83
+ if (!hasPreparedPlan && payload.artifacts !== undefined) {
84
+ throw ERRORS.TypedError(
85
+ HardwareErrorCode.CallMethodInvalidParameter,
86
+ 'Firmware artifacts require a prepared plan'
87
+ );
88
+ }
89
+ const preparedPlan = hasPreparedPlan
90
+ ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
91
+ : undefined;
92
+ const hasLegacyInputs = [
93
+ payload.bleVersion,
94
+ payload.bleBinary,
95
+ payload.firmwareVersion,
96
+ payload.firmwareBinary,
97
+ payload.resourceBinary,
98
+ payload.bootloaderVersion,
99
+ payload.bootloaderBinary,
100
+ ].some(input => input !== undefined);
101
+ if (preparedPlan && hasLegacyInputs) {
102
+ throw ERRORS.TypedError(
103
+ HardwareErrorCode.CallMethodInvalidParameter,
104
+ 'Prepared firmware plans cannot be combined with legacy firmware inputs'
105
+ );
106
+ }
107
+ const artifactReader = preparedPlan
108
+ ? resolveFirmwareUpdateHostBinding(
109
+ payload.hostBindingGeneration,
110
+ preparedPlan.preparedPlanDigest
111
+ ).artifactReader
112
+ : payload.artifactReader;
113
+ const preparedArtifacts: NonNullable<FirmwareUpdateV3Params['artifacts']> = {};
114
+ if (preparedPlan) {
115
+ const componentTargets = ['bootloader', 'firmware', 'ble'] as const;
116
+ const supportedTargets = new Set<string>([...componentTargets, 'resource']);
117
+ const unsupportedTarget = preparedPlan.targetsToUpdate.find(
118
+ target => !supportedTargets.has(target)
119
+ );
120
+ if (unsupportedTarget) {
121
+ throw ERRORS.TypedError(
122
+ HardwareErrorCode.RuntimeError,
123
+ `Firmware prepared plan target ${unsupportedTarget} is not supported by V3`,
124
+ { firmwareUpdateCode: 'FirmwarePreparedPlanInvalid' }
125
+ );
126
+ }
127
+ for (const target of componentTargets) {
128
+ if (preparedPlan.targetsToUpdate.includes(target)) {
129
+ preparedArtifacts[target] = getFirmwareUpdatePreparedRawArtifact({
130
+ preparedPlan,
131
+ target,
132
+ role: target,
133
+ }).artifact;
134
+ }
135
+ }
136
+ const resourceBindings = (payload.artifacts?.resourceEntries ?? []).map(
137
+ (entry: { entryName: string; artifact: FirmwareArtifactReference }) => ({
138
+ target: 'resource' as const,
139
+ entryName: entry.entryName,
140
+ artifact: entry.artifact,
141
+ })
142
+ );
85
143
  assertFirmwareUpdatePreparedPlanBinding({
86
- preparedPlan: payload.preparedPlan,
144
+ preparedPlan,
87
145
  executor: 'v3',
88
146
  platform: payload.platform,
89
- scopeTargets: ['bootloader', 'firmware', 'resource', 'ble'],
147
+ scopeTargets: [
148
+ 'bootloader',
149
+ 'firmware',
150
+ 'ble',
151
+ ...(resourceBindings.length ? (['resource'] as const) : []),
152
+ ],
90
153
  bindings: [
91
- ...(payload.artifacts?.bootloader
92
- ? [
93
- {
94
- target: 'bootloader' as const,
95
- artifact: payload.artifacts.bootloader,
96
- },
97
- ]
98
- : []),
99
- ...(payload.artifacts?.firmware
100
- ? [
101
- {
102
- target: 'firmware' as const,
103
- artifact: payload.artifacts.firmware,
104
- },
105
- ]
106
- : []),
107
- ...(payload.artifacts?.ble
108
- ? [
109
- {
110
- target: 'ble' as const,
111
- artifact: payload.artifacts.ble,
112
- },
113
- ]
114
- : []),
115
- ...(payload.artifacts?.resourceEntries ?? []).map(
116
- (entry: { entryName: string; artifact: FirmwareArtifactReference }) => ({
117
- target: 'resource' as const,
118
- entryName: entry.entryName,
119
- artifact: entry.artifact,
120
- })
121
- ),
154
+ ...componentTargets.flatMap(target => {
155
+ const plannedArtifact = preparedArtifacts[target];
156
+ const suppliedArtifact = payload.artifacts?.[target];
157
+ return plannedArtifact || suppliedArtifact
158
+ ? [
159
+ {
160
+ target,
161
+ artifact: suppliedArtifact ?? (plannedArtifact as FirmwareArtifactReference),
162
+ },
163
+ ]
164
+ : [];
165
+ }),
166
+ ...resourceBindings,
122
167
  ],
123
168
  });
124
169
  }
125
170
 
126
171
  this.params = {
127
- preparedPlan: payload.preparedPlan,
172
+ preparedPlan,
128
173
  bleBinary: payload.bleBinary,
129
174
  firmwareBinary: payload.firmwareBinary,
130
175
  forcedUpdateRes: payload.forcedUpdateRes,
@@ -133,10 +178,10 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
133
178
  bootloaderBinary: payload.bootloaderBinary,
134
179
  firmwareVersion: payload.firmwareVersion,
135
180
  resourceBinary: payload.resourceBinary,
136
- firmwareType: payload.firmwareType,
181
+ firmwareType: preparedPlan?.firmwareType ?? payload.firmwareType,
137
182
  platform: payload.platform,
138
- artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
139
- artifacts: payload.artifacts,
183
+ artifactReader,
184
+ artifacts: preparedPlan ? preparedArtifacts : undefined,
140
185
  };
141
186
  }
142
187
 
@@ -263,25 +308,25 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
263
308
  }
264
309
 
265
310
  private async prepareResourceInput(firmwareType: EFirmwareType) {
266
- const preparedEntries = this.params.artifacts?.resourceEntries;
267
- if (preparedEntries?.length && this.params.resourceBinary) {
268
- throw ERRORS.TypedError(
269
- HardwareErrorCode.RuntimeError,
270
- 'Firmware resource input must not contain both archive binary and prepared entries'
271
- );
272
- }
273
- if (preparedEntries?.length) {
311
+ if (this.params.preparedPlan?.targetsToUpdate.includes('resource')) {
312
+ const verifiedEntries = await readVerifiedPreparedResourceArchive({
313
+ preparedPlan: this.params.preparedPlan,
314
+ reader: this.params.artifactReader,
315
+ });
274
316
  const resourceEntries: Array<{ entryName: string; source: FirmwareByteSource }> = [];
275
- for (const entry of preparedEntries) {
276
- const resourceName = getFirmwareUpdateResourceName(entry.entryName);
277
- const source = await this.openArtifactSource(undefined, entry.artifact);
317
+ for (const entry of verifiedEntries) {
318
+ const source = await this.openArtifactSource(entry.binary, undefined);
278
319
  if (!source) {
279
320
  throw ERRORS.TypedError(
280
321
  HardwareErrorCode.RuntimeError,
281
- `Firmware resource entry ${entry.entryName} is not prepared`
322
+ `Firmware resource entry ${entry.entryName} is empty`,
323
+ {
324
+ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch',
325
+ artifactName: 'resource',
326
+ }
282
327
  );
283
328
  }
284
- resourceEntries.push({ entryName: resourceName, source });
329
+ resourceEntries.push({ entryName: entry.entryName, source });
285
330
  }
286
331
  return {
287
332
  resourceBinary: null,