@onekeyfe/hd-core 1.2.0-alpha.84 → 1.2.0-alpha.86

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 (58) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +69 -26
  2. package/__tests__/check-firmware-release-protocol-v2.test.ts +1 -2
  3. package/__tests__/firmware-memory-host.test.ts +108 -0
  4. package/__tests__/firmware-update/device-update-bootloader.test.ts +4 -1
  5. package/__tests__/firmware-update/firmware-host-binding.test.ts +9 -0
  6. package/__tests__/firmware-update/firmware-update-plan.test.ts +15 -70
  7. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +53 -1
  8. package/__tests__/protocol-v2-resources.test.ts +59 -39
  9. package/__tests__/protocol-v2.test.ts +255 -306
  10. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  11. package/dist/api/FirmwareUpdateV4.d.ts +1 -2
  12. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  13. package/dist/api/firmware/FirmwareHostBinding.d.ts +1 -1
  14. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -1
  15. package/dist/api/firmware/FirmwareMemoryHost.d.ts +27 -0
  16. package/dist/api/firmware/FirmwareMemoryHost.d.ts.map +1 -0
  17. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +3 -4
  18. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -1
  19. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -1
  20. package/dist/api/firmware/getBinary.d.ts +0 -1
  21. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  22. package/dist/data-manager/DataManager.d.ts +3 -1
  23. package/dist/data-manager/DataManager.d.ts.map +1 -1
  24. package/dist/index.d.ts +32 -70
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +450 -390
  27. package/dist/inject.d.ts.map +1 -1
  28. package/dist/protocols/protocol-v2/resources.d.ts +0 -17
  29. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  30. package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -1
  31. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  32. package/dist/types/api/export.d.ts +0 -1
  33. package/dist/types/api/export.d.ts.map +1 -1
  34. package/dist/types/api/firmwareUpdate.d.ts +1 -10
  35. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  36. package/dist/types/api/index.d.ts +0 -2
  37. package/dist/types/api/index.d.ts.map +1 -1
  38. package/dist/types/settings.d.ts +3 -15
  39. package/dist/types/settings.d.ts.map +1 -1
  40. package/package.json +4 -4
  41. package/src/api/CheckAllFirmwareRelease.ts +4 -13
  42. package/src/api/FirmwareUpdateV4.ts +166 -170
  43. package/src/api/firmware/FirmwareHostBinding.ts +16 -3
  44. package/src/api/firmware/FirmwareMemoryHost.ts +174 -0
  45. package/src/api/firmware/FirmwareUpdatePlan.ts +28 -48
  46. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +8 -1
  47. package/src/data-manager/DataManager.ts +33 -13
  48. package/src/index.ts +6 -1
  49. package/src/inject.ts +0 -2
  50. package/src/protocols/protocol-v2/resources.ts +0 -47
  51. package/src/types/api/checkAllFirmwareRelease.ts +0 -1
  52. package/src/types/api/export.ts +0 -4
  53. package/src/types/api/firmwareUpdate.ts +2 -15
  54. package/src/types/api/index.ts +0 -2
  55. package/src/types/settings.ts +3 -25
  56. package/dist/types/api/protocolV2ResourceManifest.d.ts +0 -17
  57. package/dist/types/api/protocolV2ResourceManifest.d.ts.map +0 -1
  58. package/src/types/api/protocolV2ResourceManifest.ts +0 -19
package/dist/index.js CHANGED
@@ -798,7 +798,7 @@ const getExecutor = (features) => {
798
798
  }
799
799
  return 'v2';
800
800
  };
801
- const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, componentTargets: selectedComponentTargets, } = {}) => {
801
+ const buildProtocolV2Artifacts = (release, { includeComponents = true, componentTargets: selectedComponentTargets, } = {}) => {
802
802
  var _a;
803
803
  const components = asRecord(release.components);
804
804
  if (includeComponents && !components) {
@@ -842,26 +842,6 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
842
842
  })), (asVersion(component.version) ? { targetVersion: asVersion(component.version) } : {})));
843
843
  targets.push(target);
844
844
  }
845
- const bundles = includeResources && Array.isArray(release.resourceBundles) ? release.resourceBundles : [];
846
- const resourceBundleNames = new Set();
847
- for (const value of bundles) {
848
- const bundle = asRecord(value);
849
- const name = asString(bundle === null || bundle === void 0 ? void 0 : bundle.name);
850
- if (!bundle || !name) {
851
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource bundle is invalid', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
852
- }
853
- if (resourceBundleNames.has(name)) {
854
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle duplicates name ${name}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
855
- }
856
- resourceBundleNames.add(name);
857
- 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({
858
- size: bundle.expectedSize,
859
- sha256: bundle.fingerprint,
860
- })));
861
- }
862
- if (bundles.length > 0) {
863
- targets.push('resource');
864
- }
865
845
  return { artifacts, targets: [...new Set(targets)] };
866
846
  };
867
847
  const isForcedTargetRepresented = ({ executor, forcedTarget, artifacts, targetsToUpdate, }) => {
@@ -913,7 +893,7 @@ const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifact
913
893
  };
914
894
  return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
915
895
  };
916
- const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchiveAvailable, }) => {
896
+ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchive, }) => {
917
897
  const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
918
898
  if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
919
899
  planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
@@ -925,9 +905,24 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
925
905
  }
926
906
  const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
927
907
  includeComponents: requestedComponentTargets.size > 0,
928
- includeResources: false,
929
908
  componentTargets: requestedComponentTargets,
930
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
+ }
931
926
  const representedTargets = new Set(protocolV2.targets);
932
927
  const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
933
928
  if (missingTarget) {
@@ -936,7 +931,7 @@ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, r
936
931
  if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
937
932
  planError('Forced firmware update target firmware is not represented by the plan');
938
933
  }
