@onekeyfe/hd-core 1.2.0-alpha.112 → 1.2.0-alpha.114

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 (32) hide show
  1. package/__tests__/DeviceCommands.test.ts +2 -2
  2. package/__tests__/device-lifecycle-events.test.ts +1 -1
  3. package/__tests__/device-state-mapper.test.ts +4 -4
  4. package/__tests__/device-utils.test.ts +1 -1
  5. package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +89 -36
  6. package/__tests__/get-device-state.test.ts +8 -8
  7. package/__tests__/protocol-v2-resources.test.ts +0 -20
  8. package/__tests__/protocol-v2.test.ts +240 -219
  9. package/dist/api/FirmwareUpdateV4.d.ts +3 -0
  10. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  11. package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
  12. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
  13. package/dist/index.d.ts +20 -5
  14. package/dist/index.js +214 -133
  15. package/dist/protocols/protocol-v2/features.d.ts +4 -4
  16. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  17. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -1
  18. package/dist/types/settings.d.ts +19 -4
  19. package/dist/types/settings.d.ts.map +1 -1
  20. package/dist/utils/patch.d.ts +1 -1
  21. package/dist/utils/patch.d.ts.map +1 -1
  22. package/package.json +4 -4
  23. package/src/api/FirmwareUpdateV4.ts +178 -85
  24. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
  25. package/src/api/protocol-v2/DeviceInfoGet.ts +3 -3
  26. package/src/data/messages/messages-protocol-v2.json +14 -31
  27. package/src/device/DeviceStateMapper.ts +15 -15
  28. package/src/deviceProfile/buildDeviceFeatures.ts +3 -3
  29. package/src/protocols/protocol-v2/features.ts +6 -6
  30. package/src/protocols/protocol-v2/resources.ts +49 -10
  31. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -1
  32. package/src/types/settings.ts +19 -4
