@onekeyfe/hd-core 1.2.0-alpha.82 → 1.2.0-alpha.85

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 (53) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +285 -13
  2. package/__tests__/check-firmware-release-protocol-v2.test.ts +6 -0
  3. package/__tests__/firmware-memory-host.test.ts +105 -0
  4. package/__tests__/firmware-update/firmware-update-plan.test.ts +15 -70
  5. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
  6. package/__tests__/protocol-v2-resources.test.ts +0 -38
  7. package/__tests__/protocol-v2.test.ts +212 -320
  8. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  9. package/dist/api/FirmwareUpdateV4.d.ts +1 -2
  10. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  11. package/dist/api/firmware/FirmwareMemoryHost.d.ts +27 -0
  12. package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
  13. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +33 -1
  14. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  15. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  16. package/dist/api/firmware/getBinary.d.ts +0 -1
  17. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  18. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
  19. package/dist/index.d.ts +25 -64
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +546 -387
  22. package/dist/inject.d.ts.map +1 -1
  23. package/dist/protocols/protocol-v2/resources.d.ts +0 -17
  24. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  25. package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -0
  26. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  27. package/dist/types/api/export.d.ts +0 -1
  28. package/dist/types/api/export.d.ts.map +1 -1
  29. package/dist/types/api/firmwareUpdate.d.ts +0 -10
  30. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  31. package/dist/types/api/index.d.ts +0 -2
  32. package/dist/types/api/index.d.ts.map +1 -1
  33. package/dist/types/settings.d.ts +0 -11
  34. package/dist/types/settings.d.ts.map +1 -1
  35. package/package.json +4 -4
  36. package/src/api/CheckAllFirmwareRelease.ts +72 -5
  37. package/src/api/FirmwareUpdateV4.ts +154 -165
  38. package/src/api/firmware/FirmwareMemoryHost.ts +171 -0
  39. package/src/api/firmware/FirmwareUpdatePlan.ts +176 -79
  40. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +8 -1
  41. package/src/api/firmware/protocolV2Release.ts +2 -0
  42. package/src/index.ts +6 -1
  43. package/src/inject.ts +0 -2
  44. package/src/protocols/protocol-v2/resources.ts +0 -47
  45. package/src/types/api/checkAllFirmwareRelease.ts +1 -0
  46. package/src/types/api/export.ts +0 -4
  47. package/src/types/api/firmwareUpdate.ts +0 -15
  48. package/src/types/api/index.ts +0 -2
  49. package/src/types/settings.ts +0 -20
  50. package/src/utils/deviceFeaturesUtils.ts +2 -2
  51. package/dist/types/api/protocolV2ResourceManifest.d.ts +0 -17
  52. package/dist/types/api/protocolV2ResourceManifest.d.ts.map +0 -1
  53. package/src/types/api/protocolV2ResourceManifest.ts +0 -19
package/dist/index.js CHANGED
@@ -522,6 +522,10 @@ const PROTOCOL_V2_TARGETS = {
522
522
  SE03: 'se03',
523
523
  SE04: 'se04',
524
524
  };
525
+ const PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS = new Set([
526
+ ...Object.values(PROTOCOL_V2_TARGETS),
527
+ 'resource',
528
+ ]);
525
529
  const asRecord = (value) => value && typeof value === 'object' && !Array.isArray(value)
526
530
  ? value
527
531
  : undefined;
@@ -609,6 +613,18 @@ const validateFirmwareUpdatePlanForceTargets = (value) => {
609
613
  }
610
614
  return [...value];
611
615
  };