939
- if (validatedForceTargets.includes('resource') && !resourceArchiveAvailable) {
934
+ if (validatedForceTargets.includes('resource') && !resourceArchive) {
940
935
  planError('Forced firmware update target resource has no Protocol V2 resource archive');
941
936
  }
942
937
  return finalizeFirmwareUpdatePlan({
@@ -968,7 +963,6 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
968
963
  if (executor === 'v4' && (shouldUpdateFirmware || shouldUpdateResource)) {
969
964
  const protocolV2 = buildProtocolV2Artifacts(firmwareRelease !== null && firmwareRelease !== void 0 ? firmwareRelease : {}, {
970
965
  includeComponents: shouldUpdateFirmware,
971
- includeResources: shouldUpdateResource,
972
966
  });
973
967
  artifacts = protocolV2.artifacts;
974
968
  targetsToUpdate = protocolV2.targets;
@@ -1160,7 +1154,7 @@ const prepareFirmwareUpdatePlan = ({ plan: value, leaseRef, artifacts, }) => {
1160
1154
  return Object.assign(Object.assign({}, planWithoutDigest), { preparedPlanDigest: digestPreparedPlan(planWithoutDigest) });
1161
1155
  };
1162
1156
  const validateFirmwareUpdatePreparedPlan = (value) => {
1163
- var _a, _b, _c;
1157
+ var _a, _b, _c, _d;
1164
1158
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
1165
1159
  return preparedPlanError('Firmware prepared plan must be an object');
1166
1160
  }
@@ -1240,7 +1234,13 @@ const validateFirmwareUpdatePreparedPlan = (value) => {
1240
1234
  artifactIds.add(artifact.artifactId);
1241
1235
  artifactTargets.add(artifact.target);
1242
1236
  assertFirmwareArtifactReference(artifact.artifact);
1243
- (_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
+ }
1244
1244
  }
1245
1245
  if (preparedPlan.targetsToUpdate.some(target => !FIRMWARE_UPDATE_PLAN_TARGETS.has(target)) ||
1246
1246
  new Set(preparedPlan.targetsToUpdate).size !== preparedPlan.targetsToUpdate.length ||
@@ -1335,201 +1335,6 @@ const assertFirmwareUpdatePreparedPlanBinding = ({ preparedPlan: value, executor
1335
1335
  return preparedPlan;
1336
1336
  };
1337
1337
 
1338
- const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
1339
- const SHA256_HEX_LENGTH = 64;
1340
- function normalizeHex$1(value, expectedLength, field) {
1341
- if (typeof value !== 'string') {
1342
- throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
1343
- }
1344
- const normalized = value.replace(/^0x/i, '').toLowerCase();
1345
- if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
1346
- throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
1347
- }
1348
- return normalized;
1349
- }
1350
- function parseProtocolV2Resources(value) {
1351
- if (value === undefined)
1352
- return undefined;
1353
- if (!value || typeof value !== 'object') {
1354
- throw new Error('Invalid Pro2 resources config');
1355
- }
1356
- const { source } = value;
1357
- if (!source || typeof source !== 'object') {
1358
- throw new Error('Invalid Pro2 resources config: source is required');
1359
- }
1360
- const { archiveUrl, archiveSha256, archiveSize } = source;
1361
- if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
1362
- throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
1363
- }
1364
- if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
1365
- throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
1366
- }
1367
- if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
1368
- throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
1369
- }
1370
- return {
1371
- source: {
1372
- archiveUrl,
1373
- archiveSha256: archiveSha256.toLowerCase(),
1374
- archiveSize: archiveSize,
1375
- },
1376
- };
1377
- }
1378
- const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
1379
- 'vol0:/bundles/',
1380
- 'vol0:/loaders/rom/',
1381
- ];
1382
- function isAllowedManifestDevicePath(path) {
1383
- if (!path.endsWith('.okpkg') ||
1384
- path.includes('\\') ||
1385
- path.includes('//') ||
1386
- path.split('/').some(part => part === '.' || part === '..')) {
1387
- return false;
1388
- }
1389
- if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
1390
- return true;
1391
- }
1392
- return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
1393
- }
1394
- function assertManifestString(value, field) {
1395
- if (typeof value !== 'string' || value.length === 0) {
1396
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
1397
- }
1398
- return value;
1399
- }
1400
- function assertManifestRelativePath(value, field) {
1401
- const path = assertManifestString(value, field);
1402
- if (path.startsWith('/') ||
1403
- path.includes('\\') ||
1404
- path.includes(':') ||
1405
- path.split('/').some(part => !part || part === '.' || part === '..')) {
1406
- throw new Error(`Invalid Pro2 resource manifest ${field}`);
1407
- }
1408
- return path;
1409
- }
1410
- function parseProtocolV2ResourceManifestFile(value, index) {
1411
- var _a;
1412
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
1413
- throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
1414
- }
1415
- const file = value;
1416
- const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
1417
- const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
1418
- if (originalName.includes('/')) {
1419
- throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
1420
- }
1421
- const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
1422
- if (!isAllowedManifestDevicePath(devicePath)) {
1423
- throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
1424
- }
1425
- if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
1426
- throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
1427
- }
1428
- const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
1429
- if (file.signed !== true) {
1430
- throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
1431
- }
1432
- if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
1433
- throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
1434
- }
1435
- if (file.payload_version !== null && typeof file.payload_version !== 'string') {
1436
- throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
1437
- }
1438
- if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
1439
- throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
1440
- }
1441
- return {
1442
- archive_path: archivePath,
1443
- original_name: originalName,
1444
- device_path: devicePath,
1445
- size: Number(file.size),
1446
- sha256: digest,
1447
- signed: true,
1448
- sig_algo: file.sig_algo,
1449
- payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
1450
- };
1451
- }
1452
- function parseProtocolV2ResourceManifest(value) {
1453
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
1454
- throw new Error('Invalid Pro2 resource manifest');
1455
- }
1456
- const manifest = value;
1457
- if (manifest.schema !== 1 ||
1458
- manifest.variant !== 'resource' ||
1459
- manifest.device_root !== 'vol0:' ||
1460
- manifest.restore_mode !== 'bootloader_update' ||
1461
- !Array.isArray(manifest.trees) ||
1462
- !Array.isArray(manifest.files)) {
1463
- throw new Error('Invalid Pro2 resource manifest contract');
1464
- }
1465
- const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
1466
- const devicePaths = new Set(files.map(file => file.device_path));
1467
- const archivePaths = new Set(files.map(file => file.archive_path));
1468
- if (files.length === 0 ||
1469
- devicePaths.size !== files.length ||
1470
- archivePaths.size !== files.length ||
1471
- !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
1472
- !files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
1473
- throw new Error('Invalid Pro2 resource manifest file set');
1474
- }
1475
- return {
1476
- schema: 1,
1477
- artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
1478
- release_name: assertManifestString(manifest.release_name, 'release_name'),
1479
- variant: 'resource',
1480
- commit: assertManifestString(manifest.commit, 'commit'),
1481
- short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
1482
- timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
1483
- core_version: assertManifestString(manifest.core_version, 'core_version'),
1484
- key_set: assertManifestString(manifest.key_set, 'key_set'),
1485
- device_root: 'vol0:',
1486
- restore_mode: 'bootloader_update',
1487
- trees: manifest.trees.map((tree, index) => {
1488
- if (!tree || typeof tree !== 'object') {
1489
- throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
1490
- }
1491
- const item = tree;
1492
- return {
1493
- path: assertManifestRelativePath(item.path, `trees[${index}].path`),
1494
- device: assertManifestString(item.device, `trees[${index}].device`),
1495
- };
1496
- }),
1497
- files,
1498
- };
1499
- }
1500
- function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
1501
- return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
1502
- }
1503
- function prepareProtocolV2ResourceFiles({ manifest: value, files, targetsToUpdate, }) {
1504
- const manifest = parseProtocolV2ResourceManifest(value);
1505
- const selected = selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate });
1506
- const binaries = new Map(files.map(file => [file.archivePath, file.binary]));
1507
- return selected.map(file => {
1508
- const binary = binaries.get(file.archive_path);
1509
- if (!binary ||
1510
- !isProtocolV2ResourceFileValid(binary, {
1511
- size: file.size,
1512
- fileHash: file.sha256,
1513
- })) {
1514
- throw new Error(`Pro2 resource manifest file verification failed: ${file.archive_path}`);
1515
- }
1516
- return {
1517
- binary,
1518
- devicePath: file.device_path,
1519
- size: file.size,
1520
- fileHash: file.sha256,
1521
- };
1522
- });
1523
- }
1524
- function bytesToHex$3(bytes) {
1525
- return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
1526
- }
1527
- function isProtocolV2ResourceFileValid(binary, resource) {
1528
- if (binary.byteLength !== resource.size)
1529
- return false;
1530
- return bytesToHex$3(sha256.sha256(new Uint8Array(binary))) === resource.fileHash.toLowerCase();
1531
- }
1532
-
1533
1338
  const bindingError = (message) => {
1534
1339
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, message, {
1535
1340
  firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
@@ -1542,6 +1347,8 @@ class FirmwareHostBindingRegistry {
1542
1347
  register(binding) {
1543
1348
  var _a;
1544
1349
  if (!binding ||
1350
+ typeof binding.preparedPlanDigest !== 'string' ||
1351
+ !/^[0-9a-f]{64}$/i.test(binding.preparedPlanDigest) ||
1545
1352
  typeof ((_a = binding.artifactReader) === null || _a === void 0 ? void 0 : _a.open) !== 'function' ||
1546
1353
  typeof binding.artifactReader.read !== 'function' ||
1547
1354
  typeof binding.artifactReader.close !== 'function') {
@@ -1562,7 +1369,7 @@ class FirmwareHostBindingRegistry {
1562
1369
  getGeneration() {
1563
1370
  return this.generation;
1564
1371
  }
1565
- resolve(generation) {
1372
+ resolve(generation, preparedPlanDigest) {
1566
1373
  if (!Number.isSafeInteger(generation) ||
1567
1374
  generation <= 0 ||
1568
1375
  generation !== this.generation ||
@@ -1570,12 +1377,17 @@ class FirmwareHostBindingRegistry {
1570
1377
  return bindingError(`Firmware host binding generation ${generation} is stale`);
1571
1378
  }
1572
1379
  const { binding } = this;
1380
+ if (preparedPlanDigest !== undefined &&
1381
+ binding.preparedPlanDigest.toLowerCase() !== preparedPlanDigest.toLowerCase()) {
1382
+ return bindingError(`Firmware host binding generation ${generation} does not match the prepared plan`);
1383
+ }
1573
1384
  const assertCurrent = () => {
1574
1385
  if (generation !== this.generation || binding !== this.binding) {
1575
1386
  bindingError(`Firmware host binding generation ${generation} is stale`);
1576
1387
  }
1577
1388
  };
1578
1389
  return {
1390
+ preparedPlanDigest: binding.preparedPlanDigest,
1579
1391
  artifactReader: {
1580
1392
  open: (input) => __awaiter(this, void 0, void 0, function* () {
1581
1393
  assertCurrent();
@@ -1608,7 +1420,7 @@ const firmwareHostBindingRegistry = new FirmwareHostBindingRegistry();
1608
1420
  const registerFirmwareUpdateHostBinding = (binding) => firmwareHostBindingRegistry.register(binding);
1609
1421
  const unregisterFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.unregister(generation);
1610
1422
  const getFirmwareUpdateHostBindingGeneration = () => firmwareHostBindingRegistry.getGeneration();
1611
- const resolveFirmwareUpdateHostBinding = (generation) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN);
1423
+ const resolveFirmwareUpdateHostBinding = (generation, preparedPlanDigest) => firmwareHostBindingRegistry.resolve(generation !== null && generation !== void 0 ? generation : Number.NaN, preparedPlanDigest);
1612
1424
 
1613
1425
  const callbackManager = new Map();
1614
1426
  const generateCallbackId = () => `callback_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
@@ -1679,7 +1491,6 @@ const createCoreApi = (call) => ({
1679
1491
  getFirmwareUpdateHostBindingGeneration,
1680
1492
  prepareFirmwareUpdatePlan,
1681
1493
  validateFirmwareUpdatePreparedPlan,
1682
- prepareProtocolV2ResourceFiles,
1683
1494
  getLogs: () => call({ method: 'getLogs' }),
1684
1495
  clearSessionCache: params => call(Object.assign(Object.assign({}, params), { method: 'clearSessionCache' })),
1685
1496
  searchDevices: params => call(Object.assign(Object.assign({}, params), { method: 'searchDevices' })),
@@ -40770,6 +40581,172 @@ const findLatestRelease = (releases) => {
40770
40581
  return leastRelease;
40771
40582
  };
40772
40583
 
40584
+ const PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1 = 'vol0:/loaders/bootloader/boot_resource.okpkg';
40585
+ const SHA256_HEX_LENGTH = 64;
40586
+ function normalizeHex$1(value, expectedLength, field) {
40587
+ if (typeof value !== 'string') {
40588
+ throw new Error(`Invalid Pro2 resource ${field}: expected a hexadecimal string`);
40589
+ }
40590
+ const normalized = value.replace(/^0x/i, '').toLowerCase();
40591
+ if (normalized.length !== expectedLength || !/^[0-9a-f]+$/.test(normalized)) {
40592
+ throw new Error(`Invalid Pro2 resource ${field}: expected ${expectedLength} hexadecimal characters`);
40593
+ }
40594
+ return normalized;
40595
+ }
40596
+ function parseProtocolV2Resources(value) {
40597
+ if (value === undefined)
40598
+ return undefined;
40599
+ if (!value || typeof value !== 'object') {
40600
+ throw new Error('Invalid Pro2 resources config');
40601
+ }
40602
+ const { source } = value;
40603
+ if (!source || typeof source !== 'object') {
40604
+ throw new Error('Invalid Pro2 resources config: source is required');
40605
+ }
40606
+ const { archiveUrl, archiveSha256, archiveSize } = source;
40607
+ if (typeof archiveUrl !== 'string' || !archiveUrl.startsWith('https://')) {
40608
+ throw new Error('Invalid Pro2 resources config: source.archiveUrl must use HTTPS');
40609
+ }
40610
+ if (typeof archiveSha256 !== 'string' || !/^[0-9a-fA-F]{64}$/.test(archiveSha256)) {
40611
+ throw new Error('Invalid Pro2 resources config: source.archiveSha256 must be a SHA-256 digest');
40612
+ }
40613
+ if (!Number.isSafeInteger(archiveSize) || archiveSize <= 0) {
40614
+ throw new Error('Invalid Pro2 resources config: source.archiveSize must be a positive integer');
40615
+ }
40616
+ return {
40617
+ source: {
40618
+ archiveUrl,
40619
+ archiveSha256: archiveSha256.toLowerCase(),
40620
+ archiveSize: archiveSize,
40621
+ },
40622
+ };
40623
+ }
40624
+ const PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS = [
40625
+ 'vol0:/bundles/',
40626
+ 'vol0:/loaders/rom/',
40627
+ ];
40628
+ function isAllowedManifestDevicePath(path) {
40629
+ if (!path.endsWith('.okpkg') ||
40630
+ path.includes('\\') ||
40631
+ path.includes('//') ||
40632
+ path.split('/').some(part => part === '.' || part === '..')) {
40633
+ return false;
40634
+ }
40635
+ if (path === PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) {
40636
+ return true;
40637
+ }
40638
+ return PROTOCOL_V2_RESOURCE_MANIFEST_DEVICE_ROOTS.some(root => path.startsWith(root));
40639
+ }
40640
+ function assertManifestString(value, field) {
40641
+ if (typeof value !== 'string' || value.length === 0) {
40642
+ throw new Error(`Invalid Pro2 resource manifest ${field}`);
40643
+ }
40644
+ return value;
40645
+ }
40646
+ function assertManifestRelativePath(value, field) {
40647
+ const path = assertManifestString(value, field);
40648
+ if (path.startsWith('/') ||
40649
+ path.includes('\\') ||
40650
+ path.includes(':') ||
40651
+ path.split('/').some(part => !part || part === '.' || part === '..')) {
40652
+ throw new Error(`Invalid Pro2 resource manifest ${field}`);
40653
+ }
40654
+ return path;
40655
+ }
40656
+ function parseProtocolV2ResourceManifestFile(value, index) {
40657
+ var _a;
40658
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
40659
+ throw new Error(`Invalid Pro2 resource manifest files[${index}]`);
40660
+ }
40661
+ const file = value;
40662
+ const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
40663
+ const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
40664
+ if (originalName.includes('/')) {
40665
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
40666
+ }
40667
+ const devicePath = assertManifestString(file.device_path, `files[${index}].device_path`);
40668
+ if (!isAllowedManifestDevicePath(devicePath)) {
40669
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].device_path`);
40670
+ }
40671
+ if (!Number.isSafeInteger(file.size) || Number(file.size) <= 0) {
40672
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
40673
+ }
40674
+ const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
40675
+ if (file.signed !== true) {
40676
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
40677
+ }
40678
+ if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
40679
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
40680
+ }
40681
+ if (file.payload_version !== null && typeof file.payload_version !== 'string') {
40682
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
40683
+ }
40684
+ if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
40685
+ throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
40686
+ }
40687
+ return {
40688
+ archive_path: archivePath,
40689
+ original_name: originalName,
40690
+ device_path: devicePath,
40691
+ size: Number(file.size),
40692
+ sha256: digest,
40693
+ signed: true,
40694
+ sig_algo: file.sig_algo,
40695
+ payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
40696
+ };
40697
+ }
40698
+ function parseProtocolV2ResourceManifest(value) {
40699
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
40700
+ throw new Error('Invalid Pro2 resource manifest');
40701
+ }
40702
+ const manifest = value;
40703
+ if (manifest.schema !== 1 ||
40704
+ manifest.variant !== 'resource' ||
40705
+ manifest.device_root !== 'vol0:' ||
40706
+ manifest.restore_mode !== 'bootloader_update' ||
40707
+ !Array.isArray(manifest.trees) ||
40708
+ !Array.isArray(manifest.files)) {
40709
+ throw new Error('Invalid Pro2 resource manifest contract');
40710
+ }
40711
+ const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
40712
+ const devicePaths = new Set(files.map(file => file.device_path));
40713
+ const archivePaths = new Set(files.map(file => file.archive_path));
40714
+ if (files.length === 0 ||
40715
+ devicePaths.size !== files.length ||
40716
+ archivePaths.size !== files.length ||
40717
+ !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
40718
+ !files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
40719
+ throw new Error('Invalid Pro2 resource manifest file set');
40720
+ }
40721
+ return {
40722
+ schema: 1,
40723
+ artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
40724
+ release_name: assertManifestString(manifest.release_name, 'release_name'),
40725
+ variant: 'resource',
40726
+ commit: assertManifestString(manifest.commit, 'commit'),
40727
+ short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
40728
+ timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
40729
+ core_version: assertManifestString(manifest.core_version, 'core_version'),
40730
+ key_set: assertManifestString(manifest.key_set, 'key_set'),
40731
+ device_root: 'vol0:',
40732
+ restore_mode: 'bootloader_update',
40733
+ trees: manifest.trees.map((tree, index) => {
40734
+ if (!tree || typeof tree !== 'object') {
40735
+ throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
40736
+ }
40737
+ const item = tree;
40738
+ return {
40739
+ path: assertManifestRelativePath(item.path, `trees[${index}].path`),
40740
+ device: assertManifestString(item.device, `trees[${index}].device`),
40741
+ };
40742
+ }),
40743
+ files,
40744
+ };
40745
+ }
40746
+ function selectProtocolV2ResourceManifestFiles({ manifest, targetsToUpdate, }) {
40747
+ return targetsToUpdate.includes('resource') ? [...manifest.files] : [];
40748
+ }
40749
+
40773
40750
  var _a$1;
40774
40751
  const FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS = 5 * 60 * 1000;
40775
40752
  const Log$k = getLogger(exports.LoggerNames.Core);
@@ -40828,6 +40805,7 @@ class DataManager {
40828
40805
  return __awaiter(this, void 0, void 0, function* () {
40829
40806
  this.settings = settings;
40830
40807
  this.protocolV2ResourcesConfigError = undefined;
40808
+ this.protocolV2NeoResourcesConfigError = undefined;
40831
40809
  const manifestMode = (_b = settings.firmwareManifestMode) !== null && _b !== void 0 ? _b : (settings.fetchConfig ? 'sdk-managed' : undefined);
40832
40810
  if (settings.preloadedConfig) {
40833
40811
  this.applyRemoteConfig(settings.preloadedConfig);
@@ -40888,12 +40866,19 @@ class DataManager {
40888
40866
  let neoResources;
40889
40867
  try {
40890
40868
  pro2Resources = parseProtocolV2Resources((_b = data.pro2) === null || _b === void 0 ? void 0 : _b.resources);
40891
- neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
40892
40869
  }
40893
40870
  catch (error) {
40894
40871
  this.protocolV2ResourcesConfigError =
40895
40872
  error instanceof Error ? error : new Error(String(error));
40896
- Log$k.warn('[DataConfig] Ignoring invalid Protocol V2 resources config:', error);
40873
+ Log$k.warn('[DataConfig] Ignoring invalid Pro2 resources config:', error);
40874
+ }
40875
+ try {
40876
+ neoResources = parseProtocolV2Resources((_c = data.neo) === null || _c === void 0 ? void 0 : _c.resources);
40877
+ }
40878
+ catch (error) {
40879
+ this.protocolV2NeoResourcesConfigError =
40880
+ error instanceof Error ? error : new Error(String(error));
40881
+ Log$k.warn('[DataConfig] Ignoring invalid Neo resources config:', error);
40897
40882
  }
40898
40883
  const enrichedPro2Config = this.enrichFirmwareReleaseInfo(data.pro2);
40899
40884
  const enrichedNeoConfig = this.enrichFirmwareReleaseInfo(data.neo);
@@ -40931,16 +40916,20 @@ class DataManager {
40931
40916
  }
40932
40917
  });
40933
40918
  }
40934
- static forceReloadData({ requireResources = false, } = {}) {
40919
+ static forceReloadData({ requireResources = false, resourceDeviceType = hdShared.EDeviceType.Pro2, } = {}) {
40935
40920
  return __awaiter(this, void 0, void 0, function* () {
40921
+ const resourceDeviceName = resourceDeviceType === hdShared.EDeviceType.Pro2 ? 'Pro2' : 'Neo';
40936
40922
  if (!this.settings) {
40937
40923
  throw new Error('Remote config settings are not initialized');
40938
40924
  }
40939
40925
  const hasFreshConfig = this.lastCheckTimestamp > 0 &&
40940
40926
  getTimeStamp() - this.lastCheckTimestamp <= FIRMWARE_UPDATE_CONFIG_FRESHNESS_MS;
40941
40927
  if (hasFreshConfig) {
40942
- if (requireResources && this.protocolV2ResourcesConfigError) {
40943
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid Pro2 resources config: ${this.protocolV2ResourcesConfigError.message}`);
40928
+ const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
40929
+ ? this.protocolV2ResourcesConfigError
40930
+ : this.protocolV2NeoResourcesConfigError;
40931
+ if (requireResources && resourcesConfigError) {
40932
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
40944
40933
  }
40945
40934
  return;
40946
40935
  }
@@ -40948,8 +40937,11 @@ class DataManager {
40948
40937
  if (!loaded) {
40949
40938
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Unable to refresh the latest remote config');
40950
40939
  }
40951
- if (requireResources && this.protocolV2ResourcesConfigError) {
40952
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid Pro2 resources config: ${this.protocolV2ResourcesConfigError.message}`);
40940
+ const resourcesConfigError = resourceDeviceType === hdShared.EDeviceType.Pro2
40941
+ ? this.protocolV2ResourcesConfigError
40942
+ : this.protocolV2NeoResourcesConfigError;
40943
+ if (requireResources && resourcesConfigError) {
40944
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, `Invalid ${resourceDeviceName} resources config: ${resourcesConfigError.message}`);
40953
40945
  }
40954
40946
  this.lastCheckTimestamp = getTimeStamp();
40955
40947
  });
@@ -40993,12 +40985,10 @@ DataManager.deviceMap = {
40993
40985
  ble: [],
40994
40986
  },
40995
40987
  [hdShared.EDeviceType.Pro2]: {
40996
- firmware: [],
40997
- ble: [],
40988
+ 'firmware-v1': [],
40998
40989
  },
40999
40990
  [hdShared.EDeviceType.Neo]: {
41000
- firmware: [],
41001
- ble: [],
40991
+ 'firmware-v1': [],
41002
40992
  },
41003
40993
  [hdShared.EDeviceType.ClassicPure]: {
41004
40994
  firmware: [],
@@ -47780,7 +47770,6 @@ class CheckAllFirmwareRelease extends BaseMethod {
47780
47770
  const resourceDeviceType = state.identity.deviceType === 'neo' ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2;
47781
47771
  const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
47782
47772
  const resourceStatus = 'unknown';
47783
- const resourcePreparationRequired = !!resourceSource;
47784
47773
  const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
47785
47774
  ? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
47786
47775
  : plan.targetsToUpdate;
@@ -47792,14 +47781,11 @@ class CheckAllFirmwareRelease extends BaseMethod {
47792
47781
  validatedProtocolV2ForceUpdateTargets.includes('resource');
47793
47782
  const targetsToUpdate = Array.from(new Set([
47794
47783
  ...componentTargetsToUpdate,
47795
- ...(resourcePreparationRequired || forceResourceUpdate ? ['resource'] : []),
47784
+ ...(forceResourceUpdate ? ['resource'] : []),
47796
47785
  ]));
47797
47786
  let firmwareUpdatePlan;
47798
47787
  try {
47799
- const shouldBuildFirmwareUpdatePlan = componentTargetsToUpdate.length > 0 ||
47800
- validatedForceUpdateTargets.some(target => target !== 'resource') ||
47801
- validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
47802
- (forceResourceUpdate && !resourcePreparationRequired);
47788
+ const shouldBuildFirmwareUpdatePlan = targetsToUpdate.length > 0;
47803
47789
  const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
47804
47790
  const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
47805
47791
  const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
@@ -47811,7 +47797,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47811
47797
  release,
47812
47798
  targetsToUpdate,
47813
47799
  forceUpdateTargets: validatedForceUpdateTargets,
47814
- resourceArchiveAvailable: resourcePreparationRequired,
47800
+ resourceArchive: resourceSource,
47815
47801
  });
47816
47802
  firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
47817
47803
  if (!canBindPreparedPlan) {
@@ -47835,9 +47821,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47835
47821
  const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
47836
47822
  const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
47837
47823
  const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
47838
- const status = resourcePreparationRequired && (plan.status === 'valid' || plan.status === 'unavailable')
47839
- ? 'unknown'
47840
- : plan.status;
47824
+ const { status } = plan;
47841
47825
  return Object.assign(Object.assign({ firmware: toProtocolV2FirmwareReleaseInfo({ plan: firmwarePlan, state, release }), ble: toProtocolV2FirmwareReleaseInfo({
47842
47826
  plan: blePlan,
47843
47827
  state,
@@ -47847,7 +47831,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47847
47831
  state,
47848
47832
  release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
47849
47833
  }), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
47850
- resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
47834
+ resourceStatus, resourceArchive: resourceSource, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
47851
47835
  firmwareUpdatePlan });
47852
47836
  });
47853
47837
  }
@@ -51271,6 +51255,9 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
51271
51255
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
51272
51256
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
51273
51257
  const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
51258
+ const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
51259
+ const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
51260
+ const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
51274
51261
  const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
51275
51262
  function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
51276
51263
  var _a;
@@ -51524,7 +51511,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51524
51511
  return ['V2'];
51525
51512
  }
51526
51513
  init() {
51527
- var _a, _b, _c;
51514
+ var _a, _b;
51528
51515
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
51529
51516
  this.requireDeviceMode = [];
51530
51517
  this.unlockPolicy = 'unlock-before-run';
@@ -51559,33 +51546,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51559
51546
  { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
51560
51547
  { name: 'platform', type: 'string' },
51561
51548
  { name: 'expectedDeviceId', type: 'string' },
51562
- { name: 'resourceFiles', type: 'array', allowEmpty: true },
51563
51549
  ]);
51564
51550
  if (payload.expectedDeviceId !== undefined &&
51565
51551
  (payload.expectedDeviceId.length === 0 || payload.expectedDeviceId.length > 160)) {
51566
51552
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Protocol V2 expected device identity is invalid');
51567
51553
  }
51568
- const hostBinding = payload.preparedPlan || payload.componentArtifacts || payload.resourceBundleArtifacts
51569
- ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration)
51554
+ const preparedPlan = payload.preparedPlan
51555
+ ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
51556
+ : undefined;
51557
+ const hostBinding = preparedPlan || payload.componentArtifacts
51558
+ ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.preparedPlanDigest)
51570
51559
  : undefined;
51571
51560
  if (hostBinding) {
51561
+ const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
51572
51562
  assertFirmwareUpdatePreparedPlanBinding({
51573
- preparedPlan: payload.preparedPlan,
51563
+ preparedPlan: preparedPlan !== null && preparedPlan !== void 0 ? preparedPlan : payload.preparedPlan,
51574
51564
  executor: 'v4',
51575
51565
  platform: payload.platform,
51576
- scopeTargets: [
51577
- 'boot',
51578
- 'app_v1',
51579
- 'app_v2',
51580
- 'coprocessor',
51581
- 'resource',
51582
- 'se01',
51583
- 'se02',
51584
- 'se03',
51585
- 'se04',
51586
- ],
51566
+ scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
51587
51567
  bindings: [
51588
- ...Object.entries((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {}).flatMap(([target, artifact]) => artifact
51568
+ ...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
51589
51569
  ? [
51590
51570
  {
51591
51571
  target: target,
@@ -51593,16 +51573,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51593
51573
  },
51594
51574
  ]
51595
51575
  : []),
51596
- ...((_b = payload.resourceBundleArtifacts) !== null && _b !== void 0 ? _b : []).map((entry) => ({
51597
- target: 'resource',
51598
- logicalName: entry.name,
51599
- artifact: entry.artifact,
51600
- })),
51601
51576
  ],
51602
51577
  });
51603
51578
  }
51604
51579
  this.params = {
51605
- preparedPlan: payload.preparedPlan,
51580
+ preparedPlan,
51606
51581
  chunkSize: payload.chunkSize,
51607
51582
  forcedUpdateRes: payload.forcedUpdateRes,
51608
51583
  bootloaderBinary: payload.bootloaderBinary,
@@ -51614,15 +51589,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51614
51589
  se02Binary: payload.se02Binary,
51615
51590
  se03Binary: payload.se03Binary,
51616
51591
  se04Binary: payload.se04Binary,
51617
- resourceFiles: payload.resourceFiles,
51618
51592
  firmwareType: payload.firmwareType,
51619
51593
  targetsToUpdate: payload.targetsToUpdate,
51620
51594
  expectedTargetVersions: payload.expectedTargetVersions,
51621
51595
  platform: payload.platform,
51622
51596
  expectedDeviceId: payload.expectedDeviceId,
51623
- artifactReader: (_c = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _c !== void 0 ? _c : payload.artifactReader,
51597
+ artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
51624
51598
  componentArtifacts: payload.componentArtifacts,
51625
- resourceBundleArtifacts: payload.resourceBundleArtifacts,
51626
51599
  };
51627
51600
  }
51628
51601
  getProtocolV2FirmwareChunkSize(direction, filePath) {
@@ -51653,7 +51626,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51653
51626
  });
51654
51627
  }
51655
51628
  runProtocolV2() {
51656
- var _a, _b, _c, _d, _e, _f;
51629
+ var _a, _b, _c, _d;
51657
51630
  return __awaiter(this, void 0, void 0, function* () {
51658
51631
  yield this.captureProtocolV2PhysicalIdentity();
51659
51632
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
@@ -51665,20 +51638,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51665
51638
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
51666
51639
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
51667
51640
  this.validateExpectedTargetVersions();
51668
- if ((this.params.componentArtifacts && Object.keys(this.params.componentArtifacts).length > 0) ||
51669
- ((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
51641
+ if (this.params.preparedPlan) {
51670
51642
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
51671
51643
  }
51672
- const hasExplicitResourceFiles = !!((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length);
51673
- const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
51674
- const needsPreparedResources = !hasExplicitResourceFiles && wantsResources;
51644
+ const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
51675
51645
  let fwBinaryMap = [];
51676
51646
  let bootloaderBinary = null;
51677
51647
  let installItems;
51678
- let resourceBundles;
51679
51648
  try {
51680
51649
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51681
- resourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
51682
51650
  fwBinaryMap = this.collectExplicitTargetBinaries();
51683
51651
  bootloaderBinary = this.prepareBootloaderBinary();
51684
51652
  const explicitInstallItems = this.buildProtocolV2InstallItems({
@@ -51686,10 +51654,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51686
51654
  fwBinaryMap,
51687
51655
  });
51688
51656
  const missingFirmwareTargets = this.getMissingProtocolV2FirmwareTargets(explicitInstallItems);
51689
- const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
51657
+ const needsRemoteFirmware = ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.length)
51690
51658
  ? missingFirmwareTargets.length > 0
51691
- : !this.hasExplicitProtocolV2Payload(explicitInstallItems);
51692
- if (needsPreparedResources) {
51659
+ : explicitInstallItems.length === 0;
51660
+ if (wantsResources) {
51693
51661
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
51694
51662
  firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51695
51663
  });
@@ -51716,7 +51684,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51716
51684
  if (typeof err === 'object' &&
51717
51685
  err !== null &&
51718
51686
  'params' in err &&
51719
- ((_f = err.params) === null || _f === void 0 ? void 0 : _f.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51687
+ ((_d = err.params) === null || _d === void 0 ? void 0 : _d.firmwareUpdateCode) === 'FirmwareArtifactsNotPrepared') {
51720
51688
  throw err;
51721
51689
  }
51722
51690
  if (err instanceof hdShared.HardwareError && err.errorCode === hdShared.HardwareErrorCode.NetworkError) {
@@ -51724,14 +51692,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51724
51692
  }
51725
51693
  throw normalizeFirmwarePreparationError(err);
51726
51694
  }
51727
- if (!bootloaderBinary &&
51728
- fwBinaryMap.length === 0 &&
51729
- !(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
51730
- !(resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length)) {
51695
+ if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
51731
51696
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51732
51697
  }
51733
- return this.executeProtocolV2Update(Object.assign(Object.assign({ fwBinaryMap,
51734
- bootloaderBinary }, (installItems ? { installItems } : undefined)), ((resourceBundles === null || resourceBundles === void 0 ? void 0 : resourceBundles.length) ? { resourceBundles } : undefined)));
51698
+ return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
51699
+ bootloaderBinary }, (installItems ? { installItems } : undefined)));
51735
51700
  });
51736
51701
  }
51737
51702
  openProtocolV2PreparedSource(artifact) {
@@ -51798,39 +51763,87 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51798
51763
  return installSources;
51799
51764
  });
51800
51765
  }
51801
- prepareProtocolV2ResourceSources(firmwareType, features) {
51802
- var _a, _b, _c;
51766
+ prepareProtocolV2ResourceSources() {
51767
+ var _a, _b;
51803
51768
  return __awaiter(this, void 0, void 0, function* () {
51804
- const preparedArtifacts = (_a = this.params.resourceBundleArtifacts) !== null && _a !== void 0 ? _a : [];
51805
- const resourceRequested = ((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource')) || preparedArtifacts.length > 0;
51769
+ const resourceRequested = (_b = (_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) !== null && _b !== void 0 ? _b : false;
51806
51770
  if (!resourceRequested) {
51807
51771
  return [];
51808
51772
  }
51809
- const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
51810
- const descriptors = (_c = release === null || release === void 0 ? void 0 : release.resourceBundles) !== null && _c !== void 0 ? _c : [];
51811
- const artifactByName = new Map(preparedArtifacts.map(item => [item.name, item.artifact]));
51812
- const sources = [];
51813
- for (const descriptor of descriptors) {
51814
- const artifact = artifactByName.get(descriptor.name);
51815
- if (!artifact) {
51816
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 resource bundle ${descriptor.name} is not prepared`, {
51817
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51818
- artifactName: descriptor.name,
51819
- });
51820
- }
51821
- const devicePath = validateProtocolV2FilesystemPath(descriptor.devicePath, 'resourceBundles[].devicePath');
51822
- sources.push({
51823
- name: descriptor.name,
51824
- source: yield this.openProtocolV2PreparedSource(artifact),
51825
- devicePath,
51826
- version: descriptor.version,
51827
- payloadHash: descriptor.payloadHash,
51828
- headerHash: descriptor.headerHash,
51829
- });
51830
- artifactByName.delete(descriptor.name);
51773
+ const archiveSources = yield this.prepareProtocolV2ResourceArchiveSources();
51774
+ if (archiveSources) {
51775
+ return archiveSources;
51831
51776
  }
51832
- if (artifactByName.size > 0) {
51833
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 release does not contain resource bundle ${artifactByName.keys().next().value}`);
51777
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive is not prepared', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51778
+ });
51779
+ }
51780
+ prepareProtocolV2ResourceArchiveSources() {
51781
+ var _a, _b, _c, _d;
51782
+ return __awaiter(this, void 0, void 0, function* () {
51783
+ const archiveArtifacts = (_b = (_a = this.params.preparedPlan) === null || _a === void 0 ? void 0 : _a.artifacts.filter(artifact => artifact.role === 'resourceBundle' &&
51784
+ artifact.target === 'resource' &&
51785
+ artifact.container === 'zip')) !== null && _b !== void 0 ? _b : [];
51786
+ if (archiveArtifacts.length === 0) {
51787
+ return undefined;
51788
+ }
51789
+ if (archiveArtifacts.length !== 1) {
51790
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared plan must contain exactly one resource archive', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51791
+ }
51792
+ const entries = (_c = archiveArtifacts[0].materializedEntries) !== null && _c !== void 0 ? _c : [];
51793
+ const manifestEntry = entries.find(entry => entry.entryName === 'manifest.json');
51794
+ if (!manifestEntry ||
51795
+ manifestEntry.artifact.size <= 0 ||
51796
+ manifestEntry.artifact.size > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
51797
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive has no valid manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51798
+ }
51799
+ const manifestSource = yield this.openProtocolV2PreparedSource(manifestEntry.artifact);
51800
+ let manifestValue;
51801
+ try {
51802
+ manifestValue = JSON.parse(new TextDecoder().decode(yield readFirmwareByteSourceFully(manifestSource)));
51803
+ }
51804
+ catch (error) {
51805
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51806
+ }
51807
+ const manifest = parseProtocolV2ResourceManifest(manifestValue);
51808
+ const selectedFiles = selectProtocolV2ResourceManifestFiles({
51809
+ manifest,
51810
+ targetsToUpdate: (_d = this.params.targetsToUpdate) !== null && _d !== void 0 ? _d : [],
51811
+ });
51812
+ if (selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
51813
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains too many files', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51814
+ }
51815
+ const entriesByName = new Map(entries.map(entry => [entry.entryName, entry]));
51816
+ const expectedEntryNames = new Set([
51817
+ 'manifest.json',
51818
+ ...selectedFiles.map(file => file.archive_path),
51819
+ ]);
51820
+ if (entries.some(entry => !expectedEntryNames.has(entry.entryName))) {
51821
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51822
+ }
51823
+ let totalSize = 0;
51824
+ const sources = [];
51825
+ for (const [index, file] of selectedFiles.entries()) {
51826
+ const entry = entriesByName.get(file.archive_path);
51827
+ if (!entry ||
51828
+ entry.artifact.size !== file.size ||
51829
+ entry.artifact.sha256.toLowerCase() !== file.sha256.toLowerCase()) {
51830
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
51831
+ }
51832
+ totalSize += entry.artifact.size;
51833
+ if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
51834
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 prepared resource archive exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51835
+ }
51836
+ const source = yield this.openProtocolV2PreparedSource(entry.artifact);
51837
+ const header = source.size >= PROTOCOL_V2_OKPP_HEADER_SIZE
51838
+ ? parseProtocolV2OkppHeader(new Uint8Array(yield source.readAt(0, PROTOCOL_V2_OKPP_HEADER_SIZE)))
51839
+ : null;
51840
+ sources.push(Object.assign({ name: file.original_name || `resource-${index}`, source, devicePath: file.device_path }, (header
51841
+ ? {
51842
+ version: header.version,
51843
+ payloadHash: header.payloadHash,
51844
+ headerHash: header.headerHash,
51845
+ }
51846
+ : {})));
51834
51847
  }
51835
51848
  return sources;
51836
51849
  });
@@ -51840,19 +51853,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51840
51853
  try {
51841
51854
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51842
51855
  const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
51843
- const explicitResourceBundles = this.prepareExplicitProtocolV2ResourceFiles();
51844
- const resourceSources = (explicitResourceBundles === null || explicitResourceBundles === void 0 ? void 0 : explicitResourceBundles.length)
51845
- ? yield Promise.all(explicitResourceBundles.map((bundle) => __awaiter(this, void 0, void 0, function* () {
51846
- return ({
51847
- name: bundle.name,
51848
- source: yield this.openProtocolV2MemorySource(bundle.binary),
51849
- devicePath: bundle.devicePath,
51850
- version: bundle.version,
51851
- payloadHash: bundle.payloadHash,
51852
- headerHash: bundle.headerHash,
51853
- });
51854
- })))
51855
- : yield this.prepareProtocolV2ResourceSources(firmwareType, features);
51856
+ const resourceSources = yield this.prepareProtocolV2ResourceSources();
51856
51857
  if (installSources.length === 0 && resourceSources.length === 0) {
51857
51858
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51858
51859
  }
@@ -51936,15 +51937,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51936
51937
  }
51937
51938
  }
51938
51939
  getProtocolV2RequestedTargets() {
51939
- var _a, _b, _c, _d;
51940
+ var _a, _b, _c;
51940
51941
  if ((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.length) {
51941
51942
  return [...new Set(this.params.targetsToUpdate)];
51942
51943
  }
51943
- const targets = new Set();
51944
- Object.keys((_b = this.params.componentArtifacts) !== null && _b !== void 0 ? _b : {}).forEach(target => targets.add(target));
51945
- 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)) {
51946
- targets.add('resource');
51944
+ if ((_b = this.params.preparedPlan) === null || _b === void 0 ? void 0 : _b.targetsToUpdate.length) {
51945
+ return [...new Set(this.params.preparedPlan.targetsToUpdate)];
51947
51946
  }
51947
+ const targets = new Set();
51948
+ Object.keys((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).forEach(target => targets.add(target));
51948
51949
  if (this.params.bootloaderBinary)
51949
51950
  targets.add('boot');
51950
51951
  if (this.params.applicationP1Binary)
@@ -52031,10 +52032,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52031
52032
  var _a;
52032
52033
  return (_a = this.params.bootloaderBinary) !== null && _a !== void 0 ? _a : null;
52033
52034
  }
52034
- hasExplicitProtocolV2Payload(installItems) {
52035
- var _a;
52036
- return !!((_a = this.params.resourceFiles) === null || _a === void 0 ? void 0 : _a.length) || installItems.length > 0;
52037
- }
52038
52035
  getMissingProtocolV2FirmwareTargets(installItems) {
52039
52036
  var _a;
52040
52037
  const preparedTargets = new Set(installItems.flatMap(item => {
@@ -52161,39 +52158,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52161
52158
  };
52162
52159
  });
52163
52160
  }
52164
- prepareExplicitProtocolV2ResourceFiles() {
52165
- var _a;
52166
- const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
52167
- if (!(files === null || files === void 0 ? void 0 : files.length))
52168
- return undefined;
52169
- const prepared = files.map((file, index) => {
52170
- var _a;
52171
- const devicePath = validateProtocolV2FilesystemPath(file.devicePath, `resourceFiles[${index}].devicePath`);
52172
- const descriptor = file;
52173
- if (descriptor.size !== undefined && descriptor.size !== file.binary.byteLength) {
52174
- throw new Error(`resourceFiles[${index}] size mismatch`);
52175
- }
52176
- if (descriptor.fileHash &&
52177
- !isProtocolV2ResourceFileValid(file.binary, {
52178
- size: file.binary.byteLength,
52179
- fileHash: descriptor.fileHash,
52180
- })) {
52181
- throw new Error(`resourceFiles[${index}] SHA-256 mismatch`);
52182
- }
52183
- const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(file.binary));
52184
- return Object.assign({ name: (_a = devicePath.split('/').pop()) !== null && _a !== void 0 ? _a : devicePath, binary: file.binary, devicePath }, (header
52185
- ? {
52186
- version: header.version,
52187
- payloadHash: header.payloadHash,
52188
- headerHash: header.headerHash,
52189
- }
52190
- : {}));
52191
- });
52192
- if (new Set(prepared.map(file => file.devicePath)).size !== prepared.length) {
52193
- throw new Error('resourceFiles contain duplicate devicePath values');
52194
- }
52195
- return prepared;
52196
- }
52197
52161
  getProtocolV2ResourceFilePath(path) {
52198
52162
  if (path.startsWith('vol'))
52199
52163
  return path;
@@ -52201,7 +52165,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52201
52165
  return `vol0:${path}`;
52202
52166
  return `vol0:/${path}`;
52203
52167
  }
52204
- readProtocolV2DeviceFileHeader(path) {
52168
+ readProtocolV2DeviceFileHeader(path, expectedSize) {
52205
52169
  var _a, _b, _c, _d;
52206
52170
  return __awaiter(this, void 0, void 0, function* () {
52207
52171
  const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
@@ -52213,7 +52177,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52213
52177
  if (!((_b = pathInfoRes.message) === null || _b === void 0 ? void 0 : _b.exist) ||
52214
52178
  ((_c = pathInfoRes.message) === null || _c === void 0 ? void 0 : _c.directory) ||
52215
52179
  fileSize === undefined ||
52216
- fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE) {
52180
+ fileSize < PROTOCOL_V2_OKPP_HEADER_SIZE ||
52181
+ (expectedSize !== undefined && fileSize !== expectedSize)) {
52217
52182
  return null;
52218
52183
  }
52219
52184
  const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
@@ -52253,7 +52218,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52253
52218
  if (!bundle.payloadHash || !bundle.headerHash)
52254
52219
  return false;
52255
52220
  try {
52256
- const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath);
52221
+ const header = yield this.readProtocolV2DeviceFileHeader(bundle.devicePath, bundle.source.size);
52257
52222
  if (!header)
52258
52223
  return false;
52259
52224
  if (bundle.version) {
@@ -52450,7 +52415,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52450
52415
  });
52451
52416
  });
52452
52417
  }
52453
- executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, resourceBundles, }) {
52418
+ executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
52454
52419
  return __awaiter(this, void 0, void 0, function* () {
52455
52420
  const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
52456
52421
  fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
@@ -52465,19 +52430,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52465
52430
  kind: item.kind,
52466
52431
  });
52467
52432
  })));
52468
- const resourceSources = yield Promise.all((resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []).map((bundle) => __awaiter(this, void 0, void 0, function* () {
52469
- return ({
52470
- name: bundle.name,
52471
- source: yield this.openProtocolV2MemorySource(bundle.binary),
52472
- devicePath: bundle.devicePath,
52473
- version: bundle.version,
52474
- payloadHash: bundle.payloadHash,
52475
- headerHash: bundle.headerHash,
52476
- });
52477
- })));
52478
52433
  return yield this.executeProtocolV2Phases({
52479
52434
  installSources,
52480
- resourceSources,
52435
+ resourceSources: [],
52481
52436
  });
52482
52437
  }
52483
52438
  finally {
@@ -65090,6 +65045,111 @@ const switchTransport = ({ env, Transport, plugin, }) => {
65090
65045
  initConnector();
65091
65046
  };
65092
65047
 
65048
+ let memoryHostSequence = 0;
65049
+ const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set([
65050
+ 'boot',
65051
+ 'app_v1',
65052
+ 'app_v2',
65053
+ 'coprocessor',
65054
+ 'se01',
65055
+ 'se02',
65056
+ 'se03',
65057
+ 'se04',
65058
+ ]);
65059
+ const isFirmwareUpdateV4ComponentTarget = (target) => FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target);
65060
+ const createReference = (binary, prefix) => {
65061
+ const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
65062
+ return {
65063
+ artifactRef: `fwmem:${prefix}:${digest.slice(0, 32)}`,
65064
+ size: binary.byteLength,
65065
+ sha256: digest,
65066
+ };
65067
+ };
65068
+ function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
65069
+ if (plan.executor !== 'v4') {
65070
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory host only supports V4 plans');
65071
+ }
65072
+ memoryHostSequence += 1;
65073
+ const hostId = `${Date.now()}:${memoryHostSequence}`;
65074
+ const binaries = new Map();
65075
+ const inputs = artifacts.map((input, artifactIndex) => {
65076
+ var _a;
65077
+ const artifact = createReference(input.binary, `${hostId}:artifact:${artifactIndex}`);
65078
+ binaries.set(artifact.artifactRef, new Uint8Array(input.binary));
65079
+ const materializedEntries = (_a = input.materializedEntries) === null || _a === void 0 ? void 0 : _a.map((entry, entryIndex) => {
65080
+ const entryArtifact = createReference(entry.binary, `${hostId}:entry:${artifactIndex}:${entryIndex}`);
65081
+ binaries.set(entryArtifact.artifactRef, new Uint8Array(entry.binary));
65082
+ return {
65083
+ entryName: entry.entryName,
65084
+ artifact: entryArtifact,
65085
+ };
65086
+ });
65087
+ return Object.assign({ artifactId: input.artifactId, artifact }, ((materializedEntries === null || materializedEntries === void 0 ? void 0 : materializedEntries.length) ? { materializedEntries } : {}));
65088
+ });
65089
+ const preparedPlan = sdk.prepareFirmwareUpdatePlan({
65090
+ plan,
65091
+ leaseRef: `fwmemlease:${hostId}`,
65092
+ artifacts: inputs,
65093
+ });
65094
+ const readers = new Map();
65095
+ let readerSequence = 0;
65096
+ const artifactReader = {
65097
+ open({ artifactRef }) {
65098
+ const binary = binaries.get(artifactRef);
65099
+ if (!binary) {
65100
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact is unavailable');
65101
+ }
65102
+ readerSequence += 1;
65103
+ const readerId = `fwmemreader:${hostId}:${readerSequence}`;
65104
+ readers.set(readerId, binary);
65105
+ return Promise.resolve({ readerId, size: binary.byteLength });
65106
+ },
65107
+ read({ readerId, offset, length }) {
65108
+ const binary = readers.get(readerId);
65109
+ if (!binary || offset < 0 || length <= 0 || offset + length > binary.byteLength) {
65110
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Firmware memory artifact read is invalid');
65111
+ }
65112
+ const data = binary.slice(offset, offset + length).buffer;
65113
+ return Promise.resolve({
65114
+ data,
65115
+ bytesRead: data.byteLength,
65116
+ eof: offset + length === binary.byteLength,
65117
+ });
65118
+ },
65119
+ close({ readerId }) {
65120
+ readers.delete(readerId);
65121
+ return Promise.resolve();
65122
+ },
65123
+ };
65124
+ const hostBindingGeneration = sdk.registerFirmwareUpdateHostBinding({
65125
+ artifactReader,
65126
+ preparedPlanDigest: preparedPlan.preparedPlanDigest,
65127
+ });
65128
+ const componentArtifacts = {};
65129
+ const expectedTargetVersions = {};
65130
+ for (const artifact of preparedPlan.artifacts) {
65131
+ if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
65132
+ componentArtifacts[artifact.target] = artifact.artifact;
65133
+ }
65134
+ if (artifact.targetVersion) {
65135
+ expectedTargetVersions[artifact.target] = artifact.targetVersion;
65136
+ }
65137
+ }
65138
+ return {
65139
+ preparedPlan,
65140
+ hostBindingGeneration,
65141
+ targetsToUpdate: [...preparedPlan.targetsToUpdate],
65142
+ expectedDeviceId: preparedPlan.deviceIdentity,
65143
+ expectedTargetVersions,
65144
+ componentArtifacts,
65145
+ release: () => {
65146
+ sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
65147
+ readers.clear();
65148
+ binaries.clear();
65149
+ },
65150
+ };
65151
+ }
65152
+
65093
65153
  const HardwareSdk = ({ init, call, dispose, eventEmitter, uiResponse, cancel, updateSettings, switchTransport, }) => inject({
65094
65154
  init,
65095
65155
  call,
@@ -65227,7 +65287,7 @@ exports.parseMessage = parseMessage;
65227
65287
  exports.parseProtocolV2ResourceManifest = parseProtocolV2ResourceManifest;
65228
65288
  exports.patchFeatures = patchFeatures;
65229
65289
  exports.preloadSessionCache = preloadSessionCache;
65230
- exports.prepareProtocolV2ResourceFiles = prepareProtocolV2ResourceFiles;
65290
+ exports.prepareFirmwareUpdateV4MemoryHost = prepareFirmwareUpdateV4MemoryHost;
65231
65291
  exports.projectDeviceStateFeatures = projectFeatures;
65232
65292
  exports.registerFirmwareUpdateHostBinding = registerFirmwareUpdateHostBinding;
65233
65293
  exports.safeThrowError = safeThrowError;