package/dist/index.js CHANGED
@@ -27499,10 +27499,9 @@ var nested = {
27499
27499
  MessageType_FilesystemDirMake: 60809,
27500
27500
  MessageType_FilesystemDirRemove: 60810,
27501
27501
  MessageType_FilesystemFormat: 60811,
27502
- MessageType_DeviceFirmwareUpdateStage: 61000,
27503
- MessageType_DeviceFirmwareUpdateRequest: 61001,
27504
- MessageType_DeviceFirmwareUpdateStatusGet: 61002,
27505
- MessageType_DeviceFirmwareUpdateStatus: 61003,
27502
+ MessageType_DeviceFirmwareUpdateRequest: 61000,
27503
+ MessageType_DeviceFirmwareUpdateStatusGet: 61001,
27504
+ MessageType_DeviceFirmwareUpdateStatus: 61002,
27506
27505
  MessageType_DeviceSessionGet: 61200,
27507
27506
  MessageType_DeviceSession: 61201,
27508
27507
  MessageType_DeviceSessionAskPin: 61202,
@@ -38004,7 +38003,7 @@ var nested = {
38004
38003
  type: "bytes",
38005
38004
  id: 1
38006
38005
  },
38007
- signning_message: {
38006
+ signing_message: {
38008
38007
  type: "bytes",
38009
38008
  id: 2
38010
38009
  },
@@ -38898,13 +38897,13 @@ var nested = {
38898
38897
  type: "string",
38899
38898
  id: 2
38900
38899
  },
38901
- factory_test_completed: {
38900
+ burn_in_completed: {
38902
38901
  type: "bool",
38903
- id: 4
38902
+ id: 3
38904
38903
  },
38905
- factory_burn_in_completed: {
38904
+ factory_test_completed: {
38906
38905
  type: "bool",
38907
- id: 3
38906
+ id: 4
38908
38907
  },
38909
38908
  manufacture_time: {
38910
38909
  type: "DeviceFactoryInfoManufactureTime",
@@ -38992,7 +38991,7 @@ var nested = {
38992
38991
  }
38993
38992
  }
38994
38993
  },
38995
- DeviceFirmwareUpdateStage: {
38994
+ DeviceFirmwareUpdateRequest: {
38996
38995
  fields: {
38997
38996
  targets: {
38998
38997
  rule: "repeated",
@@ -39001,10 +39000,6 @@ var nested = {
39001
39000
  }
39002
39001
  }
39003
39002
  },
39004
- DeviceFirmwareUpdateRequest: {
39005
- fields: {
39006
- }
39007
- },
39008
39003
  DeviceFirmwareUpdateRecord: {
39009
39004
  fields: {
39010
39005
  target_id: {
@@ -39186,7 +39181,7 @@ var nested = {
39186
39181
  type: "bool",
39187
39182
  id: 100
39188
39183
  },
39189
- main_mcu: {
39184
+ fw: {
39190
39185
  type: "bool",
39191
39186
  id: 200
39192
39187
  },
@@ -39255,7 +39250,7 @@ var nested = {
39255
39250
  type: "DeviceHardwareInfo",
39256
39251
  id: 100
39257
39252
  },
39258
- main_mcu: {
39253
+ fw: {
39259
39254
  type: "DeviceMainMcuInfo",
39260
39255
  id: 200
39261
39256
  },
@@ -39797,12 +39792,9 @@ var nested = {
39797
39792
  id: 1
39798
39793
  },
39799
39794
  text: {
39795
+ rule: "required",
39800
39796
  type: "string",
39801
39797
  id: 2
39802
- },
39803
- text_id: {
39804
- type: "uint32",
39805
- id: 3
39806
39798
  }
39807
39799
  }
39808
39800
  },
@@ -39833,6 +39825,7 @@ var nested = {
39833
39825
  ViewSignPage: {
39834
39826
  fields: {
39835
39827
  title: {
39828
+ rule: "required",
39836
39829
  type: "string",
39837
39830
  id: 1
39838
39831
  },
@@ -39866,16 +39859,13 @@ var nested = {
39866
39859
  options: {
39867
39860
  "default": "LayoutDefault"
39868
39861
  }
39869
- },
39870
- title_id: {
39871
- type: "uint32",
39872
- id: 8
39873
39862
  }
39874
39863
  }
39875
39864
  },
39876
39865
  ViewVerifyPage: {
39877
39866
  fields: {
39878
39867
  title: {
39868
+ rule: "required",
39879
39869
  type: "string",
39880
39870
  id: 1
39881
39871
  },
@@ -39900,14 +39890,6 @@ var nested = {
39900
39890
  value_key: {
39901
39891
  type: "uint32",
39902
39892
  id: 6
39903
- },
39904
- title_id: {
39905
- type: "uint32",
39906
- id: 7
39907
- },
39908
- chain_id: {
39909
- type: "uint32",
39910
- id: 8
39911
39893
  }
39912
39894
  }
39913
39895
  },
@@ -40754,9 +40736,7 @@ function parseProtocolV2ResourceManifestFile(value, index) {
40754
40736
  }
40755
40737
  const file = value;
40756
40738
  const archivePath = assertManifestRelativePath(file.archive_path, `files[${index}].archive_path`);
40757
- const originalName = file.original_name === undefined
40758
- ? (_a = archivePath.split('/').pop()) !== null && _a !== void 0 ? _a : archivePath
40759
- : assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
40739
+ const originalName = assertManifestRelativePath(file.original_name, `files[${index}].original_name`);
40760
40740
  if (originalName.includes('/')) {
40761
40741
  throw new Error(`Invalid Pro2 resource manifest files[${index}].original_name`);
40762
40742
  }
@@ -40768,28 +40748,74 @@ function parseProtocolV2ResourceManifestFile(value, index) {
40768
40748
  throw new Error(`Invalid Pro2 resource manifest files[${index}].size`);
40769
40749
  }
40770
40750
  const digest = normalizeHex$1(file.sha256, SHA256_HEX_LENGTH, `files[${index}].sha256`);
40751
+ if (file.signed !== true) {
40752
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].signed`);
40753
+ }
40754
+ if (file.sig_algo !== 'ed25519' && file.sig_algo !== 'mldsa65') {
40755
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].sig_algo`);
40756
+ }
40757
+ if (file.payload_version !== null && typeof file.payload_version !== 'string') {
40758
+ throw new Error(`Invalid Pro2 resource manifest files[${index}].payload_version`);
40759
+ }
40771
40760
  if (!archivePath.endsWith('.okpkg') || !originalName.endsWith('.okpkg')) {
40772
40761
  throw new Error(`Invalid Pro2 resource manifest files[${index}] package extension`);
40773
40762
  }
40774
- return Object.assign(Object.assign(Object.assign({ archive_path: archivePath, original_name: originalName, device_path: devicePath, size: Number(file.size), sha256: digest }, (file.signed === undefined ? {} : { signed: file.signed })), (file.sig_algo === undefined ? {} : { sig_algo: file.sig_algo })), (file.payload_version === undefined ? {} : { payload_version: file.payload_version }));
40763
+ return {
40764
+ archive_path: archivePath,
40765
+ original_name: originalName,
40766
+ device_path: devicePath,
40767
+ size: Number(file.size),
40768
+ sha256: digest,
40769
+ signed: true,
40770
+ sig_algo: file.sig_algo,
40771
+ payload_version: (_a = file.payload_version) !== null && _a !== void 0 ? _a : null,
40772
+ };
40775
40773
  }
40776
40774
  function parseProtocolV2ResourceManifest(value) {
40777
40775
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
40778
40776
  throw new Error('Invalid Pro2 resource manifest');
40779
40777
  }
40780
40778
  const manifest = value;
40781
- if (!Array.isArray(manifest.files)) {
40782
- throw new Error('Invalid Pro2 resource manifest files');
40779
+ if (manifest.schema !== 1 ||
40780
+ manifest.variant !== 'resource' ||
40781
+ manifest.device_root !== 'vol0:' ||
40782
+ manifest.restore_mode !== 'bootloader_update' ||
40783
+ !Array.isArray(manifest.trees) ||
40784
+ !Array.isArray(manifest.files)) {
40785
+ throw new Error('Invalid Pro2 resource manifest contract');
40783
40786
  }
40784
40787
  const files = manifest.files.map(parseProtocolV2ResourceManifestFile);
40785
40788
  const devicePaths = new Set(files.map(file => file.device_path));
40786
40789
  const archivePaths = new Set(files.map(file => file.archive_path));
40787
40790
  if (files.length === 0 ||
40788
40791
  devicePaths.size !== files.length ||
40789
- archivePaths.size !== files.length) {
40792
+ archivePaths.size !== files.length ||
40793
+ !devicePaths.has(PROTOCOL_V2_BOOT_RESOURCE_PACKAGE_PATH$1) ||
40794
+ !files.some(file => file.device_path.startsWith('vol0:/bundles/'))) {
40790
40795
  throw new Error('Invalid Pro2 resource manifest file set');
40791
40796
  }
40792
40797
  return {
40798
+ schema: 1,
40799
+ artifact_name: assertManifestString(manifest.artifact_name, 'artifact_name'),
40800
+ release_name: assertManifestString(manifest.release_name, 'release_name'),
40801
+ variant: 'resource',
40802
+ commit: assertManifestString(manifest.commit, 'commit'),
40803
+ short_sha: assertManifestString(manifest.short_sha, 'short_sha'),
40804
+ timestamp_utc: assertManifestString(manifest.timestamp_utc, 'timestamp_utc'),
40805
+ core_version: assertManifestString(manifest.core_version, 'core_version'),
40806
+ key_set: assertManifestString(manifest.key_set, 'key_set'),
40807
+ device_root: 'vol0:',
40808
+ restore_mode: 'bootloader_update',
40809
+ trees: manifest.trees.map((tree, index) => {
40810
+ if (!tree || typeof tree !== 'object') {
40811
+ throw new Error(`Invalid Pro2 resource manifest trees[${index}]`);
40812
+ }
40813
+ const item = tree;
40814
+ return {
40815
+ path: assertManifestRelativePath(item.path, `trees[${index}].path`),
40816
+ device: assertManifestString(item.device, `trees[${index}].device`),
40817
+ };
40818
+ }),
40793
40819
  files,
40794
40820
  };
40795
40821
  }
@@ -44224,10 +44250,10 @@ const getProtocolV2RuntimeMode = (protocolInfo, deviceInfo) => {
44224
44250
  return 'normal';
44225
44251
  if (binary)
44226
44252
  return binary;
44227
- if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !((_b = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.main_mcu) === null || _b === void 0 ? void 0 : _b.application)) {
44228
- if ((_c = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.main_mcu) === null || _c === void 0 ? void 0 : _c.romloader)
44253
+ if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !((_b = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _b === void 0 ? void 0 : _b.application)) {
44254
+ if ((_c = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _c === void 0 ? void 0 : _c.romloader)
44229
44255
  return 'romloader';
44230
- if ((_d = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.main_mcu) === null || _d === void 0 ? void 0 : _d.bootloader)
44256
+ if ((_d = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _d === void 0 ? void 0 : _d.bootloader)
44231
44257
  return 'bootloader';
44232
44258
  }
44233
44259
  return undefined;
@@ -44237,7 +44263,7 @@ const supportsProtocolV2Message = (protocolInfo, messageType) => protocolInfo.su
44237
44263
  const PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST = {
44238
44264
  targets: {
44239
44265
  hw: true,
44240
- main_mcu: true,
44266
+ fw: true,
44241
44267
  coprocessor: true,
44242
44268
  },
44243
44269
  types: {
@@ -44248,7 +44274,7 @@ const PROTOCOL_V2_FEATURES_DEVICE_INFO_REQUEST = {
44248
44274
  const PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST = {
44249
44275
  targets: {
44250
44276
  hw: true,
44251
- main_mcu: true,
44277
+ fw: true,
44252
44278
  coprocessor: true,
44253
44279
  se1: true,
44254
44280
  se2: true,
@@ -44263,7 +44289,7 @@ const PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST = {
44263
44289
  const PROTOCOL_V2_FULL_DEVICE_INFO_REQUEST = {
44264
44290
  targets: {
44265
44291
  hw: true,
44266
- main_mcu: true,
44292
+ fw: true,
44267
44293
  coprocessor: true,
44268
44294
  se1: true,
44269
44295
  se2: true,
@@ -44530,11 +44556,11 @@ const mapProtocolV2DeviceInfoToState = (info, mode = 'unknown') => {
44530
44556
  }
44531
44557
  : { mode },
44532
44558
  versions: definedEntries({
44533
- firmware: imageVersion((_d = info.main_mcu) === null || _d === void 0 ? void 0 : _d.application),
44534
- applicationP1: imageVersion((_e = info.main_mcu) === null || _e === void 0 ? void 0 : _e.application),
44535
- applicationP2: imageVersion((_f = info.main_mcu) === null || _f === void 0 ? void 0 : _f.application_data),
44536
- bootloader: imageVersion((_g = info.main_mcu) === null || _g === void 0 ? void 0 : _g.bootloader),
44537
- board: imageVersion((_h = info.main_mcu) === null || _h === void 0 ? void 0 : _h.romloader),
44559
+ firmware: imageVersion((_d = info.fw) === null || _d === void 0 ? void 0 : _d.application),
44560
+ applicationP1: imageVersion((_e = info.fw) === null || _e === void 0 ? void 0 : _e.application),
44561
+ applicationP2: imageVersion((_f = info.fw) === null || _f === void 0 ? void 0 : _f.application_data),
44562
+ bootloader: imageVersion((_g = info.fw) === null || _g === void 0 ? void 0 : _g.bootloader),
44563
+ board: imageVersion((_h = info.fw) === null || _h === void 0 ? void 0 : _h.romloader),
44538
44564
  ble: imageVersion((_j = info.coprocessor) === null || _j === void 0 ? void 0 : _j.application),
44539
44565
  se01: imageVersion((_k = info.se1) === null || _k === void 0 ? void 0 : _k.application),
44540
44566
  se02: imageVersion((_l = info.se2) === null || _l === void 0 ? void 0 : _l.application),
@@ -44546,16 +44572,16 @@ const mapProtocolV2DeviceInfoToState = (info, mode = 'unknown') => {
44546
44572
  se04Boot: imageVersion((_s = info.se4) === null || _s === void 0 ? void 0 : _s.bootloader),
44547
44573
  }),
44548
44574
  verification: definedEntries({
44549
- firmwareBuildId: imageBuildId((_t = info.main_mcu) === null || _t === void 0 ? void 0 : _t.application),
44550
- firmwareHash: imageHash((_u = info.main_mcu) === null || _u === void 0 ? void 0 : _u.application),
44551
- applicationP1BuildId: imageBuildId((_v = info.main_mcu) === null || _v === void 0 ? void 0 : _v.application),
44552
- applicationP1Hash: imageHash((_w = info.main_mcu) === null || _w === void 0 ? void 0 : _w.application),
44553
- applicationP2BuildId: imageBuildId((_x = info.main_mcu) === null || _x === void 0 ? void 0 : _x.application_data),
44554
- applicationP2Hash: imageHash((_y = info.main_mcu) === null || _y === void 0 ? void 0 : _y.application_data),
44555
- bootloaderBuildId: imageBuildId((_z = info.main_mcu) === null || _z === void 0 ? void 0 : _z.bootloader),
44556
- bootloaderHash: imageHash((_0 = info.main_mcu) === null || _0 === void 0 ? void 0 : _0.bootloader),
44557
- boardBuildId: imageBuildId((_1 = info.main_mcu) === null || _1 === void 0 ? void 0 : _1.romloader),
44558
- boardHash: imageHash((_2 = info.main_mcu) === null || _2 === void 0 ? void 0 : _2.romloader),
44575
+ firmwareBuildId: imageBuildId((_t = info.fw) === null || _t === void 0 ? void 0 : _t.application),
44576
+ firmwareHash: imageHash((_u = info.fw) === null || _u === void 0 ? void 0 : _u.application),
44577
+ applicationP1BuildId: imageBuildId((_v = info.fw) === null || _v === void 0 ? void 0 : _v.application),
44578
+ applicationP1Hash: imageHash((_w = info.fw) === null || _w === void 0 ? void 0 : _w.application),
44579
+ applicationP2BuildId: imageBuildId((_x = info.fw) === null || _x === void 0 ? void 0 : _x.application_data),
44580
+ applicationP2Hash: imageHash((_y = info.fw) === null || _y === void 0 ? void 0 : _y.application_data),
44581
+ bootloaderBuildId: imageBuildId((_z = info.fw) === null || _z === void 0 ? void 0 : _z.bootloader),
44582
+ bootloaderHash: imageHash((_0 = info.fw) === null || _0 === void 0 ? void 0 : _0.bootloader),
44583
+ boardBuildId: imageBuildId((_1 = info.fw) === null || _1 === void 0 ? void 0 : _1.romloader),
44584
+ boardHash: imageHash((_2 = info.fw) === null || _2 === void 0 ? void 0 : _2.romloader),
44559
44585
  bleBuildId: imageBuildId((_3 = info.coprocessor) === null || _3 === void 0 ? void 0 : _3.application),
44560
44586
  bleHash: imageHash((_4 = info.coprocessor) === null || _4 === void 0 ? void 0 : _4.application),
44561
44587
  se01BuildId: imageBuildId((_5 = info.se1) === null || _5 === void 0 ? void 0 : _5.application),
@@ -51644,6 +51670,7 @@ const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 90 * 1000;
51644
51670
  const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 3 * 60 * 1000;
51645
51671
  const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
51646
51672
  const PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT = 15 * 1000;
51673
+ const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
51647
51674
  const PROTOCOL_V2_INSTALL_TIMEOUT = 8 * 60 * 1000;
51648
51675
  const PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT = 30 * 1000;
51649
51676
  const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
@@ -51666,10 +51693,6 @@ const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
51666
51693
  const PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES = 1024 * 1024;
51667
51694
  const PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT = 512;
51668
51695
  const PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES = 256 * 1024 * 1024;
51669
- const getProtocolV2LocalResourceArchivePath = (entryName) => {
51670
- const match = entryName.match(/(?:^|\/)((?:bundles\/|loaders\/(?:bootloader|rom)\/).+\.okpkg)$/iu);
51671
- return match === null || match === void 0 ? void 0 : match[1];
51672
- };
51673
51696
  const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
51674
51697
  const getProtocolV2ZipEntrySizes = (entry) => {
51675
51698
  var _a;
@@ -51713,11 +51736,14 @@ function assertProtocolV2FirmwareTargetsSupported(deviceType, params, hasExplici
51713
51736
  }
51714
51737
  const getProtocolV2DeviceTransferProgress = (bytesBeforeChunk, bytesAfterChunk, totalBytes) => {
51715
51738
  if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
51716
- return 0;
51739
+ return 100;
51717
51740
  }
51718
51741
  if (bytesBeforeChunk <= 0 && bytesAfterChunk < totalBytes) {
51719
51742
  return 0;
51720
51743
  }
51744
+ if (bytesAfterChunk >= totalBytes) {
51745
+ return 100;
51746
+ }
51721
51747
  return Math.min(Math.max(Math.ceil((bytesAfterChunk / totalBytes) * 100), 1), 99);
51722
51748
  };
51723
51749
  const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS = {
@@ -51805,12 +51831,36 @@ const isProtocolV2ReconnectProbeError = (error) => {
51805
51831
  return ((message.includes('device protocol mismatch') && message.includes('expected v2')) ||
51806
51832
  message.includes('did not respond to expected protocol'));
51807
51833
  };
51834
+ const PROTOCOL_V2_BLE_INSTALL_INTERRUPTION_ERROR_CODES = new Set([
51835
+ hdShared.HardwareErrorCode.BleConnectedError,
51836
+ hdShared.HardwareErrorCode.BleCharacteristicNotifyError,
51837
+ hdShared.HardwareErrorCode.BleForceCleanRunPromise,
51838
+ hdShared.HardwareErrorCode.BleDeviceDisconnected,
51839
+ ]);
51840
+ const isProtocolV2BleInstallInterruptionError = (error) => {
51841
+ if (error instanceof hdShared.HardwareError &&
51842
+ PROTOCOL_V2_BLE_INSTALL_INTERRUPTION_ERROR_CODES.has(error.errorCode)) {
51843
+ return true;
51844
+ }
51845
+ const message = getProtocolV2UnknownErrorText(error).toLowerCase();
51846
+ const compactMessage = message.replace(/\s+/gu, '');
51847
+ return (/react native ble transport (?:released|disconnected)/u.test(message) ||
51848
+ (compactMessage.includes('rxerrorerror6') &&
51849
+ (compactMessage.includes('multiplatformbleadapter') ||
51850
+ compactMessage.includes('multipalformebleadapter'))));
51851
+ };
51808
51852
  const isProtocolV2FirmwareStatusEndpointUnavailable = (error) => {
51809
51853
  const message = getProtocolV2UnknownErrorText(error).toLowerCase();
51810
51854
  return (message.includes('handler not registered') ||
51811
51855
  message.includes('message handler not found') ||
51812
51856
  message.includes('unsupported message'));
51813
51857
  };
51858
+ const isProtocolV2FirmwareUpdateEndpointUnavailable = (error) => {
51859
+ const message = getProtocolV2UnknownErrorText(error).toLowerCase();
51860
+ return (message.includes('handler not registered') ||
51861
+ message.includes('message handler not found') ||
51862
+ message.includes('unsupported message'));
51863
+ };
51814
51864
  const isProtocolV2TerminalInstallStatusError = (error) => {
51815
51865
  var _a;
51816
51866
  return error instanceof hdShared.HardwareError &&
@@ -51943,9 +51993,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51943
51993
  this.protocolV2HasExplicitTargetSelection = false;
51944
51994
  this.protocolV2PreparedSources = [];
51945
51995
  this.protocolV2ExecutionInLoader = false;
51996
+ this.protocolV2LegacyDirectUpdate = false;
51946
51997
  this.protocolV2BootResourceStagingSafe = false;
51947
51998
  this.protocolV2CompletedTargetVersions = new Map();
51948
51999
  this.protocolV2FinalStatusVerified = false;
52000
+ this.protocolV2InstallAckReceived = false;
51949
52001
  this.protocolV2InstallBaselineVersions = new Map();
51950
52002
  }
51951
52003
  getSupportedProtocols() {
@@ -52441,63 +52493,60 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52441
52493
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unsafe entry path', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52442
52494
  }
52443
52495
  const entries = zipEntries.filter(entry => !entry.dir);
52444
- if (entries.length === 0) {
52496
+ if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
52445
52497
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP entry set is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52446
52498
  }
52447
- const manifestEntry = entries.find(entry => entry.name.split('/').pop() === 'manifest.json');
52448
- let manifestBinary;
52449
- let manifestDirectory = '';
52450
- let selectedFiles;
52451
- if (manifestEntry) {
52452
- if (getProtocolV2ZipEntrySizes(manifestEntry).uncompressedSize >
52453
- PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
52454
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52455
- }
52456
- manifestBinary = yield manifestEntry.async('arraybuffer');
52457
- if (manifestBinary.byteLength <= 0 ||
52458
- manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
52459
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52460
- }
52461
- let manifestValue;
52462
- try {
52463
- manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
52464
- }
52465
- catch (error) {
52466
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52499
+ let declaredUncompressedSize = 0;
52500
+ let declaredCompressedSize = 0;
52501
+ for (const entry of entries) {
52502
+ const sizes = getProtocolV2ZipEntrySizes(entry);
52503
+ declaredCompressedSize += sizes.compressedSize;
52504
+ declaredUncompressedSize += sizes.uncompressedSize;
52505
+ const entryLimit = entry.name === 'manifest.json'
52506
+ ? PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
52507
+ : PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES;
52508
+ if (sizes.uncompressedSize > entryLimit ||
52509
+ declaredCompressedSize > binary.byteLength ||
52510
+ declaredUncompressedSize >
52511
+ PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES + PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
52512
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP declared size exceeds the allowed limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52467
52513
  }
52468
- selectedFiles = selectProtocolV2ResourceManifestFiles({
52469
- manifest: parseProtocolV2ResourceManifest(manifestValue),
52470
- targetsToUpdate: (_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [],
52471
- });
52472
- manifestDirectory = manifestEntry.name.slice(0, -'manifest.json'.length);
52473
52514
  }
52474
- else {
52475
- selectedFiles = entries.flatMap(entry => {
52476
- var _a;
52477
- const archivePath = getProtocolV2LocalResourceArchivePath(entry.name);
52478
- if (!archivePath)
52479
- return [];
52480
- return [
52481
- {
52482
- archive_path: archivePath,
52483
- original_name: (_a = archivePath.split('/').pop()) !== null && _a !== void 0 ? _a : archivePath,
52484
- device_path: `vol0:/${archivePath}`,
52485
- size: getProtocolV2ZipEntrySizes(entry).uncompressedSize,
52486
- sha256: '',
52487
- },
52488
- ];
52489
- });
52515
+ const manifestEntry = zip.file('manifest.json');
52516
+ if (!manifestEntry) {
52517
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP has no manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52518
+ }
52519
+ const manifestBinary = yield manifestEntry.async('arraybuffer');
52520
+ if (manifestBinary.byteLength <= 0 ||
52521
+ manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
52522
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52523
+ }
52524
+ let manifestValue;
52525
+ try {
52526
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
52490
52527
  }
52491
- if (selectedFiles.length === 0 || selectedFiles.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT) {
52492
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP has no resource packages', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52528
+ catch (error) {
52529
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52530
+ }
52531
+ const manifest = parseProtocolV2ResourceManifest(manifestValue);
52532
+ const selectedFiles = selectProtocolV2ResourceManifestFiles({
52533
+ manifest,
52534
+ targetsToUpdate: (_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [],
52535
+ });
52536
+ const expectedEntryNames = new Set([
52537
+ 'manifest.json',
52538
+ ...selectedFiles.map(file => file.archive_path),
52539
+ ]);
52540
+ if (entries.length !== expectedEntryNames.size ||
52541
+ entries.some(entry => !expectedEntryNames.has(entry.name))) {
52542
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52493
52543
  }
52494
52544
  let totalSize = 0;
52495
- const materializedEntries = [];
52496
- const normalizedFiles = [];
52545
+ const materializedEntries = [
52546
+ { entryName: 'manifest.json', binary: manifestBinary },
52547
+ ];
52497
52548
  for (const file of selectedFiles) {
52498
- const entry = manifestEntry
52499
- ? zip.file(`${manifestDirectory}${file.archive_path}`)
52500
- : entries.find(candidate => getProtocolV2LocalResourceArchivePath(candidate.name) === file.archive_path);
52549
+ const entry = zip.file(file.archive_path);
52501
52550
  if (!entry) {
52502
52551
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP is missing ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
52503
52552
  }
@@ -52508,15 +52557,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52508
52557
  }
52509
52558
  const fileBinary = yield entry.async('arraybuffer');
52510
52559
  const digest = bytesToHex(sha256.sha256(new Uint8Array(fileBinary)));
52511
- if (fileBinary.byteLength !== file.size ||
52512
- (file.sha256 && digest !== file.sha256.toLowerCase())) {
52560
+ if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
52513
52561
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52514
52562
  }
52515
- normalizedFiles.push(Object.assign(Object.assign({}, file), { sha256: digest }));
52516
52563
  materializedEntries.push({ entryName: file.archive_path, binary: fileBinary });
52517
52564
  }
52518
- manifestBinary !== null && manifestBinary !== void 0 ? manifestBinary : (manifestBinary = new TextEncoder().encode(JSON.stringify({ files: normalizedFiles })).buffer);
52519
- materializedEntries.unshift({ entryName: 'manifest.json', binary: manifestBinary });
52520
52565
  return { binary, materializedEntries };
52521
52566
  });
52522
52567
  }
@@ -53103,6 +53148,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53103
53148
  }
53104
53149
  return ((_a = this.device.features) === null || _a === void 0 ? void 0 : _a.mode) === 'romloader';
53105
53150
  }
53151
+ isLegacyProtocolV2Runtime() {
53152
+ var _a, _b;
53153
+ const protocolInfo = (_b = (_a = this.device.state) === null || _a === void 0 ? void 0 : _a.raw) === null || _b === void 0 ? void 0 : _b.protocolV2ProtocolInfo;
53154
+ return protocolInfo ? isLegacyProtocolV2ProtocolInfo(protocolInfo) : false;
53155
+ }
53106
53156
  rebootProtocolV2ToBootloader() {
53107
53157
  return __awaiter(this, void 0, void 0, function* () {
53108
53158
  try {
@@ -53125,13 +53175,16 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53125
53175
  }
53126
53176
  enterProtocolV2BootloaderMode() {
53127
53177
  return __awaiter(this, void 0, void 0, function* () {
53178
+ this.protocolV2LegacyDirectUpdate = false;
53128
53179
  if (this.isProtocolV2RomloaderMode()) {
53129
53180
  Log$6.debug('Protocol V2 device is in romloader mode; start firmware update directly');
53181
+ this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
53130
53182
  this.protocolV2ExecutionInLoader = true;
53131
53183
  return false;
53132
53184
  }
53133
53185
  if (this.isProtocolV2BootloaderMode()) {
53134
53186
  Log$6.debug('Protocol V2 device is already in bootloader mode, skip reboot');
53187
+ this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
53135
53188
  this.protocolV2ExecutionInLoader = true;
53136
53189
  this.postTipMessage(exports.FirmwareUpdateTipMessage.GoToBootloaderSuccess);
53137
53190
  return false;
@@ -53491,7 +53544,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53491
53544
  let missingTargetStatusSince;
53492
53545
  let missingTargetStatusKey;
53493
53546
  let normalModeWithoutInstallEvidenceSince;
53494
- let installEvidenceObserved = false;
53547
+ let installEvidenceObserved = this.protocolV2InstallAckReceived;
53495
53548
  const resetMissingTargetStatusGrace = () => {
53496
53549
  missingTargetStatusSince = undefined;
53497
53550
  missingTargetStatusKey = undefined;
@@ -53506,18 +53559,13 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53506
53559
  }
53507
53560
  const currentDeviceInfo = deviceInfo;
53508
53561
  try {
53509
- const statusResponse = yield this.device.getCommands().typedCall('DeviceFirmwareUpdateStatusGet', ['DeviceFirmwareUpdateStatus', 'Success'], {
53562
+ const statusResponse = yield this.device.getCommands().typedCall('DeviceFirmwareUpdateStatusGet', 'DeviceFirmwareUpdateStatus', {
53510
53563
  fields: {
53511
53564
  status: true,
53512
53565
  payload_version: true,
53513
53566
  path: true,
53514
53567
  },
53515
53568
  }, { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT });
53516
- if (statusResponse.type === 'Success') {
53517
- this.protocolV2FinalStatusVerified = true;
53518
- this.postProgressMessage(100, 'installingFirmware');
53519
- return;
53520
- }
53521
53569
  const statusTargets = ((_a = statusResponse.message.records) !== null && _a !== void 0 ? _a : []);
53522
53570
  if (statusTargets.some(target => {
53523
53571
  const targetId = normalizeProtocolV2TargetId(target.target_id);
@@ -53822,12 +53870,46 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53822
53870
  }
53823
53871
  protocolV2StartFirmwareUpdate({ targets, }) {
53824
53872
  return __awaiter(this, void 0, void 0, function* () {
53873
+ this.protocolV2InstallAckReceived = false;
53825
53874
  this.protocolV2LastRuntimeProbeFeatures = undefined;
53826
- const commands = this.device.getCommands();
53827
- yield commands.typedCall('DeviceFirmwareUpdateStage', 'Success', { targets });
53828
- yield commands.call('DeviceFirmwareUpdateRequest', {}, { returnAfterWrite: true });
53875
+ const startUpdate = () => this.device
53876
+ .getCommands()
53877
+ .typedCall('DeviceFirmwareUpdateRequest', 'Success', { targets }, { timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT });
53878
+ let response;
53879
+ try {
53880
+ response = yield startUpdate();
53881
+ this.protocolV2InstallAckReceived = true;
53882
+ }
53883
+ catch (error) {
53884
+ if (this.isBleReconnect() && isProtocolV2BleInstallInterruptionError(error)) {
53885
+ this.throwIfAborted();
53886
+ Log$6.log('[FirmwareUpdateV4] install request interrupted by device reboot; continue status polling: ', error);
53887
+ }
53888
+ else if (this.protocolV2LegacyDirectUpdate &&
53889
+ isProtocolV2FirmwareUpdateEndpointUnavailable(error)) {
53890
+ this.protocolV2LegacyDirectUpdate = false;
53891
+ Log$6.debug('[FirmwareUpdateV4] legacy App does not expose DeviceFirmwareUpdateRequest; rebooting to bootloader');
53892
+ yield this.rebootProtocolV2ToBootloader();
53893
+ try {
53894
+ response = yield startUpdate();
53895
+ this.protocolV2InstallAckReceived = true;
53896
+ }
53897
+ catch (retryError) {
53898
+ if (!(this.isBleReconnect() && isProtocolV2BleInstallInterruptionError(retryError))) {
53899
+ throw retryError;
53900
+ }
53901
+ this.throwIfAborted();
53902
+ Log$6.log('[FirmwareUpdateV4] install request interrupted after legacy reboot; continue status polling: ', retryError);
53903
+ }
53904
+ }
53905
+ else {
53906
+ throw error;
53907
+ }
53908
+ }
53909
+ this.protocolV2LegacyDirectUpdate = false;
53829
53910
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FirmwareUpdating);
53830
53911
  this.postProgressMessage(0, 'installingFirmware');
53912
+ return response;
53831
53913
  });
53832
53914
  }
53833
53915
  protocolV2Reboot(rebootType) {
@@ -54847,7 +54929,7 @@ const resolvePreUnlockPinType = (method) => {
54847
54929
  return targetsKnownHiddenWallet ? hdTransport.DeviceSessionPinType.Any : hdTransport.DeviceSessionPinType.Main;
54848
54930
  };
54849
54931
  function runMethodWithUnlockPolicy(method, device, options = {}) {
54850
- var _a, _b, _c;
54932
+ var _a, _b;
54851
54933
  return __awaiter(this, void 0, void 0, function* () {
54852
54934
  const { context = createProtocolV2UnlockContext(), uiCoordinator, afterStatusBeforeUnlock, prepare, run: configuredRun, } = options;
54853
54935
  const run = configuredRun !== null && configuredRun !== void 0 ? configuredRun : (() => method.run());
@@ -54856,9 +54938,8 @@ function runMethodWithUnlockPolicy(method, device, options = {}) {
54856
54938
  const shouldCoordinateUi = shouldEmitUi && uiCoordinator !== undefined;
54857
54939
  const requiresPreUnlock = device.isProtocolV2() &&
54858
54940
  (method.useDevicePassphraseState || method.unlockPolicy === 'unlock-before-run') &&
54859
- ((_a = device.state) === null || _a === void 0 ? void 0 : _a.status.initialized) !== false &&
54860
- !((_b = device.isBootloader) === null || _b === void 0 ? void 0 : _b.call(device)) &&
54861
- !((_c = device.isRomloader) === null || _c === void 0 ? void 0 : _c.call(device));
54941
+ !((_a = device.isBootloader) === null || _a === void 0 ? void 0 : _a.call(device)) &&
54942
+ !((_b = device.isRomloader) === null || _b === void 0 ? void 0 : _b.call(device));
54862
54943
  if (requiresPreUnlock && !context.preflightCompleted) {
54863
54944
  const status = yield refreshProtocolV2DeviceStatus(device);
54864
54945
  if (typeof (status === null || status === void 0 ? void 0 : status.unlocked) !== 'boolean') {