616
+ const validateProtocolV2FirmwareUpdateTargets = (value) => {
617
+ if (value === undefined) {
618
+ return [];
619
+ }
620
+ if (!Array.isArray(value) ||
621
+ value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
622
+ value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
623
+ new Set(value).size !== value.length) {
624
+ return planError('Protocol V2 firmware update targets are invalid');
625
+ }
626
+ return [...value];
627
+ };
612
628
  const assertExactKeys = (value, required, optional = []) => {
613
629
  const allowed = new Set([...required, ...optional]);
614
630
  if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
@@ -773,7 +789,7 @@ const selectResourceUrl = ({ release, features, platform, }) => {
773
789
  };
774
790
  const getExecutor = (features) => {
775
791
  const deviceType = getDeviceType(features);
776
- if (deviceType === hdShared.EDeviceType.Pro2) {
792
+ if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
777
793
  return 'v4';
778
794
  }
779
795
  if (deviceType === hdShared.EDeviceType.Pro &&
@@ -782,7 +798,7 @@ const getExecutor = (features) => {
782
798
  }
783
799
  return 'v2';
784
800
  };
785
- const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, } = {}) => {
801
+ const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
786
802
  var _a;
787
803
  const components = asRecord(release.components);
788
804
  if (includeComponents && !components) {
@@ -794,49 +810,38 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
794
810
  const componentKeys = includeComponents && components
795
811
  ? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
796
812
  : [];
813
+ const selectedComponentKeys = selectedComponentTargets
814
+ ? componentKeys.filter(key => {
815
+ var _a;
816
+ const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
817
+ const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
818
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
819
+ return !!target && selectedComponentTargets.has(target);
820
+ })
821
+ : componentKeys;
797
822
  const artifacts = [];
798
823
  const targets = [];
799
- const componentTargets = new Set();
800
- for (const key of componentKeys) {
824
+ const componentTargetSet = new Set();
825
+ for (const key of selectedComponentKeys) {
801
826
  const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
802
827
  const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
828
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
803
829
  if (targetName === 'ROMLOADER') {
804
830
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
805
831
  }
806
- const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
807
832
  if (!component || !target) {
808
833
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} has an unsupported target`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
809
834
  }
810
- if (componentTargets.has(target)) {
835
+ if (componentTargetSet.has(target)) {
811
836
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
812
837
  }
813
- componentTargets.add(target);
838
+ componentTargetSet.add(target);
814
839
  artifacts.push(Object.assign(Object.assign({ artifactId: `component:${target}`, role: 'component', target, url: assertArtifactUrl(component.url, `Protocol V2 component ${key}`), container: 'raw', logicalName: key }, asIntegrity({
815
840
  size: component.expectedSize,
816
841
  sha256: component.fingerprint,
817
842
  })), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
818
843
  targets.push(target);
819
844
  }
820
- const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
821
- const resourceBundleNames = new Set();
822
- for (const value of bundles) {
823
- const bundle = asRecord(value);
824
- const name = asString(bundle === null || bundle === void 0 ? void 0 : bundle.name);
825
- if (!bundle || !name) {
826
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource bundle is invalid', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
827
- }
828
- if (resourceBundleNames.has(name)) {
829
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle duplicates name ${name}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
830
- }
831
- resourceBundleNames.add(name);
832
- artifacts.push(Object.assign({ artifactId: `resourceBundle:${name}`, role: 'resourceBundle', target: 'resource', url: assertArtifactUrl(bundle.url, `Protocol V2 resource bundle ${name}`), container: 'raw', logicalName: name }, asIntegrity({
833
- size: bundle.expectedSize,
834
- sha256: bundle.fingerprint,
835
- })));
836
- }
837
- if (bundles.length > 0) {
838
- targets.push('resource');
839
- }
840
845
  return { artifacts, targets: [...new Set(targets)] };
841
846
  };
842
847
  const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
@@ -865,6 +870,78 @@ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, ta
865
870
  }
866
871
  }
867
872
  };
873
+ const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, targetsToUpdate, }) => {
874
+ const executor = getExecutor(features);
875
+ const bootloaderMode = resolveDeviceBootloaderMode(features);
876
+ const reportedIdentity = getDeviceUUID(features);
877
+ const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
878
+ if (artifacts.length > 0 &&
879
+ (platform === 'native' || platform === 'desktop') &&
880
+ !deviceIdentity &&
881
+ !(bootloaderMode && executor === 'v2')) {
882
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
883
+ }
884
+ const planWithoutDigest = {
885
+ schemaVersion: 2,
886
+ executor,
887
+ deviceIdentity: deviceIdentity || 'unavailable',
888
+ deviceModel: String(getDeviceType(features)),
889
+ firmwareType,
890
+ platform,
891
+ artifacts,
892
+ targetsToUpdate,
893
+ };
894
+ return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
895
+ };
896
+ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
897
+ const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
898
+ if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
899
+ planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
900
+ }
901
+ const requestedComponentTargets = new Set(targetsToUpdate.filter(target => target !== 'resource'));
902
+ if (getDeviceType(features) === hdShared.EDeviceType.Neo &&
903
+ (requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))) {
904
+ planError('Neo does not support Protocol V2 targets se03 or se04');
905
+ }
906
+ const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
907
+ includeComponents: requestedComponentTargets.size > 0,
908
+ componentTargets: requestedComponentTargets,
909
+ });
910
+ const resourceRequested = targetsToUpdate.includes('resource');
911
+ if (resourceRequested) {
912
+ const archive = resourceArchive;
913
+ if (!archive) {
914
+ return planError('Protocol V2 resource target has no resource archive');
915
+ }
916
+ const integrity = asIntegrity({
917
+ size: archive.archiveSize,
918
+ sha256: archive.archiveSha256,
919
+ });
920
+ if (integrity.expectedSize === undefined || integrity.expectedSha256 === undefined) {
921
+ planError('Protocol V2 resource archive integrity metadata is invalid');
922
+ }
923
+ protocolV2.artifacts.push(Object.assign({ artifactId: 'resource:archive', role: 'resourceBundle', target: 'resource', url: assertArtifactUrl(archive.archiveUrl, 'Protocol V2 resource archive'), container: 'zip', logicalName: 'protocol-v2-resource-archive' }, integrity));
924
+ protocolV2.targets.push('resource');
925
+ }
926
+ const representedTargets = new Set(protocolV2.targets);
927
+ const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
928
+ if (missingTarget) {
929
+ planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
930
+ }
931
+ if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
932
+ planError('Forced firmware update target firmware is not represented by the plan');
933
+ }
934
+ if (validatedForceTargets.includes('resource') && !resourceArchive) {
935
+ planError('Forced firmware update target resource has no Protocol V2 resource archive');
936
+ }
937
+ return finalizeFirmwareUpdatePlan({
938
+ features,
939
+ firmwareType,
940
+ platform,
941
+ artifacts: protocolV2.artifacts,
942
+ targetsToUpdate: protocolV2.targets,
943
+ });
944
+ };
868
945
  const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
869
946
  var _a, _b, _c, _d, _e, _f, _g;
870
947
  const executor = getExecutor(features);
@@ -886,7 +963,6 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
886
963
  if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
887
964
  const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
888
965
  includeComponents: shouldUpdateFirmware,
889
- includeResources: shouldUpdateResource,
890
966
  });
891
967
  artifacts = protocolV2.artifacts;
892
968
  targetsToUpdate = protocolV2.targets;
@@ -951,25 +1027,13 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
951
1027
  artifacts,
952
1028
  targetsToUpdate,
953
1029
  });
954
- const reportedIdentity = getDeviceUUID(features);
955
- const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
956
- if (artifacts.length > 0 &&
957
- (platform === 'native' || platform === 'desktop') &&
958
- !deviceIdentity &&
959
- !(bootloaderMode && executor === 'v2')) {
960
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
961
- }
962
- const planWithoutDigest = {
963
- schemaVersion: 2,
964
- executor,
965
- deviceIdentity: deviceIdentity || 'unavailable',
966
- deviceModel: String(getDeviceType(features)),
1030
+ return finalizeFirmwareUpdatePlan({
1031
+ features,
967
1032
  firmwareType,
968
1033
  platform,
969
1034
  artifacts,
970
1035
  targetsToUpdate,
971
- };
972
- return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
1036
+ });
973
1037
  };
974
1038
 
975
1039
  const preparedPlanError = (message) => {
@@ -1090,7 +1154,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
1090
1154
  return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
1091
1155
  };
1092
1156
  const validateFirmwareUpdatePreparedPlan = (value) => {
1093
- var _a, _b, _c;
1157
+ var _a, _b, _c, _d;
1094
1158
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
1095
1159
  return preparedPlanError('Firmware prepared plan must be an object');
1096
1160
  }
@@ -1170,7 +1234,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
1170
1234
  artifactIds.add(artifact.artifactId);
1171
1235
  artifactTargets.add(artifact.target);
1172
1236
  assertFirmwareArtifactReference(artifact.artifact);
1173
- (_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.forEach(assertPreparedEntry);
1237
+ const materializedEntryNames = (_d = (_c = artifact.materializedEntries) === null || _c === void 0 ? void 0 : _c.map(entry => {
1238
+ assertPreparedEntry(entry);
1239
+ return getFirmwareUpdateResourceName(entry.entryName).toLowerCase();
1240
+ })) !== null && _d !== void 0 ? _d : [];
1241
+ if (new Set(materializedEntryNames).size !== materializedEntryNames.length) {
1242
+ return preparedPlanError('Firmware prepared plan contains duplicate entry names');
1243
+ }
1174
1244
  }
1175
1245
  if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
1176
1246
  new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
@@ -1265,201 +1335,6 @@ const assertFirmwareUpdatePreparedPlanBinding = ({ preparedPlan: value, executor
1265
1335
  return preparedPlan;
1266
1336
  };
1267
1337
 
1268
- const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
1269
- const SHA256_HEX_LENGTH = 64;
1270
- function normalizeHex$1(value, expectedLength, field) {
1271
- if (typeof value !== 'string') {
1272
- throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
1273
- }
1274
- const normalized = value.replace(/^0x/i, '').toLowerCase();
1275
- if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
1276
- throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
1277
- }
1278
- return normalized;
1279
- }
1280
- function parseProtocolV2Resources(value) {
1281
- if (value === undefined)
1282
- return undefined;
1283
- if (!value || typeof value !== 'object') {
1284
- throw new Error('Invalid Pro2 resources config');
1285
- }
1286
- const { source } = value;
1287
- if (!source || typeof source !== 'object') {
1288
- throw new Error('Invalid Pro2 resources config: source is required');
1289
- }
1290
- const { archiveUrl, archiveSha256, archiveSize } = source;
1291
- if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
1292
- throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
1293
- }
1294
- if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
1295
- throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
1296
- }
1297
- if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
1298
- throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
1299
- }
1300
- return {
1301
- source: {
1302
- archiveUrl,
1303
- archiveSha256: archiveSha256.toLowerCase(),
1304
- archiveSize: archiveSize,
1305
- },
1306
- };
1307
- }
1308
- const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
1309
- 'vol0:/bundles/',
1310
- 'vol0:/loaders/rom/',
1311
- ];
1312
- function isAllowedManifestDevicePath(path) {
1313
- if (!path.endsWith('.okpkg') ||
1314
- path.includes('\\') ||
1315
- path.includes('//') ||
1316
- path.split('/').some(part => part === '.' || part === '..')) {
1317
- return false;
1318
- }
1319
- if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
1320
- return true;
1321
- }
1322
- return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
1323
- }
1324
- function assertManifestString(value, field) {
1325
- if (typeof value !== 'string' || value.length === 0) {
1326
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
1327
- }
1328
- return value;
1329
- }
1330
- function assertManifestRelativePath(value, field) {
1331
- const path = assertManifestString(value, field);
1332
- if (path.startsWith('/') ||
1333
- path.includes('\\') ||
1334
- path.includes(':') ||
1335
- path.split('/').some(part => !part || part === '.' || part === '..')) {
1336
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
1337
- }
1338
- return path;
1339
- }
1340
- function parseProtocolV2ResourceManifestFile(value, index) {
1341
- var _a;
1342
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
1343
- throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
1344
- }
1345
- const file = value;
1346
- const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
1347
- const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
1348
- if (originalName.includes('/')) {
1349
- throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
1350
- }
1351
- const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
1352
- if (!isAllowedManifestDevicePath(devicePath)) {
1353
- throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
1354
- }
1355
- if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
1356
- throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
1357
- }
1358
- const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
1359
- if (file.signed !== true) {
1360
- throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
1361
- }
1362
- if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
1363
- throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
1364
- }
1365
- if (file.payload_version !== null && typeof file.payload_version !== 'string') {
1366
- throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
1367
- }
1368
- if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
1369
- throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
1370
- }
1371
- return {
1372
- archive_path: archivePath,
1373
- original_name: originalName,
1374
- device_path: devicePath,
1375
- size: Number(file.size),
1376
- sha256: digest,
1377
- signed: true,
1378
- sig_algo: file.sig_algo,
1379
- payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
1380
- };
1381
- }
1382
- function parseProtocolV2ResourceManifest(value) {
1383
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
1384
- throw new Error('Invalid Pro2 resource manifest');
1385
- }
1386
- const manifest = value;
1387
- if (manifest.schema !== 1 ||
1388
- manifest.variant !== 'resource' ||
1389
- manifest.device_root !== 'vol0:' ||
1390
- manifest.restore_mode !== 'bootloader_update' ||
1391
- !Array.isArray(manifest.trees) ||
1392
- !Array.isArray(manifest.files)) {
1393
- throw new Error('Invalid Pro2 resource manifest contract');
1394
- }
1395
- const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
1396
- const devicePaths = new Set(files.map(file => file.device_path));
1397
- const archivePaths = new Set(files.map(file => file.archive_path));
1398
- if (files.length === 0 ||
1399
- devicePaths.size !== files.length ||
1400
- archivePaths.size !== files.length ||
1401
- !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
1402
- !files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
1403
- throw new Error('Invalid Pro2 resource manifest file set');
1404
- }
1405
- return {
1406
- schema: 1,
1407
- artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
1408
- release_name: assertManifestString(manifest.release_name, 'release_name'),
1409
- variant: 'resource',
1410
- commit: assertManifestString(manifest.commit, 'commit'),
1411
- short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
1412
- timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
1413
- core_version: assertManifestString(manifest.core_version, 'core_version'),
1414
- key_set: assertManifestString(manifest.key_set, 'key_set'),
1415
- device_root: 'vol0:',
1416
- restore_mode: 'bootloader_update',
1417
- trees: manifest.trees.map((tree, index) => {
1418
- if (!tree || typeof tree !== 'object') {
1419
- throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
1420
- }
1421
- const item = tree;
1422
- return {
1423
- path: assertManifestRelativePath(item.path, `trees[${index}].path`),
1424
- device: assertManifestString(item.device, `trees[${index}].device`),
1425
- };
1426
- }),
1427
- files,
1428
- };
1429
- }
1430
- function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
1431
- return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
1432
- }
1433
- function prepareProtocolV2ResourceFiles({ manifest: value, files, targetsToUpdate, }) {
1434
- const manifest = parseProtocolV2ResourceManifest(value);
1435
- const selected = selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate });
1436
- const binaries = new Map(files.map(file => [file.archivePath, file.binary]));
1437
- return selected.map(file => {
1438
- const binary = binaries.get(file.archive_path);
1439
- if (!binary ||
1440
- !isProtocolV2ResourceFileValid(binary, {
1441
- size: file.size,
1442
- fileHash: file.sha256,
1443
- })) {
1444
- throw new Error(`Pro2 resource manifest file verification failed: ${file.archive_path}`);
1445
- }
1446
- return {
1447
- binary,
1448
- devicePath: file.device_path,
1449
- size: file.size,
1450
- fileHash: file.sha256,
1451
- };
1452
- });
1453
- }
1454
- function bytesToHex$3(bytes) {
1455
- return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
1456
- }
1457
- function isProtocolV2ResourceFileValid(binary, resource) {
1458
- if (binary.byteLength !== resource.size)
1459
- return false;
1460
- return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
1461
- }
1462
-
1463
1338
  const bindingError = (message) => {
1464
1339
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, {
1465
1340
  firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
@@ -1609,7 +1484,6 @@ const createCoreApi = (call) => ({
1609
1484
  getFirmwareUpdateHostBindingGeneration,
1610
1485
  prepareFirmwareUpdatePlan,
1611
1486
  validateFirmwareUpdatePreparedPlan,
1612
- prepareProtocolV2ResourceFiles,
1613
1487
  getLogs: () => call({ method: 'getLogs' }),
1614
1488
  clearSessionCache: params => call(Object.assign(Object.assign({}, params), { method: 'clearSessionCache' })),
1615
1489
  searchDevices: params => call(Object.assign(Object.assign({}, params), { method: 'searchDevices' })),
@@ -40700,6 +40574,172 @@ const findLatestRelease = (releases) => {
40700
40574
  return leastRelease;
40701
40575
  };
40702
40576
 
40577
+ const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
40578
+ const SHA256_HEX_LENGTH = 64;
40579
+ function normalizeHex$1(value, expectedLength, field) {
40580
+ if (typeof value !== 'string') {
40581
+ throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
40582
+ }
40583
+ const normalized = value.replace(/^0x/i, '').toLowerCase();
40584
+ if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
40585
+ throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
40586
+ }
40587
+ return normalized;
40588
+ }
40589
+ function parseProtocolV2Resources(value) {
40590
+ if (value === undefined)
40591
+ return undefined;
40592
+ if (!value || typeof value !== 'object') {
40593
+ throw new Error('Invalid Pro2 resources config');
40594
+ }
40595
+ const { source } = value;
40596
+ if (!source || typeof source !== 'object') {
40597
+ throw new Error('Invalid Pro2 resources config: source is required');
40598
+ }
40599
+ const { archiveUrl, archiveSha256, archiveSize } = source;
40600
+ if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
40601
+ throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
40602
+ }
40603
+ if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
40604
+ throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
40605
+ }
40606
+ if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
40607
+ throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
40608
+ }
40609
+ return {
40610
+ source: {
40611
+ archiveUrl,
40612
+ archiveSha256: archiveSha256.toLowerCase(),
40613
+ archiveSize: archiveSize,
40614
+ },
40615
+ };
40616
+ }
40617
+ const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
40618
+ 'vol0:/bundles/',
40619
+ 'vol0:/loaders/rom/',
40620
+ ];
40621
+ function isAllowedManifestDevicePath(path) {
40622
+ if (!path.endsWith('.okpkg') ||
40623
+ path.includes('\\') ||
40624
+ path.includes('//') ||
40625
+ path.split('/').some(part => part === '.' || part === '..')) {
40626
+ return false;
40627
+ }
40628
+ if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
40629
+ return true;
40630
+ }
40631
+ return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
40632
+ }
40633
+ function assertManifestString(value, field) {
40634
+ if (typeof value !== 'string' || value.length === 0) {
40635
+ throw new Error(`Invalid Pro2 resource manifest ${field}`);
40636
+ }
40637
+ return value;
40638
+ }
40639
+ function assertManifestRelativePath(value, field) {
40640
+ const path = assertManifestString(value, field);
40641
+ if (path.startsWith('/') ||
40642
+ path.includes('\\') ||
40643
+ path.includes(':') ||
40644
+ path.split('/').some(part => !part || part === '.' || part === '..')) {
40645
+ throw new Error(`Invalid Pro2 resource manifest ${field}`);
40646
+ }
40647
+ return path;
40648
+ }
40649
+ function parseProtocolV2ResourceManifestFile(value, index) {
40650
+ var _a;
40651
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
40652
+ throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
40653
+ }
40654
+ const file = value;
40655
+ const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
40656
+ const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
40657
+ if (originalName.includes('/')) {
40658
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
40659
+ }
40660
+ const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
40661
+ if (!isAllowedManifestDevicePath(devicePath)) {
40662
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
40663
+ }
40664
+ if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
40665
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
40666
+ }
40667
+ const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
40668
+ if (file.signed !== true) {
40669
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
40670
+ }
40671
+ if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
40672
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
40673
+ }
40674
+ if (file.payload_version !== null && typeof file.payload_version !== 'string') {
40675
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
40676
+ }
40677
+ if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
40678
+ throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
40679
+ }
40680
+ return {
40681
+ archive_path: archivePath,
40682
+ original_name: originalName,
40683
+ device_path: devicePath,
40684
+ size: Number(file.size),
40685
+ sha256: digest,
40686
+ signed: true,
40687
+ sig_algo: file.sig_algo,
40688
+ payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
40689
+ };
40690
+ }
40691
+ function parseProtocolV2ResourceManifest(value) {
40692
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
40693
+ throw new Error('Invalid Pro2 resource manifest');
40694
+ }
40695
+ const manifest = value;
40696
+ if (manifest.schema !== 1 ||
40697
+ manifest.variant !== 'resource' ||
40698
+ manifest.device_root !== 'vol0:' ||
40699
+ manifest.restore_mode !== 'bootloader_update' ||
40700
+ !Array.isArray(manifest.trees) ||
40701
+ !Array.isArray(manifest.files)) {
40702
+ throw new Error('Invalid Pro2 resource manifest contract');
40703
+ }
40704
+ const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
40705
+ const devicePaths = new Set(files.map(file => file.device_path));
40706
+ const archivePaths = new Set(files.map(file => file.archive_path));
40707
+ if (files.length === 0 ||
40708
+ devicePaths.size !== files.length ||
40709
+ archivePaths.size !== files.length ||
40710
+ !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
40711
+ !files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
40712
+ throw new Error('Invalid Pro2 resource manifest file set');
40713
+ }
40714
+ return {
40715
+ schema: 1,
40716
+ artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
40717
+ release_name: assertManifestString(manifest.release_name, 'release_name'),
40718
+ variant: 'resource',
40719
+ commit: assertManifestString(manifest.commit, 'commit'),
40720
+ short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
40721
+ timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
40722
+ core_version: assertManifestString(manifest.core_version, 'core_version'),
40723
+ key_set: assertManifestString(manifest.key_set, 'key_set'),
40724
+ device_root: 'vol0:',
40725
+ restore_mode: 'bootloader_update',
40726
+ trees: manifest.trees.map((tree, index) => {
40727
+ if (!tree || typeof tree !== 'object') {
40728
+ throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
40729
+ }
40730
+ const item = tree;
40731
+ return {
40732
+ path: assertManifestRelativePath(item.path, `trees[${index}].path`),
40733
+ device: assertManifestString(item.device, `trees[${index}].device`),
40734
+ };
40735
+ }),
40736
+ files,
40737
+ };
40738
+ }
40739
+ function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
40740
+ return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
40741
+ }
40742
+
40703
40743
  var _a$1;
40704
40744
  const FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS = 5 * 60 * 1000;
40705
40745
  const Log$k = getLogger(exports.LoggerNames.Core);
@@ -41925,7 +41965,7 @@ const getFirmwareUpdateField = ({ features, updateType, targetVersion, firmwareT
41925
41965
  if (deviceType === hdShared.EDeviceType.Pro) {
41926
41966
  return latestFirmwareField;
41927
41967
  }
41928
- if (deviceType === hdShared.EDeviceType.Pro2) {
41968
+ if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
41929
41969
  return 'firmware-v1';
41930
41970
  }
41931
41971
  return 'firmware';
@@ -41957,7 +41997,7 @@ const getFirmwareUpdateFieldArray = (features, updateType) => {
41957
41997
  if (deviceType === 'pro') {
41958
41998
  return ['firmware-v8'];
41959
41999
  }
41960
- if (deviceType === 'pro2') {
42000
+ if (deviceType === 'pro2' || deviceType === 'neo') {
41961
42001
  return ['firmware-v1'];
41962
42002
  }
41963
42003
  return ['firmware'];
@@ -47688,9 +47728,11 @@ class CheckAllFirmwareRelease extends BaseMethod {
47688
47728
  });
47689
47729
  }
47690
47730
  runProtocolV2() {
47731
+ var _a;
47691
47732
  return __awaiter(this, void 0, void 0, function* () {
47692
- const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
47693
- .payload;
47733
+ const { checkFirmwareHash = false, firmwareType: firmwareTypeParam, platform, forceUpdateTargets, protocolV2ForceUpdateTargets, } = this.payload;
47734
+ const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
47735
+ const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(protocolV2ForceUpdateTargets);
47694
47736
  const { state, features, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
47695
47737
  device: this.device,
47696
47738
  firmwareType: firmwareTypeParam,
@@ -47709,10 +47751,54 @@ class CheckAllFirmwareRelease extends BaseMethod {
47709
47751
  const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
47710
47752
  const resourceStatus = 'unknown';
47711
47753
  const resourcePreparationRequired = !!resourceSource;
47754
+ const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
47755
+ ? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
47756
+ : plan.targetsToUpdate;
47757
+ const componentTargetsToUpdate = Array.from(new Set([
47758
+ ...detectedComponentTargets,
47759
+ ...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
47760
+ ]));
47761
+ const forceResourceUpdate = validatedForceUpdateTargets.includes('resource') ||
47762
+ validatedProtocolV2ForceUpdateTargets.includes('resource');
47712
47763
  const targetsToUpdate = Array.from(new Set([
47713
- ...plan.targetsToUpdate,
47714
- ...(resourcePreparationRequired ? ['resource'] : []),
47764
+ ...componentTargetsToUpdate,
47765
+ ...(resourcePreparationRequired || forceResourceUpdate ? ['resource'] : []),
47715
47766
  ]));
47767
+ let firmwareUpdatePlan;
47768
+ try {
47769
+ const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
47770
+ const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
47771
+ const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
47772
+ const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
47773
+ if (shouldBuildFirmwareUpdatePlan) {
47774
+ const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
47775
+ features,
47776
+ firmwareType,
47777
+ platform: canBindPreparedPlan ? requestedPlatform : 'web',
47778
+ release,
47779
+ targetsToUpdate,
47780
+ forceUpdateTargets: validatedForceUpdateTargets,
47781
+ resourceArchive: resourceSource,
47782
+ });
47783
+ firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
47784
+ if (!canBindPreparedPlan) {
47785
+ Log$c.warn('[CheckAllFirmwareRelease] Protocol V2 device identity is unavailable; using the release result without a prepared Plan');
47786
+ }
47787
+ }
47788
+ else {
47789
+ firmwareUpdatePlan = undefined;
47790
+ }
47791
+ }
47792
+ catch (error) {
47793
+ if (validatedForceUpdateTargets.length > 0 ||
47794
+ validatedProtocolV2ForceUpdateTargets.length > 0 ||
47795
+ !(error instanceof hdShared.HardwareError) ||
47796
+ ((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
47797
+ throw error;
47798
+ }
47799
+ Log$c.warn('[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result');
47800
+ firmwareUpdatePlan = undefined;
47801
+ }
47716
47802
  const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
47717
47803
  const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
47718
47804
  const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
@@ -47728,7 +47814,8 @@ class CheckAllFirmwareRelease extends BaseMethod {
47728
47814
  state,
47729
47815
  release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
47730
47816
  }), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
47731
- resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: plan.hasUpgrade || resourcePreparationRequired, targetsToUpdate });
47817
+ resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
47818
+ firmwareUpdatePlan });
47732
47819
  });
47733
47820
  }
47734
47821
  }
@@ -51151,6 +51238,9 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
51151
51238
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
51152
51239
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
51153
51240
  const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
51241
+ const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
51242
+ const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
51243
+ const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
51154
51244
  const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
51155
51245
  function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
51156
51246
  var _a;
@@ -51404,7 +51494,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51404
51494
  return ['V2'];
51405
51495
  }
51406
51496
  init() {
51407
- var _a, _b, _c;
51497
+ var _a, _b;
51408
51498
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
51409
51499
  this.requireDeviceMode = [];
51410
51500
  this.unlockPolicy = 'unlock-before-run';
@@ -51439,33 +51529,24 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51439
51529
  { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
51440
51530
  { name: 'platform', type: 'string' },
51441
51531
  { name: 'expectedDeviceId', type: 'string' },
51442
- { name: 'resourceFiles', type: 'array', allowEmpty: true },
51443
51532
  ]);
51444
51533
  if (payload.expectedDeviceId !== undefined &&
51445
51534
  (payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
51446
51535
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
51447
51536
  }
51448
- const hostBinding = payload.preparedPlan || payload.componentArtifacts || payload.resourceBundleArtifacts
51537
+ const hostBinding = payload.preparedPlan || payload.componentArtifacts
51449
51538
  ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
51450
51539
  : undefined;
51451
51540
  if (hostBinding) {
51541
+ const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
51542
+ const preparedPlan = validateFirmwareUpdatePreparedPlan(payload.preparedPlan);
51452
51543
  assertFirmwareUpdatePreparedPlanBinding({
51453
- preparedPlan: payload.preparedPlan,
51544
+ preparedPlan,
51454
51545
  executor: 'v4',
51455
51546
  platform: payload.platform,
51456
- scopeTargets: [
51457
- 'boot',
51458
- 'app_v1',
51459
- 'app_v2',
51460
- 'coprocessor',
51461
- 'resource',
51462
- 'se01',
51463
- 'se02',
51464
- 'se03',
51465
- 'se04',
51466
- ],
51547
+ scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
51467
51548
  bindings: [
51468
- ...Object.entries((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {}).flatMap(([target, artifact]) => artifact
51549
+ ...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
51469
51550
  ? [
51470
51551
  {
51471
51552
  target: target,
@@ -51473,16 +51554,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51473
51554
  },
51474
51555
  ]
51475
51556
  : []),
51476
- ...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
51477
- target: 'resource',
51478
- logicalName: entry.name,
51479
- artifact: entry.artifact,
51480
- })),
51481
51557
  ],
51482
51558
  });
51483
51559
  }
51484
51560
  this.params = {
51485
- preparedPlan: payload.preparedPlan,
51561
+ preparedPlan: payload.preparedPlan
51562
+ ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
51563
+ : undefined,
51486
51564
  chunkSize: payload.chunkSize,
51487
51565
  forcedUpdateRes: payload.forcedUpdateRes,
51488
51566
  bootloaderBinary: payload.bootloaderBinary,
@@ -51494,15 +51572,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51494
51572
  se02Binary: payload.se02Binary,
51495
51573
  se03Binary: payload.se03Binary,
51496
51574
  se04Binary: payload.se04Binary,
51497
- resourceFiles: payload.resourceFiles,
51498
51575
  firmwareType: payload.firmwareType,
51499
51576
  targetsToUpdate: payload.targetsToUpdate,
51500
51577
  expectedTargetVersions: payload.expectedTargetVersions,
51501
51578
  platform: payload.platform,
51502
51579
  expectedDeviceId: payload.expectedDeviceId,
51503
- artifactReader: (_c = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _c !== void 0 ? _c : payload.artifactReader,
51580
+ artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
51504
51581
  componentArtifacts: payload.componentArtifacts,
51505
- resourceBundleArtifacts: payload.resourceBundleArtifacts,
51506
51582
  };
51507
51583
  }
51508
51584
  getProtocolV2FirmwareChunkSize(direction, filePath) {
@@ -51533,7 +51609,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51533
51609
  });
51534
51610
  }
51535
51611
  runProtocolV2() {
51536
- var _a, _b, _c, _d, _e, _f;
51612
+ var _a, _b, _c, _d;
51537
51613
  return __awaiter(this, void 0, void 0, function* () {
51538
51614
  yield this.captureProtocolV2PhysicalIdentity();
51539
51615
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
@@ -51545,20 +51621,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51545
51621
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
51546
51622
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
51547
51623
  this.validateExpectedTargetVersions();
51548
- if ((this.params.componentArtifacts && Object.keys(this.params.componentArtifacts).length > 0) ||
51549
- ((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
51624
+ if (this.params.preparedPlan) {
51550
51625
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
51551
51626
  }
51552
- const hasExplicitResourceFiles = !!((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length);
51553
- const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
51554
- const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
51627
+ const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
51555
51628
  let fwBinaryMap = [];
51556
51629
  let bootloaderBinary = null;
51557
51630
  let installItems;
51558
- let resourceBundles;
51559
51631
  try {
51560
51632
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51561
- resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
51562
51633
  fwBinaryMap = this.collectExplicitTargetBinaries();
51563
51634
  bootloaderBinary = this.prepareBootloaderBinary();
51564
51635
  const explicitInstallItems = this.buildProtocolV2InstallItems({
@@ -51566,10 +51637,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51566
51637
  fwBinaryMap,
51567
51638
  });
51568
51639
  const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
51569
- const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
51640
+ const needsRemoteFirmware = ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.length)
51570
51641
  ? missingFirmwareTargets.length > 0
51571
- : !this.hasExplicitProtocolV2Payload(explicitInstallItems);
51572
- if (needsPreparedResources) {
51642
+ : explicitInstallItems.length === 0;
51643
+ if (wantsResources) {
51573
51644
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
51574
51645
  firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51575
51646
  });
@@ -51596,7 +51667,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51596
51667
  if (typeof err === 'object' &&
51597
51668
  err !== null &&
51598
51669
  'params' in err &&
51599
- ((_f = err.params) === null || _f === void 0 ? void 0 : _f.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51670
+ ((_d = err.params) === null || _d === void 0 ? void 0 : _d.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51600
51671
  throw err;
51601
51672
  }
51602
51673
  if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
@@ -51604,14 +51675,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51604
51675
  }
51605
51676
  throw normalizeFirmwarePreparationError(err);
51606
51677
  }
51607
- if (!bootloaderBinary &&
51608
- fwBinaryMap.length === 0 &&
51609
- !(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
51610
- !(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
51678
+ if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
51611
51679
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51612
51680
  }
51613
- return this.executeProtocolV2Update(Object.assign(Object.assign({ fwBinaryMap,
51614
- bootloaderBinary }, (installItems ? { installItems } : undefined)), ((resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length) ? { resourceBundles } : undefined)));
51681
+ return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
51682
+ bootloaderBinary }, (installItems ? { installItems } : undefined)));
51615
51683
  });
51616
51684
  }
51617
51685
  openProtocolV2PreparedSource(artifact) {
@@ -51678,39 +51746,87 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51678
51746
  return installSources;
51679
51747
  });
51680
51748
  }
51681
- prepareProtocolV2ResourceSources(firmwareType, features) {
51682
- var _a, _b, _c;
51749
+ prepareProtocolV2ResourceSources() {
51750
+ var _a, _b;
51683
51751
  return __awaiter(this, void 0, void 0, function* () {
51684
- const preparedArtifacts = (_a = this.params.resourceBundleArtifacts) !== null && _a !== void 0 ? _a : [];
51685
- const resourceRequested = ((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource')) || preparedArtifacts.length > 0;
51752
+ const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
51686
51753
  if (!resourceRequested) {
51687
51754
  return [];
51688
51755
  }
51689
- const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
51690
- const descriptors = (_c = release === null || release === void 0 ? void 0 : release.resourceBundles) !== null && _c !== void 0 ? _c : [];
51691
- const artifactByName = new Map(preparedArtifacts.map(item => [item.name, item.artifact]));
51692
- const sources = [];
51693
- for (const descriptor of descriptors) {
51694
- const artifact = artifactByName.get(descriptor.name);
51695
- if (!artifact) {
51696
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle ${descriptor.name} is not prepared`, {
51697
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51698
- artifactName: descriptor.name,
51699
- });
51700
- }
51701
- const devicePath = validateProtocolV2FilesystemPath(descriptor.devicePath, 'resourceBundles[].devicePath');
51702
- sources.push({
51703
- name: descriptor.name,
51704
- source: yield this.openProtocolV2PreparedSource(artifact),
51705
- devicePath,
51706
- version: descriptor.version,
51707
- payloadHash: descriptor.payloadHash,
51708
- headerHash: descriptor.headerHash,
51709
- });
51710
- artifactByName.delete(descriptor.name);
51756
+ const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
51757
+ if (archiveSources) {
51758
+ return archiveSources;
51759
+ }
51760
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51761
+ });
51762
+ }
51763
+ prepareProtocolV2ResourceArchiveSources() {
51764
+ var _a, _b, _c, _d;
51765
+ return __awaiter(this, void 0, void 0, function* () {
51766
+ const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
51767
+ artifact.target === 'resource' &&
51768
+ artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
51769
+ if (archiveArtifacts.length === 0) {
51770
+ return undefined;
51771
+ }
51772
+ if (archiveArtifacts.length !== 1) {
51773
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51711
51774
  }
51712
- if (artifactByName.size > 0) {
51713
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 release does not contain resource bundle ${artifactByName.keys().next().value}`);
51775
+ const entries = (_c = archiveArtifacts[0].materializedEntries) !== null && _c !== void 0 ? _c : [];
51776
+ const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
51777
+ if (!manifestEntry ||
51778
+ manifestEntry.artifact.size <= 0 ||
51779
+ manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
51780
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51781
+ }
51782
+ const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
51783
+ let manifestValue;
51784
+ try {
51785
+ manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
51786
+ }
51787
+ catch (error) {
51788
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51789
+ }
51790
+ const manifest = parseProtocolV2ResourceManifest(manifestValue);
51791
+ const selectedFiles = selectProtocolV2ResourceManifestFiles({
51792
+ manifest,
51793
+ targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
51794
+ });
51795
+ if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
51796
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51797
+ }
51798
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
51799
+ const expectedEntryNames = new Set([
51800
+ 'manifest.json',
51801
+ ...selectedFiles.map(file => file.archive_path),
51802
+ ]);
51803
+ if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
51804
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51805
+ }
51806
+ let totalSize = 0;
51807
+ const sources = [];
51808
+ for (const [index, file] of selectedFiles.entries()) {
51809
+ const entry = entriesByName.get(file.archive_path);
51810
+ if (!entry ||
51811
+ entry.artifact.size !== file.size ||
51812
+ entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()) {
51813
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
51814
+ }
51815
+ totalSize += entry.artifact.size;
51816
+ if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
51817
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51818
+ }
51819
+ const source = yield this.openProtocolV2PreparedSource(entry.artifact);
51820
+ const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
51821
+ ? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
51822
+ : null;
51823
+ sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
51824
+ ? {
51825
+ version: header.version,
51826
+ payloadHash: header.payloadHash,
51827
+ headerHash: header.headerHash,
51828
+ }
51829
+ : {})));
51714
51830
  }
51715
51831
  return sources;
51716
51832
  });
@@ -51720,19 +51836,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51720
51836
  try {
51721
51837
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51722
51838
  const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
51723
- const explicitResourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
51724
- const resourceSources = (explicitResourceBundles === null || explicitResourceBundles === void 0 ? void 0 : explicitResourceBundles.length)
51725
- ? yield Promise.all(explicitResourceBundles.map((bundle) => __awaiter(this, void 0, void 0, function* () {
51726
- return ({
51727
- name: bundle.name,
51728
- source: yield this.openProtocolV2MemorySource(bundle.binary),
51729
- devicePath: bundle.devicePath,
51730
- version: bundle.version,
51731
- payloadHash: bundle.payloadHash,
51732
- headerHash: bundle.headerHash,
51733
- });
51734
- })))
51735
- : yield this.prepareProtocolV2ResourceSources(firmwareType, features);
51839
+ const resourceSources = yield this.prepareProtocolV2ResourceSources();
51736
51840
  if (installSources.length === 0 && resourceSources.length === 0) {
51737
51841
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51738
51842
  }
@@ -51816,15 +51920,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51816
51920
  }
51817
51921
  }
51818
51922
  getProtocolV2RequestedTargets() {
51819
- var _a, _b, _c, _d;
51923
+ var _a, _b, _c;
51820
51924
  if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
51821
51925
  return [...new Set(this.params.targetsToUpdate)];
51822
51926
  }
51823
- const targets = new Set();
51824
- Object.keys((_b = this.params.componentArtifacts) !== null && _b !== void 0 ? _b : {}).forEach(target => targets.add(target));
51825
- if (((_c = this.params.resourceBundleArtifacts) === null || _c === void 0 ? void 0 : _c.length) || ((_d = this.params.resourceFiles) === null || _d === void 0 ? void 0 : _d.length)) {
51826
- targets.add('resource');
51927
+ if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
51928
+ return [...new Set(this.params.preparedPlan.targetsToUpdate)];
51827
51929
  }
51930
+ const targets = new Set();
51931
+ Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
51828
51932
  if (this.params.bootloaderBinary)
51829
51933
  targets.add('boot');
51830
51934
  if (this.params.applicationP1Binary)
@@ -51911,10 +52015,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51911
52015
  var _a;
51912
52016
  return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
51913
52017
  }
51914
- hasExplicitProtocolV2Payload(installItems) {
51915
- var _a;
51916
- return !!((_a = this.params.resourceFiles) === null || _a === void 0 ? void 0 : _a.length) || installItems.length > 0;
51917
- }
51918
52018
  getMissingProtocolV2FirmwareTargets(installItems) {
51919
52019
  var _a;
51920
52020
  const preparedTargets = new Set(installItems.flatMap(item => {
@@ -52041,39 +52141,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52041
52141
  };
52042
52142
  });
52043
52143
  }
52044
- prepareExplicitProtocolV2ResourceFiles() {
52045
- var _a;
52046
- const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
52047
- if (!(files === null || files === void 0 ? void 0 : files.length))
52048
- return undefined;
52049
- const prepared = files.map((file, index) => {
52050
- var _a;
52051
- const devicePath = validateProtocolV2FilesystemPath(file.devicePath, `resourceFiles[${index}].devicePath`);
52052
- const descriptor = file;
52053
- if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
52054
- throw new Error(`resourceFiles[${index}] size mismatch`);
52055
- }
52056
- if (descriptor.fileHash &&
52057
- !isProtocolV2ResourceFileValid(file.binary, {
52058
- size: file.binary.byteLength,
52059
- fileHash: descriptor.fileHash,
52060
- })) {
52061
- throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
52062
- }
52063
- const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(file.binary));
52064
- return Object.assign({ name: (_a = devicePath.split('/').pop()) !== null && _a !== void 0 ? _a : devicePath, binary: file.binary, devicePath }, (header
52065
- ? {
52066
- version: header.version,
52067
- payloadHash: header.payloadHash,
52068
- headerHash: header.headerHash,
52069
- }
52070
- : {}));
52071
- });
52072
- if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
52073
- throw new Error('resourceFiles contain duplicate devicePath values');
52074
- }
52075
- return prepared;
52076
- }
52077
52144
  getProtocolV2ResourceFilePath(path) {
52078
52145
  if (path.startsWith('vol'))
52079
52146
  return path;
@@ -52330,7 +52397,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52330
52397
  });
52331
52398
  });
52332
52399
  }
52333
- executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, resourceBundles, }) {
52400
+ executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
52334
52401
  return __awaiter(this, void 0, void 0, function* () {
52335
52402
  const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
52336
52403
  fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
@@ -52345,19 +52412,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52345
52412
  kind: item.kind,
52346
52413
  });
52347
52414
  })));
52348
- const resourceSources = yield Promise.all((resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []).map((bundle) => __awaiter(this, void 0, void 0, function* () {
52349
- return ({
52350
- name: bundle.name,
52351
- source: yield this.openProtocolV2MemorySource(bundle.binary),
52352
- devicePath: bundle.devicePath,
52353
- version: bundle.version,
52354
- payloadHash: bundle.payloadHash,
52355
- headerHash: bundle.headerHash,
52356
- });
52357
- })));
52358
52415
  return yield this.executeProtocolV2Phases({
52359
52416
  installSources,
52360
- resourceSources,
52417
+ resourceSources: [],
52361
52418
  });
52362
52419
  }
52363
52420
  finally {
@@ -64970,6 +65027,108 @@ const switchTransport = ({ env, Transport, plugin, }) => {
64970
65027
  initConnector();
64971
65028
  };
64972
65029
 
65030
+ let memoryHostSequence = 0;
65031
+ const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set([
65032
+ 'boot',
65033
+ 'app_v1',
65034
+ 'app_v2',
65035
+ 'coprocessor',
65036
+ 'se01',
65037
+ 'se02',
65038
+ 'se03',
65039
+ 'se04',
65040
+ ]);
65041
+ const isFirmwareUpdateV4ComponentTarget = (target) => FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target);
65042
+ const createReference = (binary, prefix) => {
65043
+ const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
65044
+ return {
65045
+ artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
65046
+ size: binary.byteLength,
65047
+ sha256: digest,
65048
+ };
65049
+ };
65050
+ function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
65051
+ if (plan.executor !== 'v4') {
65052
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
65053
+ }
65054
+ memoryHostSequence += 1;
65055
+ const hostId = `${Date.now()}:${memoryHostSequence}`;
65056
+ const binaries = new Map();
65057
+ const inputs = artifacts.map((input, artifactIndex) => {
65058
+ var _a;
65059
+ const artifact = createReference(input.binary, `${hostId}:artifact:${artifactIndex}`);
65060
+ binaries.set(artifact.artifactRef, new Uint8Array(input.binary));
65061
+ const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
65062
+ const entryArtifact = createReference(entry.binary, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
65063
+ binaries.set(entryArtifact.artifactRef, new Uint8Array(entry.binary));
65064
+ return {
65065
+ entryName: entry.entryName,
65066
+ artifact: entryArtifact,
65067
+ };
65068
+ });
65069
+ return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
65070
+ });
65071
+ const preparedPlan = sdk.prepareFirmwareUpdatePlan({
65072
+ plan,
65073
+ leaseRef: `fwmemlease:${hostId}`,
65074
+ artifacts: inputs,
65075
+ });
65076
+ const readers = new Map();
65077
+ let readerSequence = 0;
65078
+ const artifactReader = {
65079
+ open({ artifactRef }) {
65080
+ const binary = binaries.get(artifactRef);
65081
+ if (!binary) {
65082
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
65083
+ }
65084
+ readerSequence += 1;
65085
+ const readerId = `fwmemreader:${hostId}:${readerSequence}`;
65086
+ readers.set(readerId, binary);
65087
+ return Promise.resolve({ readerId, size: binary.byteLength });
65088
+ },
65089
+ read({ readerId, offset, length }) {
65090
+ const binary = readers.get(readerId);
65091
+ if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
65092
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
65093
+ }
65094
+ const data = binary.slice(offset, offset + length).buffer;
65095
+ return Promise.resolve({
65096
+ data,
65097
+ bytesRead: data.byteLength,
65098
+ eof: offset + length === binary.byteLength,
65099
+ });
65100
+ },
65101
+ close({ readerId }) {
65102
+ readers.delete(readerId);
65103
+ return Promise.resolve();
65104
+ },
65105
+ };
65106
+ const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({ artifactReader });
65107
+ const componentArtifacts = {};
65108
+ const expectedTargetVersions = {};
65109
+ for (const artifact of preparedPlan.artifacts) {
65110
+ if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
65111
+ componentArtifacts[artifact.target] = artifact.artifact;
65112
+ }
65113
+ if (artifact.targetVersion) {
65114
+ expectedTargetVersions[artifact.target] = artifact.targetVersion;
65115
+ }
65116
+ }
65117
+ return {
65118
+ preparedPlan,
65119
+ hostBindingGeneration,
65120
+ targetsToUpdate: [...preparedPlan.targetsToUpdate],
65121
+ expectedDeviceId: preparedPlan.deviceIdentity,
65122
+ expectedTargetVersions,
65123
+ componentArtifacts,
65124
+ release: () => {
65125
+ sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
65126
+ readers.clear();
65127
+ binaries.clear();
65128
+ },
65129
+ };
65130
+ }
65131
+
64973
65132
  const HardwareSdk = ({ init, call, dispose, eventEmitter, uiResponse, cancel, updateSettings, switchTransport, }) => inject({
64974
65133
  init,
64975
65134
  call,
@@ -65107,7 +65266,7 @@ exports.parseMessage = parseMessage;
65107
65266
  exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
65108
65267
  exports.patchFeatures = patchFeatures;
65109
65268
  exports.preloadSessionCache = preloadSessionCache;
65110
- exports.prepareProtocolV2ResourceFiles = prepareProtocolV2ResourceFiles;
65269
+ exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
65111
65270
  exports.projectDeviceStateFeatures = projectFeatures;
65112
65271
  exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
65113
65272
  exports.safeThrowError = safeThrowError;