@onekeyfe/hd-core 1.2.0-alpha.4 → 1.2.0-alpha.40

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 (693) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +155 -0
  2. package/__tests__/DeviceCommands.test.ts +517 -0
  3. package/__tests__/DeviceEventRegistration.test.ts +49 -0
  4. package/__tests__/chain-params-onekey-compatibility.test.ts +229 -0
  5. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +282 -0
  6. package/__tests__/connectSettings.test.ts +19 -0
  7. package/__tests__/core-dispose.test.ts +34 -0
  8. package/__tests__/core-error-output.test.ts +39 -0
  9. package/__tests__/device-features-state.test.ts +78 -0
  10. package/__tests__/device-identity.test.ts +52 -0
  11. package/__tests__/device-lifecycle-events.test.ts +249 -0
  12. package/__tests__/device-pool-state.test.ts +144 -0
  13. package/__tests__/device-settings.test.ts +416 -0
  14. package/__tests__/device-state-contract.test.ts +27 -0
  15. package/__tests__/device-state-events.test.ts +286 -0
  16. package/__tests__/device-state-mapper.test.ts +261 -0
  17. package/__tests__/device-state-projector.test.ts +94 -0
  18. package/__tests__/device-state-store.test.ts +82 -0
  19. package/__tests__/device-utils.test.ts +107 -0
  20. package/__tests__/device-wallet-session-store.test.ts +478 -0
  21. package/__tests__/deviceFeaturesUtils.test.ts +39 -0
  22. package/__tests__/deviceSettings.test.ts +103 -0
  23. package/__tests__/deviceUploadNft.test.ts +187 -0
  24. package/__tests__/evmLedgerLegacySafety.test.ts +12 -6
  25. package/__tests__/evmSignTransaction.test.ts +69 -0
  26. package/__tests__/evmSignTypedData.test.ts +80 -0
  27. package/__tests__/filesystemValidation.test.ts +53 -0
  28. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
  29. package/__tests__/get-device-state.test.ts +578 -0
  30. package/__tests__/homescreen.test.ts +64 -0
  31. package/__tests__/kaspa-public-types.type-test.ts +16 -0
  32. package/__tests__/kaspa-use-tweak-pro2.test.ts +20 -0
  33. package/__tests__/kaspaSignTransaction.test.ts +601 -0
  34. package/__tests__/known-device-public-types.type-test.ts +3 -0
  35. package/__tests__/logBlockEvent.test.ts +128 -1
  36. package/__tests__/method-protocol-support.test.ts +113 -0
  37. package/__tests__/networkUtils.test.ts +406 -0
  38. package/__tests__/open-wallet-session-error-response.test.ts +43 -0
  39. package/__tests__/open-wallet-session.test.ts +1609 -0
  40. package/__tests__/pro2Nft.test.ts +108 -0
  41. package/__tests__/pro2Wallpaper.test.ts +39 -0
  42. package/__tests__/protocol-v2-bootloader-mode.test.ts +37 -0
  43. package/__tests__/protocol-v2-firmware-targets.test.ts +37 -0
  44. package/__tests__/protocol-v2-ping.test.ts +28 -0
  45. package/__tests__/protocol-v2-ui-lifecycle.test.ts +56 -0
  46. package/__tests__/protocol-v2-unlock-policy.test.ts +96 -0
  47. package/__tests__/protocol-v2.test.ts +5748 -2387
  48. package/__tests__/protocolV2FileWrite.test.ts +92 -0
  49. package/__tests__/protocolV2UiInteraction.test.ts +266 -0
  50. package/__tests__/public-device-state-api.test.ts +275 -0
  51. package/__tests__/public-pro2-api-boundary.test.ts +107 -0
  52. package/__tests__/refresh-device-state.test.ts +101 -0
  53. package/__tests__/request-context-logging.test.ts +16 -0
  54. package/__tests__/search-devices.test.ts +136 -0
  55. package/__tests__/tron-sign-message-init.test.ts +74 -0
  56. package/__tests__/uiProgressThrottle.test.ts +74 -0
  57. package/dist/api/BaseMethod.d.ts +16 -1
  58. package/dist/api/BaseMethod.d.ts.map +1 -1
  59. package/dist/api/CheckAllFirmwareRelease.d.ts +24 -1
  60. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  61. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  62. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  63. package/dist/api/CipherKeyValue.d.ts +1 -0
  64. package/dist/api/CipherKeyValue.d.ts.map +1 -1
  65. package/dist/api/ClearSessionCache.d.ts +9 -0
  66. package/dist/api/ClearSessionCache.d.ts.map +1 -0
  67. package/dist/api/DirList.d.ts +1 -0
  68. package/dist/api/DirList.d.ts.map +1 -1
  69. package/dist/api/DirMake.d.ts +1 -0
  70. package/dist/api/DirMake.d.ts.map +1 -1
  71. package/dist/api/DirRemove.d.ts +1 -0
  72. package/dist/api/DirRemove.d.ts.map +1 -1
  73. package/dist/api/FileDelete.d.ts +1 -0
  74. package/dist/api/FileDelete.d.ts.map +1 -1
  75. package/dist/api/FileRead.d.ts +1 -0
  76. package/dist/api/FileRead.d.ts.map +1 -1
  77. package/dist/api/FileWrite.d.ts +2 -0
  78. package/dist/api/FileWrite.d.ts.map +1 -1
  79. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  80. package/dist/api/FirmwareUpdateV2.d.ts +2 -2
  81. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  82. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  83. package/dist/api/FirmwareUpdateV4.d.ts +23 -14
  84. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  85. package/dist/api/GetDeviceState.d.ts +8 -0
  86. package/dist/api/GetDeviceState.d.ts.map +1 -0
  87. package/dist/api/GetFeatures.d.ts +1 -1
  88. package/dist/api/GetFeatures.d.ts.map +1 -1
  89. package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
  90. package/dist/api/GetPassphraseState.d.ts +2 -6
  91. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  92. package/dist/api/OpenWalletSession.d.ts +8 -0
  93. package/dist/api/OpenWalletSession.d.ts.map +1 -0
  94. package/dist/api/PathInfo.d.ts +1 -0
  95. package/dist/api/PathInfo.d.ts.map +1 -1
  96. package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
  97. package/dist/api/SearchDevices.d.ts +3 -0
  98. package/dist/api/SearchDevices.d.ts.map +1 -1
  99. package/dist/api/UploadPortfolio.d.ts +17 -0
  100. package/dist/api/UploadPortfolio.d.ts.map +1 -0
  101. package/dist/api/alephium/AlephiumGetAddress.d.ts.map +1 -1
  102. package/dist/api/alephium/AlephiumSignMessage.d.ts.map +1 -1
  103. package/dist/api/alephium/AlephiumSignTransaction.d.ts.map +1 -1
  104. package/dist/api/algo/AlgoGetAddress.d.ts +1 -0
  105. package/dist/api/algo/AlgoGetAddress.d.ts.map +1 -1
  106. package/dist/api/algo/AlgoSignTransaction.d.ts +1 -0
  107. package/dist/api/algo/AlgoSignTransaction.d.ts.map +1 -1
  108. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +1 -0
  109. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  110. package/dist/api/aptos/AptosGetAddress.d.ts +1 -0
  111. package/dist/api/aptos/AptosGetAddress.d.ts.map +1 -1
  112. package/dist/api/aptos/AptosGetPublicKey.d.ts +1 -0
  113. package/dist/api/aptos/AptosGetPublicKey.d.ts.map +1 -1
  114. package/dist/api/aptos/AptosSignInMessage.d.ts +1 -0
  115. package/dist/api/aptos/AptosSignInMessage.d.ts.map +1 -1
  116. package/dist/api/aptos/AptosSignMessage.d.ts +1 -0
  117. package/dist/api/aptos/AptosSignMessage.d.ts.map +1 -1
  118. package/dist/api/aptos/AptosSignTransaction.d.ts +1 -0
  119. package/dist/api/aptos/AptosSignTransaction.d.ts.map +1 -1
  120. package/dist/api/benfen/BenfenGetAddress.d.ts.map +1 -1
  121. package/dist/api/benfen/BenfenGetPublicKey.d.ts.map +1 -1
  122. package/dist/api/benfen/BenfenSignMessage.d.ts.map +1 -1
  123. package/dist/api/benfen/BenfenSignTransaction.d.ts.map +1 -1
  124. package/dist/api/btc/BTCGetAddress.d.ts +1 -0
  125. package/dist/api/btc/BTCGetAddress.d.ts.map +1 -1
  126. package/dist/api/btc/BTCGetPublicKey.d.ts +1 -0
  127. package/dist/api/btc/BTCGetPublicKey.d.ts.map +1 -1
  128. package/dist/api/btc/BTCSignMessage.d.ts +1 -0
  129. package/dist/api/btc/BTCSignMessage.d.ts.map +1 -1
  130. package/dist/api/btc/BTCSignPsbt.d.ts +1 -0
  131. package/dist/api/btc/BTCSignPsbt.d.ts.map +1 -1
  132. package/dist/api/btc/BTCSignTransaction.d.ts +1 -0
  133. package/dist/api/btc/BTCSignTransaction.d.ts.map +1 -1
  134. package/dist/api/btc/BTCVerifyMessage.d.ts +1 -0
  135. package/dist/api/btc/BTCVerifyMessage.d.ts.map +1 -1
  136. package/dist/api/btc/helpers/versionLimit.d.ts +2 -0
  137. package/dist/api/btc/helpers/versionLimit.d.ts.map +1 -1
  138. package/dist/api/cardano/CardanoGetAddress.d.ts +1 -0
  139. package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -1
  140. package/dist/api/cardano/CardanoGetPublicKey.d.ts +1 -0
  141. package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -1
  142. package/dist/api/cardano/CardanoSignMessage.d.ts +1 -0
  143. package/dist/api/cardano/CardanoSignMessage.d.ts.map +1 -1
  144. package/dist/api/cardano/CardanoSignTransaction.d.ts +1 -0
  145. package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -1
  146. package/dist/api/conflux/ConfluxGetAddress.d.ts +2 -0
  147. package/dist/api/conflux/ConfluxGetAddress.d.ts.map +1 -1
  148. package/dist/api/conflux/ConfluxSignMessage.d.ts +2 -0
  149. package/dist/api/conflux/ConfluxSignMessage.d.ts.map +1 -1
  150. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts +2 -0
  151. package/dist/api/conflux/ConfluxSignMessageCIP23.d.ts.map +1 -1
  152. package/dist/api/conflux/ConfluxSignTransaction.d.ts +2 -0
  153. package/dist/api/conflux/ConfluxSignTransaction.d.ts.map +1 -1
  154. package/dist/api/cosmos/CosmosGetAddress.d.ts +1 -0
  155. package/dist/api/cosmos/CosmosGetAddress.d.ts.map +1 -1
  156. package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -0
  157. package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
  158. package/dist/api/cosmos/CosmosSignTransaction.d.ts +1 -0
  159. package/dist/api/cosmos/CosmosSignTransaction.d.ts.map +1 -1
  160. package/dist/api/device/DeviceCancel.d.ts +1 -0
  161. package/dist/api/device/DeviceCancel.d.ts.map +1 -1
  162. package/dist/api/device/DeviceChangePin.d.ts +1 -0
  163. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  164. package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
  165. package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
  166. package/dist/api/device/DeviceLock.d.ts +1 -0
  167. package/dist/api/device/DeviceLock.d.ts.map +1 -1
  168. package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -0
  169. package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
  170. package/dist/api/device/DeviceRebootToBootloader.d.ts +1 -0
  171. package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
  172. package/dist/api/device/DeviceSettings.d.ts +1 -0
  173. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  174. package/dist/api/device/DeviceSupportFeatures.d.ts +1 -0
  175. package/dist/api/device/DeviceSupportFeatures.d.ts.map +1 -1
  176. package/dist/api/device/DeviceUnlock.d.ts +1 -0
  177. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  178. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  179. package/dist/api/device/DeviceWipe.d.ts +1 -0
  180. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  181. package/dist/api/device/PreInitialize.d.ts +1 -0
  182. package/dist/api/device/PreInitialize.d.ts.map +1 -1
  183. package/dist/api/dynex/DnxGetAddress.d.ts.map +1 -1
  184. package/dist/api/dynex/DnxSignTransaction.d.ts.map +1 -1
  185. package/dist/api/evm/EVMGetAddress.d.ts +1 -0
  186. package/dist/api/evm/EVMGetAddress.d.ts.map +1 -1
  187. package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
  188. package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
  189. package/dist/api/evm/EVMSignMessage.d.ts +1 -0
  190. package/dist/api/evm/EVMSignMessage.d.ts.map +1 -1
  191. package/dist/api/evm/EVMSignMessageEIP712.d.ts.map +1 -1
  192. package/dist/api/evm/EVMSignTransaction.d.ts +1 -0
  193. package/dist/api/evm/EVMSignTransaction.d.ts.map +1 -1
  194. package/dist/api/evm/EVMSignTypedData.d.ts +1 -0
  195. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  196. package/dist/api/evm/EVMVerifyMessage.d.ts +1 -0
  197. package/dist/api/evm/EVMVerifyMessage.d.ts.map +1 -1
  198. package/dist/api/evm/protocol.d.ts +3 -0
  199. package/dist/api/evm/protocol.d.ts.map +1 -0
  200. package/dist/api/filecoin/FilecoinGetAddress.d.ts +1 -0
  201. package/dist/api/filecoin/FilecoinGetAddress.d.ts.map +1 -1
  202. package/dist/api/filecoin/FilecoinSignTransaction.d.ts +1 -0
  203. package/dist/api/filecoin/FilecoinSignTransaction.d.ts.map +1 -1
  204. package/dist/api/firmware/getBinary.d.ts +8 -4
  205. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  206. package/dist/api/helpers/filesystemValidation.d.ts +3 -0
  207. package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
  208. package/dist/api/helpers/paramsValidator.d.ts +1 -0
  209. package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
  210. package/dist/api/helpers/protocolV2FileWrite.d.ts +35 -0
  211. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -0
  212. package/dist/api/index.d.ts +8 -25
  213. package/dist/api/index.d.ts.map +1 -1
  214. package/dist/api/kaspa/KaspaGetAddress.d.ts +4 -0
  215. package/dist/api/kaspa/KaspaGetAddress.d.ts.map +1 -1
  216. package/dist/api/kaspa/KaspaSignTransaction.d.ts +9 -1
  217. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  218. package/dist/api/kaspa/helpers/TransferSerialize.d.ts.map +1 -1
  219. package/dist/api/lightning/LnurlAuth.d.ts +0 -4
  220. package/dist/api/lightning/LnurlAuth.d.ts.map +1 -1
  221. package/dist/api/near/NearGetAddress.d.ts +1 -0
  222. package/dist/api/near/NearGetAddress.d.ts.map +1 -1
  223. package/dist/api/near/NearSignTransaction.d.ts +1 -0
  224. package/dist/api/near/NearSignTransaction.d.ts.map +1 -1
  225. package/dist/api/nem/NEMGetAddress.d.ts +1 -0
  226. package/dist/api/nem/NEMGetAddress.d.ts.map +1 -1
  227. package/dist/api/nem/NEMSignTransaction.d.ts +1 -0
  228. package/dist/api/nem/NEMSignTransaction.d.ts.map +1 -1
  229. package/dist/api/neo/NeoGetAddress.d.ts.map +1 -1
  230. package/dist/api/neo/NeoSignTransaction.d.ts.map +1 -1
  231. package/dist/api/nervos/NervosGetAddress.d.ts.map +1 -1
  232. package/dist/api/nervos/NervosSignTransaction.d.ts.map +1 -1
  233. package/dist/api/nexa/NexaGetAddress.d.ts.map +1 -1
  234. package/dist/api/nexa/NexaSignTransaction.d.ts +1 -0
  235. package/dist/api/nexa/NexaSignTransaction.d.ts.map +1 -1
  236. package/dist/api/nostr/NostrDecryptMessage.d.ts +1 -0
  237. package/dist/api/nostr/NostrDecryptMessage.d.ts.map +1 -1
  238. package/dist/api/nostr/NostrEncryptMessage.d.ts +1 -0
  239. package/dist/api/nostr/NostrEncryptMessage.d.ts.map +1 -1
  240. package/dist/api/nostr/NostrGetPublicKey.d.ts +1 -0
  241. package/dist/api/nostr/NostrGetPublicKey.d.ts.map +1 -1
  242. package/dist/api/nostr/NostrSignEvent.d.ts +1 -0
  243. package/dist/api/nostr/NostrSignEvent.d.ts.map +1 -1
  244. package/dist/api/nostr/NostrSignSchnorr.d.ts +1 -0
  245. package/dist/api/nostr/NostrSignSchnorr.d.ts.map +1 -1
  246. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -0
  247. package/dist/api/polkadot/PolkadotGetAddress.d.ts.map +1 -1
  248. package/dist/api/polkadot/PolkadotSignTransaction.d.ts +1 -0
  249. package/dist/api/polkadot/PolkadotSignTransaction.d.ts.map +1 -1
  250. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts +1 -0
  251. package/dist/api/protocol-v2/DeviceFactoryInfoGet.d.ts.map +1 -1
  252. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts +1 -0
  253. package/dist/api/protocol-v2/DeviceFactoryInfoSet.d.ts.map +1 -1
  254. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts +1 -0
  255. package/dist/api/protocol-v2/DeviceFirmwareUpdate.d.ts.map +1 -1
  256. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts +4 -2
  257. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  258. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts +7 -0
  259. package/dist/api/protocol-v2/DeviceGetOnboardingStatus.d.ts.map +1 -0
  260. package/dist/api/protocol-v2/DeviceInfoGet.d.ts +1 -1
  261. package/dist/api/protocol-v2/DeviceInfoGet.d.ts.map +1 -1
  262. package/dist/api/protocol-v2/DeviceReboot.d.ts +1 -0
  263. package/dist/api/protocol-v2/DeviceReboot.d.ts.map +1 -1
  264. package/dist/api/protocol-v2/DeviceStatusGet.d.ts +7 -0
  265. package/dist/api/protocol-v2/DeviceStatusGet.d.ts.map +1 -0
  266. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +30 -0
  267. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  268. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +27 -0
  269. package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -0
  270. package/dist/api/protocol-v2/FilesystemFormat.d.ts +1 -0
  271. package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -1
  272. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts +1 -0
  273. package/dist/api/protocol-v2/FilesystemPermissionFix.d.ts.map +1 -1
  274. package/dist/api/protocol-v2/Ping.d.ts +3 -0
  275. package/dist/api/protocol-v2/Ping.d.ts.map +1 -1
  276. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts +1 -0
  277. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  278. package/dist/api/protocol-v2/helpers.d.ts +4 -1
  279. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  280. package/dist/api/scdo/ScdoGetAddress.d.ts.map +1 -1
  281. package/dist/api/scdo/ScdoSignMessage.d.ts.map +1 -1
  282. package/dist/api/scdo/ScdoSignTransaction.d.ts.map +1 -1
  283. package/dist/api/solana/SolGetAddress.d.ts +1 -0
  284. package/dist/api/solana/SolGetAddress.d.ts.map +1 -1
  285. package/dist/api/solana/SolSignMessage.d.ts +1 -0
  286. package/dist/api/solana/SolSignMessage.d.ts.map +1 -1
  287. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -0
  288. package/dist/api/solana/SolSignOffchainMessage.d.ts.map +1 -1
  289. package/dist/api/solana/SolSignTransaction.d.ts +1 -0
  290. package/dist/api/solana/SolSignTransaction.d.ts.map +1 -1
  291. package/dist/api/starcoin/StarcoinGetAddress.d.ts +1 -0
  292. package/dist/api/starcoin/StarcoinGetAddress.d.ts.map +1 -1
  293. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts +1 -0
  294. package/dist/api/starcoin/StarcoinGetPublicKey.d.ts.map +1 -1
  295. package/dist/api/starcoin/StarcoinSignMessage.d.ts +1 -0
  296. package/dist/api/starcoin/StarcoinSignMessage.d.ts.map +1 -1
  297. package/dist/api/starcoin/StarcoinSignTransaction.d.ts +1 -0
  298. package/dist/api/starcoin/StarcoinSignTransaction.d.ts.map +1 -1
  299. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts +1 -0
  300. package/dist/api/starcoin/StarcoinVerifyMessage.d.ts.map +1 -1
  301. package/dist/api/stellar/StellarGetAddress.d.ts +1 -2
  302. package/dist/api/stellar/StellarGetAddress.d.ts.map +1 -1
  303. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -2
  304. package/dist/api/stellar/StellarSignTransaction.d.ts.map +1 -1
  305. package/dist/api/sui/SuiGetAddress.d.ts +1 -0
  306. package/dist/api/sui/SuiGetAddress.d.ts.map +1 -1
  307. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -0
  308. package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -1
  309. package/dist/api/sui/SuiSignMessage.d.ts +1 -0
  310. package/dist/api/sui/SuiSignMessage.d.ts.map +1 -1
  311. package/dist/api/sui/SuiSignTransaction.d.ts +1 -0
  312. package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -1
  313. package/dist/api/ton/TonGetAddress.d.ts +1 -0
  314. package/dist/api/ton/TonGetAddress.d.ts.map +1 -1
  315. package/dist/api/ton/TonSignData.d.ts +1 -0
  316. package/dist/api/ton/TonSignData.d.ts.map +1 -1
  317. package/dist/api/ton/TonSignMessage.d.ts +1 -0
  318. package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
  319. package/dist/api/ton/TonSignProof.d.ts +1 -0
  320. package/dist/api/ton/TonSignProof.d.ts.map +1 -1
  321. package/dist/api/tron/TronGetAddress.d.ts +1 -0
  322. package/dist/api/tron/TronGetAddress.d.ts.map +1 -1
  323. package/dist/api/tron/TronSignMessage.d.ts +5 -0
  324. package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
  325. package/dist/api/tron/TronSignTransaction.d.ts +1 -0
  326. package/dist/api/tron/TronSignTransaction.d.ts.map +1 -1
  327. package/dist/api/utils.d.ts +2 -1
  328. package/dist/api/utils.d.ts.map +1 -1
  329. package/dist/api/xrp/XrpGetAddress.d.ts +1 -0
  330. package/dist/api/xrp/XrpGetAddress.d.ts.map +1 -1
  331. package/dist/api/xrp/XrpSignTransaction.d.ts +1 -0
  332. package/dist/api/xrp/XrpSignTransaction.d.ts.map +1 -1
  333. package/dist/constants/index.d.ts +1 -1
  334. package/dist/constants/index.d.ts.map +1 -1
  335. package/dist/core/RequestQueue.d.ts.map +1 -1
  336. package/dist/core/deviceEventRegistration.d.ts +13 -0
  337. package/dist/core/deviceEventRegistration.d.ts.map +1 -0
  338. package/dist/core/index.d.ts +3 -1
  339. package/dist/core/index.d.ts.map +1 -1
  340. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  341. package/dist/device/Device.d.ts +64 -16
  342. package/dist/device/Device.d.ts.map +1 -1
  343. package/dist/device/DeviceCommands.d.ts +8 -6
  344. package/dist/device/DeviceCommands.d.ts.map +1 -1
  345. package/dist/device/DeviceConnector.d.ts +1 -1
  346. package/dist/device/DeviceConnector.d.ts.map +1 -1
  347. package/dist/device/DeviceFeaturesState.d.ts +3 -0
  348. package/dist/device/DeviceFeaturesState.d.ts.map +1 -0
  349. package/dist/device/DevicePool.d.ts +5 -2
  350. package/dist/device/DevicePool.d.ts.map +1 -1
  351. package/dist/device/DeviceStateMapper.d.ts +13 -0
  352. package/dist/device/DeviceStateMapper.d.ts.map +1 -0
  353. package/dist/device/DeviceStateProjector.d.ts +7 -0
  354. package/dist/device/DeviceStateProjector.d.ts.map +1 -0
  355. package/dist/device/DeviceStateStore.d.ts +21 -0
  356. package/dist/device/DeviceStateStore.d.ts.map +1 -0
  357. package/dist/device/DeviceWalletSessionStore.d.ts +27 -0
  358. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -0
  359. package/dist/device/cloneDeviceState.d.ts +2 -0
  360. package/dist/device/cloneDeviceState.d.ts.map +1 -0
  361. package/dist/device/deviceIdentity.d.ts +5 -0
  362. package/dist/device/deviceIdentity.d.ts.map +1 -0
  363. package/dist/deviceProfile/buildDeviceFeatures.d.ts +9 -3
  364. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  365. package/dist/deviceProfile/index.d.ts +0 -1
  366. package/dist/deviceProfile/index.d.ts.map +1 -1
  367. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts +7 -0
  368. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -0
  369. package/dist/events/device.d.ts +16 -2
  370. package/dist/events/device.d.ts.map +1 -1
  371. package/dist/events/logBlockEvent.d.ts +2 -0
  372. package/dist/events/logBlockEvent.d.ts.map +1 -1
  373. package/dist/events/ui-request.d.ts +46 -4
  374. package/dist/events/ui-request.d.ts.map +1 -1
  375. package/dist/index.d.ts +1442 -712
  376. package/dist/index.js +7497 -3705
  377. package/dist/inject.d.ts.map +1 -1
  378. package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
  379. package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
  380. package/dist/protocols/protocol-v2/features.d.ts +25 -17
  381. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  382. package/dist/protocols/protocol-v2/firmware.d.ts +1 -0
  383. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  384. package/dist/protocols/protocol-v2/index.d.ts +3 -2
  385. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  386. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +17 -0
  387. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
  388. package/dist/protocols/protocol-v2/uiInteraction.d.ts +39 -0
  389. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -0
  390. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +2 -0
  391. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -0
  392. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  393. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  394. package/dist/protocols/protocol-v2/walletSession.d.ts +25 -0
  395. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -0
  396. package/dist/types/api/checkAllFirmwareRelease.d.ts +25 -4
  397. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  398. package/dist/types/api/deviceSettings.d.ts +11 -2
  399. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  400. package/dist/types/api/deviceUnlock.d.ts +1 -1
  401. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  402. package/dist/types/api/export.d.ts +3 -2
  403. package/dist/types/api/export.d.ts.map +1 -1
  404. package/dist/types/api/firmwareUpdate.d.ts +6 -1
  405. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  406. package/dist/types/api/getDeviceState.d.ts +12 -0
  407. package/dist/types/api/getDeviceState.d.ts.map +1 -0
  408. package/dist/types/api/getFeatures.d.ts.map +1 -1
  409. package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
  410. package/dist/types/api/getPassphraseState.d.ts +2 -10
  411. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  412. package/dist/types/api/index.d.ts +19 -30
  413. package/dist/types/api/index.d.ts.map +1 -1
  414. package/dist/types/api/kaspaSignTransaction.d.ts +42 -4
  415. package/dist/types/api/kaspaSignTransaction.d.ts.map +1 -1
  416. package/dist/types/api/openWalletSession.d.ts +35 -0
  417. package/dist/types/api/openWalletSession.d.ts.map +1 -0
  418. package/dist/types/api/protocolV2.d.ts +18 -84
  419. package/dist/types/api/protocolV2.d.ts.map +1 -1
  420. package/dist/types/api/sessionCache.d.ts +13 -0
  421. package/dist/types/api/sessionCache.d.ts.map +1 -0
  422. package/dist/types/device.d.ts +132 -8
  423. package/dist/types/device.d.ts.map +1 -1
  424. package/dist/types/params.d.ts.map +1 -1
  425. package/dist/types/settings.d.ts +7 -14
  426. package/dist/types/settings.d.ts.map +1 -1
  427. package/dist/utils/assets.d.ts +2 -1
  428. package/dist/utils/assets.d.ts.map +1 -1
  429. package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
  430. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
  431. package/dist/utils/deviceFeaturesUtils.d.ts +8 -3
  432. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  433. package/dist/utils/deviceInfoUtils.d.ts +9 -9
  434. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  435. package/dist/utils/deviceSettings.d.ts +38 -7
  436. package/dist/utils/deviceSettings.d.ts.map +1 -1
  437. package/dist/utils/deviceVersionUtils.d.ts +7 -5
  438. package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
  439. package/dist/utils/homescreen.d.ts +4 -0
  440. package/dist/utils/homescreen.d.ts.map +1 -1
  441. package/dist/utils/index.d.ts +6 -3
  442. package/dist/utils/index.d.ts.map +1 -1
  443. package/dist/utils/networkUtils.d.ts +10 -1
  444. package/dist/utils/networkUtils.d.ts.map +1 -1
  445. package/dist/utils/patch.d.ts +1 -1
  446. package/dist/utils/patch.d.ts.map +1 -1
  447. package/dist/utils/pro2Nft.d.ts +29 -0
  448. package/dist/utils/pro2Nft.d.ts.map +1 -0
  449. package/dist/utils/pro2Wallpaper.d.ts +22 -0
  450. package/dist/utils/pro2Wallpaper.d.ts.map +1 -0
  451. package/dist/utils/tracing.d.ts.map +1 -1
  452. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  453. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  454. package/package.json +4 -4
  455. package/src/api/BaseMethod.ts +53 -20
  456. package/src/api/CheckAllFirmwareRelease.ts +296 -1
  457. package/src/api/CheckBootloaderRelease.ts +1 -2
  458. package/src/api/CheckFirmwareRelease.ts +1 -2
  459. package/src/api/CipherKeyValue.ts +4 -0
  460. package/src/api/ClearSessionCache.ts +32 -0
  461. package/src/api/DirList.ts +9 -4
  462. package/src/api/DirMake.ts +7 -4
  463. package/src/api/DirRemove.ts +7 -4
  464. package/src/api/FileDelete.ts +7 -4
  465. package/src/api/FileRead.ts +15 -9
  466. package/src/api/FileWrite.ts +26 -181
  467. package/src/api/FirmwareUpdate.ts +11 -12
  468. package/src/api/FirmwareUpdateV2.ts +132 -52
  469. package/src/api/FirmwareUpdateV3.ts +3 -11
  470. package/src/api/FirmwareUpdateV4.ts +693 -535
  471. package/src/api/GetDeviceState.ts +59 -0
  472. package/src/api/GetFeatures.ts +6 -4
  473. package/src/api/GetOnekeyFeatures.ts +1 -75
  474. package/src/api/GetPassphraseState.ts +36 -21
  475. package/src/api/OpenWalletSession.ts +251 -0
  476. package/src/api/PathInfo.ts +9 -4
  477. package/src/api/PromptWebDeviceAccess.ts +2 -7
  478. package/src/api/SearchDevices.ts +29 -4
  479. package/src/api/UploadPortfolio.ts +40 -0
  480. package/src/api/alephium/AlephiumGetAddress.ts +0 -4
  481. package/src/api/alephium/AlephiumSignMessage.ts +0 -4
  482. package/src/api/alephium/AlephiumSignTransaction.ts +2 -6
  483. package/src/api/algo/AlgoGetAddress.ts +4 -0
  484. package/src/api/algo/AlgoSignTransaction.ts +4 -0
  485. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +41 -32
  486. package/src/api/aptos/AptosGetAddress.ts +4 -0
  487. package/src/api/aptos/AptosGetPublicKey.ts +4 -0
  488. package/src/api/aptos/AptosSignInMessage.ts +4 -0
  489. package/src/api/aptos/AptosSignMessage.ts +4 -0
  490. package/src/api/aptos/AptosSignTransaction.ts +4 -0
  491. package/src/api/benfen/BenfenGetAddress.ts +11 -7
  492. package/src/api/benfen/BenfenGetPublicKey.ts +0 -4
  493. package/src/api/benfen/BenfenSignMessage.ts +0 -4
  494. package/src/api/benfen/BenfenSignTransaction.ts +0 -4
  495. package/src/api/btc/BTCGetAddress.ts +8 -1
  496. package/src/api/btc/BTCGetPublicKey.ts +9 -2
  497. package/src/api/btc/BTCSignMessage.ts +8 -1
  498. package/src/api/btc/BTCSignPsbt.ts +4 -0
  499. package/src/api/btc/BTCSignTransaction.ts +8 -1
  500. package/src/api/btc/BTCVerifyMessage.ts +8 -1
  501. package/src/api/btc/helpers/versionLimit.ts +7 -4
  502. package/src/api/cardano/CardanoGetAddress.ts +4 -0
  503. package/src/api/cardano/CardanoGetPublicKey.ts +4 -0
  504. package/src/api/cardano/CardanoSignMessage.ts +5 -1
  505. package/src/api/cardano/CardanoSignTransaction.ts +5 -1
  506. package/src/api/conflux/ConfluxGetAddress.ts +6 -0
  507. package/src/api/conflux/ConfluxSignMessage.ts +6 -0
  508. package/src/api/conflux/ConfluxSignMessageCIP23.ts +6 -0
  509. package/src/api/conflux/ConfluxSignTransaction.ts +8 -5
  510. package/src/api/cosmos/CosmosGetAddress.ts +4 -0
  511. package/src/api/cosmos/CosmosGetPublicKey.ts +4 -0
  512. package/src/api/cosmos/CosmosSignTransaction.ts +4 -0
  513. package/src/api/device/DeviceCancel.ts +5 -0
  514. package/src/api/device/DeviceChangePin.ts +28 -0
  515. package/src/api/device/DeviceFullyUploadResource.ts +4 -5
  516. package/src/api/device/DeviceLock.ts +5 -0
  517. package/src/api/device/DeviceRebootToBoardloader.ts +5 -0
  518. package/src/api/device/DeviceRebootToBootloader.ts +5 -0
  519. package/src/api/device/DeviceSettings.ts +194 -1
  520. package/src/api/device/DeviceSupportFeatures.ts +4 -0
  521. package/src/api/device/DeviceUnlock.ts +14 -1
  522. package/src/api/device/DeviceUpdateBootloader.ts +1 -2
  523. package/src/api/device/DeviceWipe.ts +25 -0
  524. package/src/api/device/PreInitialize.ts +4 -0
  525. package/src/api/dynex/DnxGetAddress.ts +0 -6
  526. package/src/api/dynex/DnxSignTransaction.ts +0 -6
  527. package/src/api/evm/EVMGetAddress.ts +6 -2
  528. package/src/api/evm/EVMGetPublicKey.ts +6 -2
  529. package/src/api/evm/EVMSignMessage.ts +6 -2
  530. package/src/api/evm/EVMSignMessageEIP712.ts +1 -11
  531. package/src/api/evm/EVMSignTransaction.ts +6 -2
  532. package/src/api/evm/EVMSignTypedData.ts +42 -50
  533. package/src/api/evm/EVMVerifyMessage.ts +6 -2
  534. package/src/api/evm/legacyV1/getAddress.ts +2 -2
  535. package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
  536. package/src/api/evm/legacyV1/signMessage.ts +2 -2
  537. package/src/api/evm/legacyV1/signTypedData.ts +2 -2
  538. package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
  539. package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
  540. package/src/api/evm/protocol.ts +6 -0
  541. package/src/api/filecoin/FilecoinGetAddress.ts +4 -0
  542. package/src/api/filecoin/FilecoinSignTransaction.ts +4 -0
  543. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +3 -3
  544. package/src/api/firmware/getBinary.ts +8 -3
  545. package/src/api/helpers/batchGetPublickeys.ts +2 -2
  546. package/src/api/helpers/filesystemValidation.ts +61 -0
  547. package/src/api/helpers/paramsValidator.ts +1 -1
  548. package/src/api/helpers/protocolV2FileWrite.ts +206 -0
  549. package/src/api/index.ts +9 -26
  550. package/src/api/kaspa/KaspaGetAddress.ts +7 -0
  551. package/src/api/kaspa/KaspaSignTransaction.ts +380 -29
  552. package/src/api/kaspa/helpers/TransferSerialize.ts +17 -7
  553. package/src/api/lightning/LnurlAuth.ts +0 -4
  554. package/src/api/near/NearGetAddress.ts +4 -0
  555. package/src/api/near/NearSignTransaction.ts +4 -0
  556. package/src/api/nem/NEMGetAddress.ts +4 -0
  557. package/src/api/nem/NEMSignTransaction.ts +4 -0
  558. package/src/api/neo/NeoGetAddress.ts +0 -4
  559. package/src/api/neo/NeoSignTransaction.ts +0 -4
  560. package/src/api/nervos/NervosGetAddress.ts +0 -4
  561. package/src/api/nervos/NervosSignTransaction.ts +2 -6
  562. package/src/api/nexa/NexaGetAddress.ts +0 -4
  563. package/src/api/nexa/NexaSignTransaction.ts +3 -5
  564. package/src/api/nostr/NostrDecryptMessage.ts +4 -0
  565. package/src/api/nostr/NostrEncryptMessage.ts +4 -0
  566. package/src/api/nostr/NostrGetPublicKey.ts +4 -0
  567. package/src/api/nostr/NostrSignEvent.ts +4 -0
  568. package/src/api/nostr/NostrSignSchnorr.ts +4 -0
  569. package/src/api/polkadot/PolkadotGetAddress.ts +4 -0
  570. package/src/api/polkadot/PolkadotSignTransaction.ts +4 -0
  571. package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +5 -2
  572. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +5 -2
  573. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +8 -5
  574. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +43 -5
  575. package/src/api/protocol-v2/DeviceGetOnboardingStatus.ts +21 -0
  576. package/src/api/protocol-v2/DeviceInfoGet.ts +8 -15
  577. package/src/api/protocol-v2/DeviceReboot.ts +7 -3
  578. package/src/api/protocol-v2/DeviceStatusGet.ts +19 -0
  579. package/src/api/protocol-v2/DeviceUploadNft.ts +166 -0
  580. package/src/api/protocol-v2/DeviceUploadWallpaper.ts +134 -0
  581. package/src/api/protocol-v2/FilesystemFormat.ts +9 -3
  582. package/src/api/protocol-v2/FilesystemPermissionFix.ts +5 -2
  583. package/src/api/protocol-v2/Ping.ts +37 -3
  584. package/src/api/protocol-v2/ProtocolInfoRequest.ts +8 -3
  585. package/src/api/protocol-v2/helpers.ts +21 -16
  586. package/src/api/scdo/ScdoGetAddress.ts +0 -4
  587. package/src/api/scdo/ScdoSignMessage.ts +0 -4
  588. package/src/api/scdo/ScdoSignTransaction.ts +0 -4
  589. package/src/api/solana/SolGetAddress.ts +4 -0
  590. package/src/api/solana/SolSignMessage.ts +4 -0
  591. package/src/api/solana/SolSignOffchainMessage.ts +4 -0
  592. package/src/api/solana/SolSignTransaction.ts +4 -0
  593. package/src/api/starcoin/StarcoinGetAddress.ts +4 -0
  594. package/src/api/starcoin/StarcoinGetPublicKey.ts +4 -0
  595. package/src/api/starcoin/StarcoinSignMessage.ts +4 -0
  596. package/src/api/starcoin/StarcoinSignTransaction.ts +4 -0
  597. package/src/api/starcoin/StarcoinVerifyMessage.ts +4 -0
  598. package/src/api/stellar/StellarGetAddress.ts +1 -10
  599. package/src/api/stellar/StellarSignTransaction.ts +1 -14
  600. package/src/api/sui/SuiGetAddress.ts +4 -0
  601. package/src/api/sui/SuiGetPublicKey.ts +4 -0
  602. package/src/api/sui/SuiSignMessage.ts +4 -0
  603. package/src/api/sui/SuiSignTransaction.ts +4 -0
  604. package/src/api/ton/TonGetAddress.ts +4 -0
  605. package/src/api/ton/TonSignData.ts +5 -1
  606. package/src/api/ton/TonSignMessage.ts +4 -0
  607. package/src/api/ton/TonSignProof.ts +4 -0
  608. package/src/api/tron/TronGetAddress.ts +4 -0
  609. package/src/api/tron/TronSignMessage.ts +18 -7
  610. package/src/api/tron/TronSignTransaction.ts +4 -0
  611. package/src/api/utils.ts +7 -3
  612. package/src/api/xrp/XrpGetAddress.ts +4 -0
  613. package/src/api/xrp/XrpSignTransaction.ts +5 -1
  614. package/src/constants/index.ts +1 -4
  615. package/src/core/RequestQueue.ts +1 -0
  616. package/src/core/deviceEventRegistration.ts +27 -0
  617. package/src/core/index.ts +274 -120
  618. package/src/data/messages/messages-protocol-v2.json +1161 -477
  619. package/src/data/messages/messages.json +286 -1
  620. package/src/data-manager/DataManager.ts +6 -6
  621. package/src/data-manager/TransportManager.ts +1 -1
  622. package/src/data-manager/connectSettings.ts +4 -0
  623. package/src/device/Device.ts +820 -282
  624. package/src/device/DeviceCommands.ts +166 -158
  625. package/src/device/DeviceConnector.ts +10 -7
  626. package/src/device/DeviceFeaturesState.ts +25 -0
  627. package/src/device/DevicePool.ts +66 -16
  628. package/src/device/DeviceStateMapper.ts +374 -0
  629. package/src/device/DeviceStateProjector.ts +94 -0
  630. package/src/device/DeviceStateStore.ts +201 -0
  631. package/src/device/DeviceWalletSessionStore.ts +144 -0
  632. package/src/device/cloneDeviceState.ts +39 -0
  633. package/src/device/deviceIdentity.ts +18 -0
  634. package/src/deviceProfile/buildDeviceFeatures.ts +224 -190
  635. package/src/deviceProfile/index.ts +0 -1
  636. package/src/deviceProfile/protocolV2DeviceIdentity.ts +32 -0
  637. package/src/events/device.ts +22 -1
  638. package/src/events/logBlockEvent.ts +80 -2
  639. package/src/events/ui-request.ts +57 -4
  640. package/src/inject.ts +16 -41
  641. package/src/protocols/protocol-v2/deviceSession.ts +24 -0
  642. package/src/protocols/protocol-v2/features.ts +103 -32
  643. package/src/protocols/protocol-v2/firmware.ts +2 -1
  644. package/src/protocols/protocol-v2/index.ts +8 -1
  645. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +65 -0
  646. package/src/protocols/protocol-v2/uiInteraction.ts +236 -0
  647. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -0
  648. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +117 -0
  649. package/src/protocols/protocol-v2/walletSession.ts +360 -0
  650. package/src/types/api/checkAllFirmwareRelease.ts +46 -4
  651. package/src/types/api/deviceSettings.ts +26 -2
  652. package/src/types/api/deviceUnlock.ts +1 -1
  653. package/src/types/api/export.ts +8 -0
  654. package/src/types/api/firmwareUpdate.ts +23 -5
  655. package/src/types/api/getDeviceState.ts +19 -0
  656. package/src/types/api/getFeatures.ts +3 -0
  657. package/src/types/api/getOnekeyFeatures.ts +3 -0
  658. package/src/types/api/getPassphraseState.ts +9 -11
  659. package/src/types/api/index.ts +27 -64
  660. package/src/types/api/kaspaSignTransaction.ts +60 -4
  661. package/src/types/api/openWalletSession.ts +54 -0
  662. package/src/types/api/protocolV2.ts +33 -139
  663. package/src/types/api/sessionCache.ts +19 -0
  664. package/src/types/device.ts +185 -7
  665. package/src/types/params.ts +3 -2
  666. package/src/types/settings.ts +17 -16
  667. package/src/utils/assets.ts +4 -1
  668. package/src/utils/deviceFeaturesCompat.ts +180 -0
  669. package/src/utils/deviceFeaturesUtils.ts +56 -45
  670. package/src/utils/deviceInfoUtils.ts +27 -69
  671. package/src/utils/deviceSettings.ts +171 -39
  672. package/src/utils/deviceVersionUtils.ts +25 -44
  673. package/src/utils/findDefectiveBatchDevice.ts +3 -3
  674. package/src/utils/homescreen.ts +36 -0
  675. package/src/utils/index.ts +27 -3
  676. package/src/utils/networkUtils.ts +274 -16
  677. package/src/utils/pro2Nft.ts +91 -0
  678. package/src/utils/pro2Wallpaper.ts +130 -0
  679. package/src/utils/tracing.ts +3 -1
  680. package/src/utils/uiProgressThrottle.ts +63 -0
  681. package/tsconfig.type-tests.json +12 -0
  682. package/dist/api/GetDeviceInfo.d.ts +0 -9
  683. package/dist/api/GetDeviceInfo.d.ts.map +0 -1
  684. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts +0 -13
  685. package/dist/api/protocol-v2/FilesystemDiskControl.d.ts.map +0 -1
  686. package/dist/deviceProfile/buildDeviceProfile.d.ts +0 -21
  687. package/dist/deviceProfile/buildDeviceProfile.d.ts.map +0 -1
  688. package/dist/types/api/getDeviceInfo.d.ts +0 -87
  689. package/dist/types/api/getDeviceInfo.d.ts.map +0 -1
  690. package/src/api/GetDeviceInfo.ts +0 -145
  691. package/src/api/protocol-v2/FilesystemDiskControl.ts +0 -50
  692. package/src/deviceProfile/buildDeviceProfile.ts +0 -352
  693. package/src/types/api/getDeviceInfo.ts +0 -101
@@ -1,11 +1,14 @@
1
- import { ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
2
2
  import {
3
3
  DeviceRebootType,
4
4
  PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
5
+ PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE,
5
6
  PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
6
7
  } from '@onekeyfe/hd-transport';
8
+ import { sha256 } from '@noble/hashes/sha256';
7
9
 
8
10
  import { FirmwareUpdateTipMessage, UI_REQUEST } from '../events/ui-request';
11
+ import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
9
12
  import { validateParams } from './helpers/paramsValidator';
10
13
  import {
11
14
  LoggerNames,
@@ -25,20 +28,19 @@ import {
25
28
  } from '../protocols/protocol-v2';
26
29
  import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
27
30
  import {
28
- PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
29
31
  getProtocolV2UnknownErrorText,
30
32
  isProtocolV2DeviceDisconnectedError,
31
33
  } from './protocol-v2/helpers';
32
34
 
33
- import type { FirmwareUpdateV4Params } from '../types/api/firmwareUpdate';
35
+ import type { FirmwareUpdateV4Params, FirmwareUpdateV4Target } from '../types/api/firmwareUpdate';
34
36
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
37
+ import type { ProtocolV2DeviceInfo } from '@onekeyfe/hd-transport';
35
38
  import type { PROTO } from '../constants';
36
39
  import type { TypedResponseMessage } from '../device/DeviceCommands';
37
40
  import type {
38
41
  Features,
39
42
  IFirmwareReleaseInfo,
40
43
  IProtocolV2FirmwareComponent,
41
- IProtocolV2ResourceManifestPackage,
42
44
  IVersionArray,
43
45
  } from '../types';
44
46
 
@@ -46,20 +48,22 @@ const Log = getLogger(LoggerNames.Method);
46
48
 
47
49
  const SESSION_ERROR = 'session not found';
48
50
  const PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT = 60 * 1000;
51
+ const PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT = 2 * 60 * 1000;
49
52
  const PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT = 5 * 1000;
50
- const PROTOCOL_V2_START_UPDATE_TIMEOUT = 60 * 1000;
53
+ const PROTOCOL_V2_START_UPDATE_TIMEOUT = 3 * 60 * 1000;
51
54
  const PROTOCOL_V2_INSTALL_TIMEOUT = 5 * 60 * 1000;
52
55
  const PROTOCOL_V2_TARGET_STATUS_PENDING = 0;
53
56
  const PROTOCOL_V2_TARGET_STATUS_IN_PROGRESS = 1;
54
57
  const PROTOCOL_V2_TARGET_STATUS_FINISHED = 2;
55
58
  const PROTOCOL_V2_TARGET_STATUS_FAILED_MIN = 3;
56
59
  const PROTOCOL_V2_CONNECT_PROTOCOL = 'V2';
57
- const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = 'vol1:';
60
+ const PROTOCOL_V2_FIRMWARE_STAGING_VOLUME = 'vol0:/';
58
61
  const PROTOCOL_V2_MIN_FILE_CHUNK_SIZE = 64;
59
62
  const PROTOCOL_V2_CONNECT_RETRY_COUNT = 10;
60
63
  const PROTOCOL_V2_CONNECT_POLL_INTERVAL = 500;
61
64
  const PROTOCOL_V2_CONNECT_SINGLE_TIMEOUT = 75 * 1000;
62
65
  const PROTOCOL_V2_DEVICE_INFO_READY_TIMEOUT = 60 * 1000;
66
+ const PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT = 3;
63
67
  const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
64
68
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
65
69
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
@@ -94,12 +98,34 @@ type ProtocolV2FirmwareUpdateStatusTarget = {
94
98
  path?: string;
95
99
  };
96
100
 
97
- type ProtocolV2FirmwareUpdateStartResponse =
98
- | TypedResponseMessage<'Success'>
99
- | TypedResponseMessage<'DeviceFirmwareUpdateStatus'>
100
- | undefined;
101
+ type ProtocolV2FirmwareUpdateStartResponse = TypedResponseMessage<'Success'>;
101
102
 
102
103
  type ProtocolV2TargetBinary = { fileName: string; binary: ArrayBuffer; targetId: number };
104
+ type ProtocolV2InstallItem = ProtocolV2TargetBinary & {
105
+ kind: ProtocolV2RemoteComponentTarget['kind'];
106
+ };
107
+ type ProtocolV2InstallTarget = ProtocolV2InstallItem & {
108
+ path: string;
109
+ };
110
+
111
+ type ProtocolV2FileTransferParams = PROTO.FirmwareUpload & {
112
+ filePath: string;
113
+ processedSize?: number;
114
+ totalSize?: number;
115
+ onTransferredBytes?: (transferredBytes: number) => void;
116
+ };
117
+
118
+ /** RESC bundle okpkg written independently to devicePath through FileWrite. */
119
+ type ProtocolV2ResourceBundleBinary = {
120
+ name: string;
121
+ binary: ArrayBuffer;
122
+ devicePath: string;
123
+ /** Download URL for remote-config mode; omitted in manual mode. */
124
+ url?: string;
125
+ version?: IVersionArray;
126
+ payloadHash?: string;
127
+ headerHash?: string;
128
+ };
103
129
 
104
130
  type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
105
131
  binary: ArrayBuffer;
@@ -108,7 +134,7 @@ type ProtocolV2RemoteComponentBinary = ProtocolV2RemoteComponentTarget & {
108
134
  type ProtocolV2RemoteComponentTarget = {
109
135
  fileName: string;
110
136
  targetId: number;
111
- kind: 'bootloader' | 'firmware' | 'resource';
137
+ kind: 'bootloader' | 'firmware';
112
138
  };
113
139
 
114
140
  type ProtocolV2OkppHeader = {
@@ -161,18 +187,24 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS: Readonly<
161
187
  targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04,
162
188
  kind: 'firmware',
163
189
  },
164
- CRATE: {
165
- fileName: 'resource.bin',
166
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
167
- kind: 'resource',
168
- },
169
190
  };
170
191
 
192
+ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4Target>([
193
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
194
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
195
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2, 'app_v2'],
196
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR, 'coprocessor'],
197
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01, 'se01'],
198
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02, 'se02'],
199
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
200
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
201
+ ]);
202
+
171
203
  const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
172
204
  'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
173
205
 
174
- // hd-transport 的历史 decode 行为会把单值 enum 输出为枚举名字符串;
175
- // Protocol V2 沿用这个 SDK 语义,内部比较前再映射回固件协议数值。
206
+ // hd-transport historically decodes scalar enums as enum-name strings.
207
+ // Map them back to firmware protocol values before internal comparisons.
176
208
  const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map<string, number>(
177
209
  Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value])
178
210
  );
@@ -198,25 +230,12 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
198
230
  );
199
231
  };
200
232
 
201
- const isProtocolV2PollingTransientError = (error: unknown) => {
202
- const message = getProtocolV2UnknownErrorText(error).toLowerCase();
203
- return (
204
- isProtocolV2DeviceDisconnectedError(error) ||
205
- isProtocolV2ReconnectProbeError(error) ||
206
- message.includes('libusb_transfer_timed_out') ||
207
- (message.includes('response timeout') && message.includes('devicefirmwareupdatestatusget')) ||
208
- message.includes('device not found') ||
209
- message.includes('transportnotfound')
210
- );
211
- };
212
-
213
- const isProtocolV2StartUpdateTransientError = (error: unknown) => {
233
+ const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
214
234
  const message = getProtocolV2UnknownErrorText(error).toLowerCase();
215
235
  return (
216
- isProtocolV2DeviceDisconnectedError(error) ||
217
- isProtocolV2ReconnectProbeError(error) ||
218
- message.includes('libusb_transfer_timed_out') ||
219
- (message.includes('response timeout') && message.includes('devicefirmwareupdaterequest'))
236
+ message.includes('handler not registered') ||
237
+ message.includes('message handler not found') ||
238
+ message.includes('unsupported message')
220
239
  );
221
240
  };
222
241
 
@@ -262,13 +281,6 @@ const versionArrayToNumber = (version?: IVersionArray) => {
262
281
  return version[0] * 0x10000 + version[1] * 0x100 + version[2];
263
282
  };
264
283
 
265
- const versionStringToArray = (version?: string | null): IVersionArray | undefined => {
266
- if (!version) return undefined;
267
- const parts = version.split('.').map(part => Number(part));
268
- if (parts.length !== 3 || parts.some(part => !Number.isFinite(part))) return undefined;
269
- return parts as IVersionArray;
270
- };
271
-
272
284
  const compareProtocolV2Versions = (current?: IVersionArray, target?: IVersionArray) => {
273
285
  const currentNumber = versionArrayToNumber(current);
274
286
  const targetNumber = versionArrayToNumber(target);
@@ -355,6 +367,33 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
355
367
  };
356
368
  };
357
369
 
370
+ export const isProtocolV2FirmwareFingerprintValid = (
371
+ binary: ArrayBuffer | Uint8Array,
372
+ fingerprint: string | undefined
373
+ ) => {
374
+ const expectedFingerprint = normalizeProtocolV2Hex(fingerprint);
375
+ if (!expectedFingerprint) return true;
376
+ return bytesToHex(sha256(toProtocolV2Bytes(binary))) === expectedFingerprint;
377
+ };
378
+
379
+ export const assertProtocolV2ReconnectIdentity = (
380
+ expectedSerialNumber?: string,
381
+ actualSerialNumber?: string
382
+ ) => {
383
+ if (!expectedSerialNumber || !actualSerialNumber) {
384
+ throw ERRORS.TypedError(
385
+ HardwareErrorCode.DeviceNotFound,
386
+ 'Protocol V2 reconnect physical identity is unavailable'
387
+ );
388
+ }
389
+ if (actualSerialNumber !== expectedSerialNumber) {
390
+ throw ERRORS.TypedError(
391
+ HardwareErrorCode.DeviceNotFound,
392
+ `Protocol V2 reconnect physical identity mismatch: expected ${expectedSerialNumber}, received ${actualSerialNumber}`
393
+ );
394
+ }
395
+ };
396
+
358
397
  /**
359
398
  * FirmwareUpdateV4 is the complete Protocol V2 firmware update flow.
360
399
  *
@@ -364,9 +403,16 @@ const parseProtocolV2OkppHeader = (bytes: Uint8Array): ProtocolV2OkppHeader | nu
364
403
  * - completion waits for target status to finish, reboots to normal, then polls DeviceInfo
365
404
  */
366
405
  export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
406
+ private protocolV2ExpectedSerialNumber?: string;
407
+
408
+ getSupportedProtocols() {
409
+ return ['V2'] as const;
410
+ }
411
+
367
412
  init() {
368
413
  this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
369
414
  this.requireDeviceMode = [];
415
+ this.unlockPolicy = 'unlock-before-run';
370
416
  this.useDevicePassphraseState = false;
371
417
  this.skipForceUpdateCheck = true;
372
418
 
@@ -387,7 +433,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
387
433
 
388
434
  validateParams(payload, [
389
435
  { name: 'chunkSize', type: 'number' },
390
- { name: 'resourceBinaries', type: 'array', allowEmpty: true },
391
436
  { name: 'forcedUpdateRes', type: 'boolean' },
392
437
  { name: 'bootloaderBinary', type: 'buffer' },
393
438
  { name: 'romloaderBinary', type: 'buffer' },
@@ -399,7 +444,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
399
444
  { name: 'se03Binary', type: 'buffer' },
400
445
  { name: 'se04Binary', type: 'buffer' },
401
446
  { name: 'firmwareType', type: 'string' },
447
+ { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
402
448
  { name: 'platform', type: 'string' },
449
+ { name: 'resourceBundleFiles', type: 'array', allowEmpty: true },
403
450
  ]);
404
451
 
405
452
  this.params = {
@@ -414,19 +461,24 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
414
461
  se02Binary: payload.se02Binary,
415
462
  se03Binary: payload.se03Binary,
416
463
  se04Binary: payload.se04Binary,
417
- resourceBinaries: payload.resourceBinaries,
464
+ resourceBundleFiles: payload.resourceBundleFiles,
418
465
  firmwareType: payload.firmwareType,
466
+ targetsToUpdate: payload.targetsToUpdate,
419
467
  platform: payload.platform,
420
468
  };
421
469
  }
422
470
 
423
- private getProtocolV2FirmwareChunkSize() {
471
+ private getProtocolV2FirmwareChunkSize(direction: 'read' | 'write' = 'write') {
424
472
  const payloadChunkSize = Number(this.params?.chunkSize);
425
473
  const env = DataManager.getSettings('env');
426
- const maxChunkSize =
427
- this.params?.platform === 'native' || (env && DataManager.isBleConnect(env))
428
- ? PROTOCOL_V2_BLE_FILE_CHUNK_SIZE
429
- : PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
474
+ const isBle = this.params?.platform === 'native' || (env && DataManager.isBleConnect(env));
475
+ let maxChunkSize = PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
476
+ if (isBle) {
477
+ maxChunkSize =
478
+ direction === 'read'
479
+ ? PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE
480
+ : PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
481
+ }
430
482
  if (!Number.isFinite(payloadChunkSize) || payloadChunkSize <= 0) {
431
483
  return maxChunkSize;
432
484
  }
@@ -437,28 +489,22 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
437
489
  }
438
490
 
439
491
  async run() {
440
- if (!this.device.isProtocolV2()) {
441
- throw ERRORS.TypedError(
442
- HardwareErrorCode.RuntimeError,
443
- 'firmwareUpdateV4 requires a Protocol V2 device'
444
- );
445
- }
446
-
447
492
  Log.debug('FirmwareUpdateV4 strategy: Protocol V2');
448
493
  return this.runProtocolV2();
449
494
  }
450
495
 
451
496
  private async runProtocolV2() {
497
+ await this.captureProtocolV2PhysicalIdentity();
452
498
  const deviceFeatures = await this.getProtocolV2DeviceFeatures();
453
499
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
454
500
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
455
501
 
456
- let resourceBinaryMap: ProtocolV2TargetBinary[] = [];
457
502
  let fwBinaryMap: ProtocolV2TargetBinary[] = [];
458
503
  let bootloaderBinary: ArrayBuffer | null = null;
504
+ let installItems: ProtocolV2InstallItem[] | undefined;
505
+ let resourceBundles: ProtocolV2ResourceBundleBinary[] | undefined;
459
506
  try {
460
507
  this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
461
- resourceBinaryMap = await this.prepareResourceBinaries(firmwareType, deviceFeatures);
462
508
  fwBinaryMap = this.collectExplicitTargetBinaries();
463
509
  bootloaderBinary = this.prepareBootloaderBinary();
464
510
  if (!this.hasExplicitProtocolV2Payload(fwBinaryMap)) {
@@ -466,16 +512,20 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
466
512
  firmwareType,
467
513
  deviceFeatures
468
514
  );
469
- resourceBinaryMap = remoteBinaries.resourceBinaryMap;
470
515
  bootloaderBinary = remoteBinaries.bootloaderBinary;
471
516
  fwBinaryMap = remoteBinaries.fwBinaryMap;
517
+ installItems = remoteBinaries.installItems;
518
+ }
519
+ resourceBundles = this.prepareProtocolV2ResourceBundles(firmwareType, deviceFeatures);
520
+ if (resourceBundles?.length) {
521
+ resourceBundles = await this.prefetchProtocolV2ResourceBundles(resourceBundles);
472
522
  }
473
523
  this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
474
524
  } catch (err) {
475
525
  throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
476
526
  }
477
527
 
478
- if (resourceBinaryMap.length === 0 && !bootloaderBinary && fwBinaryMap.length === 0) {
528
+ if (!bootloaderBinary && fwBinaryMap.length === 0 && !resourceBundles?.length) {
479
529
  throw ERRORS.TypedError(
480
530
  HardwareErrorCode.FirmwareUpdateDownloadFailed,
481
531
  'No firmware to update'
@@ -485,9 +535,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
485
535
  await this.enterProtocolV2BootloaderMode();
486
536
 
487
537
  await this.executeProtocolV2Update({
488
- resourceBinaryMap,
489
538
  fwBinaryMap,
490
539
  bootloaderBinary,
540
+ ...(installItems ? { installItems } : undefined),
541
+ ...(resourceBundles?.length ? { resourceBundles } : undefined),
491
542
  });
492
543
 
493
544
  await this.exitProtocolV2BootloaderToNormal();
@@ -510,41 +561,36 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
510
561
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Device features not available');
511
562
  }
512
563
 
513
- private async prepareResourceBinaries(firmwareType: EFirmwareType, features: Features) {
514
- if (this.params.resourceBinaries?.length) {
515
- this.params.resourceBinaries.forEach((binary, index) => {
516
- if (!(binary instanceof ArrayBuffer)) {
517
- throw ERRORS.TypedError(
518
- HardwareErrorCode.CallMethodInvalidParameter,
519
- `Parameter [resourceBinaries.${index}] is of type invalid and should be [buffer].`
520
- );
521
- }
522
- });
564
+ private getProtocolV2SerialNumber(deviceInfo: ProtocolV2DeviceInfo) {
565
+ const serialNumber = deviceInfo.hw?.serial_no?.trim();
566
+ return serialNumber || undefined;
567
+ }
523
568
 
524
- return this.params.resourceBinaries.map((binary, index) => ({
525
- fileName: `resource-${index + 1}.bin`,
526
- binary,
527
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
528
- }));
529
- }
530
- const resourceUrl = DataManager.getSysResourcesLatestRelease({
531
- features,
532
- forcedUpdateRes: this.params.forcedUpdateRes,
533
- firmwareType,
569
+ private assertProtocolV2DeviceInfoIdentity(deviceInfo: ProtocolV2DeviceInfo) {
570
+ assertProtocolV2ReconnectIdentity(
571
+ this.protocolV2ExpectedSerialNumber,
572
+ this.getProtocolV2SerialNumber(deviceInfo)
573
+ );
574
+ }
575
+
576
+ private async requestProtocolV2PhysicalIdentity() {
577
+ return requestProtocolV2DeviceInfo({
578
+ commands: this.device.getCommands(),
579
+ timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
534
580
  });
581
+ }
535
582
 
536
- if (resourceUrl) {
537
- const resource = (await getSysResourceBinary(resourceUrl)).binary;
538
- return [
539
- {
540
- fileName: 'resource.bin',
541
- binary: resource,
542
- targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_CRATE,
543
- },
544
- ];
545
- }
546
- Log.warn('No resource url found');
547
- return [];
583
+ private async captureProtocolV2PhysicalIdentity() {
584
+ const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
585
+ const serialNumber = this.getProtocolV2SerialNumber(deviceInfo);
586
+ assertProtocolV2ReconnectIdentity(serialNumber, serialNumber);
587
+ this.protocolV2ExpectedSerialNumber = serialNumber;
588
+ }
589
+
590
+ private async verifyProtocolV2ReconnectIdentity() {
591
+ const deviceInfo = await this.requestProtocolV2PhysicalIdentity();
592
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
593
+ return deviceInfo;
548
594
  }
549
595
 
550
596
  private prepareBootloaderBinary(): ArrayBuffer | null {
@@ -553,12 +599,34 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
553
599
 
554
600
  private hasExplicitProtocolV2Payload(fwBinaryMap: ProtocolV2TargetBinary[]) {
555
601
  return (
556
- !!this.params.resourceBinaries?.length ||
602
+ !!this.params.resourceBundleFiles?.length ||
557
603
  !!this.params.bootloaderBinary ||
558
604
  fwBinaryMap.length > 0
559
605
  );
560
606
  }
561
607
 
608
+ private buildProtocolV2InstallItems({
609
+ bootloaderBinary,
610
+ fwBinaryMap,
611
+ }: {
612
+ bootloaderBinary: ArrayBuffer | null;
613
+ fwBinaryMap: ProtocolV2TargetBinary[];
614
+ }): ProtocolV2InstallItem[] {
615
+ const installItems: ProtocolV2InstallItem[] = [];
616
+
617
+ if (bootloaderBinary) {
618
+ installItems.push({
619
+ fileName: 'bootloader.bin',
620
+ binary: bootloaderBinary,
621
+ targetId: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
622
+ kind: 'bootloader',
623
+ });
624
+ }
625
+
626
+ installItems.push(...fwBinaryMap.map(item => ({ ...item, kind: 'firmware' as const })));
627
+ return installItems;
628
+ }
629
+
562
630
  private getRemoteComponentEntries(release: IFirmwareReleaseInfo) {
563
631
  const { components } = release;
564
632
  if (!components) return [];
@@ -594,63 +662,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
594
662
  return target;
595
663
  }
596
664
 
597
- private getProtocolV2ComponentTargetVersion(
598
- release: IFirmwareReleaseInfo,
599
- component: IProtocolV2FirmwareComponent,
600
- target: ProtocolV2RemoteComponentTarget
601
- ) {
602
- if (component.version) return component.version;
603
- if (target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER) {
604
- return release.bootloaderVersion;
605
- }
606
- if (
607
- target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1 ||
608
- target.targetId === ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2
609
- ) {
610
- return release.version;
611
- }
612
- return undefined;
613
- }
614
-
615
- private getProtocolV2ComponentCurrentVersion(
616
- features: Features,
617
- target: ProtocolV2RemoteComponentTarget
618
- ) {
619
- switch (target.targetId) {
620
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER:
621
- return getDeviceBootloaderVersion(features);
622
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1:
623
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2:
624
- return getDeviceFirmwareVersion(features);
625
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR:
626
- return getDeviceBLEFirmwareVersion(features);
627
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01:
628
- return versionStringToArray(features.se01Version);
629
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02:
630
- return versionStringToArray(features.se02Version);
631
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03:
632
- return versionStringToArray(features.se03Version);
633
- case ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04:
634
- return versionStringToArray(features.se04Version);
635
- default:
636
- return undefined;
637
- }
638
- }
639
-
640
- private isProtocolV2ComponentVersionSatisfied(
641
- release: IFirmwareReleaseInfo,
642
- component: IProtocolV2FirmwareComponent,
643
- target: ProtocolV2RemoteComponentTarget,
644
- features: Features
645
- ) {
646
- const targetVersion = this.getProtocolV2ComponentTargetVersion(release, component, target);
647
- if (!targetVersion) return false;
648
-
649
- const currentVersion = this.getProtocolV2ComponentCurrentVersion(features, target);
650
- const compareResult = compareProtocolV2Versions(currentVersion, targetVersion);
651
- return compareResult !== undefined && compareResult >= 0;
652
- }
653
-
654
665
  private getProtocolV2ResourceFilePath(path: string) {
655
666
  if (path.startsWith('vol')) return path;
656
667
  if (path.startsWith('/')) return `vol0:${path}`;
@@ -673,7 +684,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
673
684
  return null;
674
685
  }
675
686
 
676
- const chunkSize = this.getProtocolV2FirmwareChunkSize();
687
+ const chunkSize = this.getProtocolV2FirmwareChunkSize('read');
677
688
  const chunks: Uint8Array[] = [];
678
689
  let offset = 0;
679
690
  while (offset < PROTOCOL_V2_OKPP_HEADER_SIZE) {
@@ -702,95 +713,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
702
713
  return parseProtocolV2OkppHeader(headerBytes);
703
714
  }
704
715
 
705
- private async isProtocolV2ResourcePackageMatched(
706
- pkg: IProtocolV2ResourceManifestPackage,
707
- manifestVersion?: IVersionArray
708
- ) {
709
- try {
710
- const header = await this.readProtocolV2DeviceFileHeader(pkg.path);
711
- if (!header) return false;
712
-
713
- const expectedType = pkg.type ?? 'RESC';
714
- const expectedVersion = pkg.version ?? manifestVersion;
715
- if (header.type !== expectedType) return false;
716
- if (expectedVersion && compareProtocolV2Versions(header.version, expectedVersion) !== 0) {
717
- return false;
718
- }
719
-
720
- const expectedPayloadHash = normalizeProtocolV2Hex(pkg.payloadHash);
721
- if (expectedPayloadHash && header.payloadHash !== expectedPayloadHash) return false;
722
-
723
- const expectedHeaderHash = normalizeProtocolV2Hex(pkg.headerHash);
724
- if (expectedHeaderHash && header.headerHash !== expectedHeaderHash) return false;
725
-
726
- return true;
727
- } catch (error) {
728
- Log.log(`Protocol V2 resource package check failed for ${pkg.path}: `, error);
729
- return false;
730
- }
731
- }
732
-
733
- private async isProtocolV2ResourceManifestSatisfied(
734
- manifest: IFirmwareReleaseInfo['resourceManifest']
735
- ) {
736
- if (!manifest?.packages?.length) return false;
737
-
738
- for (const pkg of manifest.packages) {
739
- if (!(await this.isProtocolV2ResourcePackageMatched(pkg, manifest.version))) {
740
- return false;
741
- }
742
- }
743
- return true;
744
- }
745
-
746
- private getProtocolV2ResourceManifest(
747
- release: IFirmwareReleaseInfo,
748
- component: IProtocolV2FirmwareComponent
749
- ) {
750
- return component.resourceManifest ?? release.resourceManifest;
751
- }
752
-
753
- private getProtocolV2ResourceComponentFileName(key: string) {
754
- const safeKey = key.replace(/[^a-z0-9_-]/gi, '_') || 'resource';
755
- return `resource-${safeKey}.bin`;
756
- }
757
-
758
- private async shouldInstallRemoteProtocolV2Component(
759
- release: IFirmwareReleaseInfo,
760
- key: string,
761
- component: IProtocolV2FirmwareComponent,
762
- target: ProtocolV2RemoteComponentTarget,
763
- features: Features
764
- ) {
765
- if (target.kind === 'resource') {
766
- if (
767
- this.params.forcedUpdateRes ||
768
- features.bootloaderMode ||
769
- features.mode === 'bootloader'
770
- ) {
771
- return true;
772
- }
773
- const resourceMatched = await this.isProtocolV2ResourceManifestSatisfied(
774
- this.getProtocolV2ResourceManifest(release, component)
775
- );
776
- if (resourceMatched) {
777
- Log.log(`[FirmwareUpdateV4] skip Protocol V2 resource component ${key}; manifest matched`);
778
- }
779
- return !resourceMatched;
780
- }
781
-
782
- const versionSatisfied = this.isProtocolV2ComponentVersionSatisfied(
783
- release,
784
- component,
785
- target,
786
- features
787
- );
788
- if (versionSatisfied) {
789
- Log.log(`[FirmwareUpdateV4] skip Protocol V2 component ${key}; version is up to date`);
790
- }
791
- return !versionSatisfied;
792
- }
793
-
794
716
  private async downloadRemoteProtocolV2Component(
795
717
  key: string,
796
718
  component: IProtocolV2FirmwareComponent
@@ -804,6 +726,22 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
804
726
  }
805
727
 
806
728
  const { binary } = await getSysResourceBinary(component.url);
729
+ if (!isProtocolV2FirmwareFingerprintValid(binary, component.fingerprint)) {
730
+ throw ERRORS.TypedError(
731
+ HardwareErrorCode.RuntimeError,
732
+ `Protocol V2 firmware fingerprint mismatch: ${key}/${component.target}`
733
+ );
734
+ }
735
+ const expectedPayloadHash = normalizeProtocolV2Hex(component.payloadHash);
736
+ if (expectedPayloadHash) {
737
+ const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
738
+ if (!header || header.payloadHash !== expectedPayloadHash) {
739
+ throw ERRORS.TypedError(
740
+ HardwareErrorCode.RuntimeError,
741
+ `Protocol V2 firmware payload hash mismatch: ${key}/${component.target}`
742
+ );
743
+ }
744
+ }
807
745
  return {
808
746
  ...target,
809
747
  binary,
@@ -813,66 +751,274 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
813
751
  private async prepareRemoteProtocolV2Binaries(firmwareType: EFirmwareType, features: Features) {
814
752
  const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
815
753
 
816
- const resourceBinaryMap: ProtocolV2TargetBinary[] = [];
817
754
  let bootloaderBinary: ArrayBuffer | null = null;
818
755
  const fwBinaryMap: ProtocolV2TargetBinary[] = [];
756
+ const installItems: ProtocolV2InstallItem[] = [];
819
757
 
820
758
  if (!release) {
821
759
  return {
822
- resourceBinaryMap,
823
760
  bootloaderBinary,
824
761
  fwBinaryMap,
762
+ installItems,
825
763
  };
826
764
  }
827
765
 
828
766
  const entries = this.getRemoteComponentEntries(release);
767
+ const targetsToUpdate = new Set(this.params.targetsToUpdate ?? []);
829
768
 
830
769
  for (const [key, component] of entries) {
831
- const target = this.getRemoteComponentTarget(key, component);
832
- const shouldInstall = await this.shouldInstallRemoteProtocolV2Component(
833
- release,
834
- key,
835
- component,
836
- target,
837
- features
838
- );
839
- if (shouldInstall) {
770
+ const targetName = component.target?.toUpperCase();
771
+ const target = PROTOCOL_V2_REMOTE_COMPONENT_TARGETS[targetName];
772
+ const updateTarget = target
773
+ ? PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId)
774
+ : undefined;
775
+ if (updateTarget && targetsToUpdate.has(updateTarget)) {
840
776
  const remoteBinary = await this.downloadRemoteProtocolV2Component(key, component);
841
- if (remoteBinary.kind === 'resource') {
842
- resourceBinaryMap.push({
843
- fileName: this.getProtocolV2ResourceComponentFileName(key),
777
+ if (remoteBinary.kind === 'bootloader') {
778
+ bootloaderBinary = remoteBinary.binary;
779
+ installItems.push({
780
+ fileName: remoteBinary.fileName,
844
781
  binary: remoteBinary.binary,
845
782
  targetId: remoteBinary.targetId,
783
+ kind: remoteBinary.kind,
846
784
  });
847
- } else if (remoteBinary.kind === 'bootloader') {
848
- bootloaderBinary = remoteBinary.binary;
849
785
  } else {
850
- fwBinaryMap.push({
786
+ const binaryEntry = {
851
787
  fileName: remoteBinary.fileName,
852
788
  binary: remoteBinary.binary,
853
789
  targetId: remoteBinary.targetId,
854
- });
790
+ };
791
+ fwBinaryMap.push(binaryEntry);
792
+ installItems.push({ ...binaryEntry, kind: remoteBinary.kind });
855
793
  }
856
794
  }
857
795
  }
858
796
 
859
797
  return {
860
- resourceBinaryMap,
861
798
  bootloaderBinary,
862
799
  fwBinaryMap,
800
+ installItems,
863
801
  };
864
802
  }
865
803
 
804
+ // ============================================================
805
+ // Incremental RESC bundle sync through FileRead and FilesystemFileWrite
806
+ // ============================================================
807
+
808
+ /**
809
+ * Prepare the RESC bundle list.
810
+ *
811
+ * Two modes, matching FirmwareUpdateV3 binary-versus-version behavior:
812
+ * - resourceBundleFiles supplied: use binaries directly without version checks.
813
+ * - Otherwise load release.resourceBundles from remote config.json; the binaries
814
+ * are prefetched before reboot and synchronization skips matching device headers.
815
+ */
816
+ private prepareProtocolV2ResourceBundles(
817
+ firmwareType: EFirmwareType,
818
+ features: Features
819
+ ): ProtocolV2ResourceBundleBinary[] | undefined {
820
+ // Manual binaries are installed directly without comparison.
821
+ if (this.params.resourceBundleFiles?.length) {
822
+ return this.params.resourceBundleFiles.map((file, index) => {
823
+ const devicePath = validateProtocolV2FilesystemPath(
824
+ file.devicePath,
825
+ `resourceBundleFiles[${index}].devicePath`
826
+ );
827
+ return {
828
+ name: devicePath.split('/').pop() ?? devicePath,
829
+ binary: file.binary,
830
+ devicePath,
831
+ };
832
+ });
833
+ }
834
+
835
+ if (!this.params.targetsToUpdate?.includes('resource')) {
836
+ return undefined;
837
+ }
838
+
839
+ // Remote-config bundles are downloaded and compared later.
840
+ const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
841
+ if (!release?.resourceBundles?.length) return undefined;
842
+
843
+ return release.resourceBundles.map((bundle, index) => ({
844
+ name: bundle.name,
845
+ binary: new ArrayBuffer(0),
846
+ devicePath: validateProtocolV2FilesystemPath(
847
+ bundle.devicePath,
848
+ `resourceBundles[${index}].devicePath`
849
+ ),
850
+ url: bundle.url,
851
+ version: bundle.version,
852
+ payloadHash: bundle.payloadHash,
853
+ headerHash: bundle.headerHash,
854
+ })) as ProtocolV2ResourceBundleBinary[];
855
+ }
856
+
857
+ private async prefetchProtocolV2ResourceBundles(
858
+ bundles: ProtocolV2ResourceBundleBinary[]
859
+ ): Promise<ProtocolV2ResourceBundleBinary[]> {
860
+ const prefetched: ProtocolV2ResourceBundleBinary[] = [];
861
+ for (const bundle of bundles) {
862
+ let { binary } = bundle;
863
+ let downloadedFromRemote = false;
864
+ if (binary.byteLength === 0) {
865
+ if (!bundle.url) {
866
+ throw new Error(`Missing Protocol V2 RESC bundle binary: ${bundle.name}`);
867
+ }
868
+ Log.log(`[FirmwareUpdateV4] downloading remote RESC bundle ${bundle.name}`);
869
+ ({ binary } = await getSysResourceBinary(bundle.url));
870
+ downloadedFromRemote = true;
871
+ }
872
+ if (binary.byteLength === 0) {
873
+ throw new Error(`Protocol V2 RESC bundle is empty: ${bundle.name}`);
874
+ }
875
+ if (downloadedFromRemote) {
876
+ const header = parseProtocolV2OkppHeader(toProtocolV2Bytes(binary));
877
+ if (!header || header.type !== 'RESC') {
878
+ throw new Error(`Invalid Protocol V2 RESC bundle header: ${bundle.name}`);
879
+ }
880
+ if (bundle.version && compareProtocolV2Versions(header.version, bundle.version) !== 0) {
881
+ throw new Error(`Protocol V2 RESC bundle version mismatch: ${bundle.name}`);
882
+ }
883
+ const expectedPayloadHash = normalizeProtocolV2Hex(bundle.payloadHash);
884
+ if (expectedPayloadHash && header.payloadHash !== expectedPayloadHash) {
885
+ throw new Error(`Protocol V2 RESC bundle payload hash mismatch: ${bundle.name}`);
886
+ }
887
+ const expectedHeaderHash = normalizeProtocolV2Hex(bundle.headerHash);
888
+ if (expectedHeaderHash && header.headerHash !== expectedHeaderHash) {
889
+ throw new Error(`Protocol V2 RESC bundle header hash mismatch: ${bundle.name}`);
890
+ }
891
+ }
892
+ prefetched.push({ ...bundle, binary });
893
+ }
894
+ return prefetched;
895
+ }
896
+
897
+ /**
898
+ * Synchronize RESC bundles to the device.
899
+ *
900
+ * Manual mode writes supplied binaries directly.
901
+ * Remote-config mode uses prefetched binaries and skips matching bundles after FileRead.
902
+ */
903
+ private async syncProtocolV2ResourceBundles(
904
+ bundles: ProtocolV2ResourceBundleBinary[],
905
+ firmwareSize: number
906
+ ): Promise<{ processedSize: number; totalSize: number }> {
907
+ const transferStartTime = Date.now();
908
+ const transferTransport = this.getProtocolV2FirmwareTransferTransport();
909
+
910
+ const isRemoteMode = bundles.some(bundle => !!bundle.url);
911
+ let bundlesToSync = bundles;
912
+
913
+ // Remote binaries were prefetched before bootloader entry. Only device-local
914
+ // header comparison and transfer are allowed in this phase.
915
+ if (isRemoteMode) {
916
+ const filtered: ProtocolV2ResourceBundleBinary[] = [];
917
+ for (const bundle of bundles) {
918
+ // Compare the existing device header.
919
+ const upToDate = await this.isProtocolV2ResourceBundleUpToDate(bundle);
920
+ if (upToDate) {
921
+ Log.log(`[FirmwareUpdateV4] skip RESC bundle ${bundle.name}; already up to date`);
922
+ } else {
923
+ filtered.push(bundle);
924
+ }
925
+ }
926
+ bundlesToSync = filtered;
927
+ }
928
+
929
+ if (bundlesToSync.length === 0) {
930
+ Log.log('[FirmwareUpdateV4] all RESC bundles up to date, nothing to sync');
931
+ return { processedSize: 0, totalSize: firmwareSize };
932
+ }
933
+
934
+ // Write directly to the device through FileWrite.
935
+ let totalSize = 0;
936
+ for (const b of bundlesToSync) totalSize += b.binary.byteLength;
937
+
938
+ const transferTotalSize = totalSize + firmwareSize;
939
+ let processedSize = 0;
940
+ for (const bundle of bundlesToSync) {
941
+ Log.log(
942
+ `[FirmwareUpdateV4] syncing RESC bundle ${bundle.name} -> ${bundle.devicePath} bytes=${bundle.binary.byteLength}`
943
+ );
944
+ processedSize = await this.protocolV2CommonUpdateProcess({
945
+ payload: bundle.binary,
946
+ filePath: bundle.devicePath,
947
+ processedSize,
948
+ totalSize: transferTotalSize,
949
+ });
950
+ }
951
+
952
+ const elapsedMs = Date.now() - transferStartTime;
953
+ Log.log(
954
+ `[FirmwareUpdateV4] RESC bundle sync finished transport=${transferTransport} bytes=${totalSize} elapsed=${(
955
+ elapsedMs / 1000
956
+ ).toFixed(2)}s speed=${formatProtocolV2TransferSpeed(totalSize, elapsedMs)} KB/s`
957
+ );
958
+ return { processedSize, totalSize: transferTotalSize };
959
+ }
960
+
961
+ /**
962
+ * Compare the existing okpkg OKPP header in remote-config mode.
963
+ */
964
+ private async isProtocolV2ResourceBundleUpToDate(
965
+ bundle: ProtocolV2ResourceBundleBinary
966
+ ): Promise<boolean> {
967
+ if (this.params.forcedUpdateRes) return false;
968
+ if (!bundle.version && !bundle.payloadHash) return false;
969
+
970
+ try {
971
+ const header = await this.readProtocolV2DeviceFileHeader(bundle.devicePath);
972
+ if (!header) return false;
973
+
974
+ if (bundle.version) {
975
+ const cmp = compareProtocolV2Versions(header.version, bundle.version);
976
+ if (cmp === undefined || cmp !== 0) return false;
977
+ }
978
+ if (bundle.payloadHash) {
979
+ const expected = normalizeProtocolV2Hex(bundle.payloadHash);
980
+ if (expected && header.payloadHash !== expected) return false;
981
+ }
982
+ if (bundle.headerHash) {
983
+ const expected = normalizeProtocolV2Hex(bundle.headerHash);
984
+ if (expected && header.headerHash !== expected) return false;
985
+ }
986
+ return true;
987
+ } catch (error) {
988
+ Log.log(`[FirmwareUpdateV4] RESC bundle ${bundle.name} header check failed: `, error);
989
+ return false;
990
+ }
991
+ }
992
+
866
993
  private isProtocolV2BootloaderMode() {
867
994
  if (typeof this.device.isBootloader === 'function') {
868
995
  return this.device.isBootloader();
869
996
  }
870
- return !!this.device.features?.bootloaderMode;
997
+ return (
998
+ this.device.features?.mode === 'bootloader' ||
999
+ (this.device.features?.mode == null && !!this.device.features?.bootloaderMode)
1000
+ );
1001
+ }
1002
+
1003
+ private isProtocolV2RomloaderMode() {
1004
+ if (!this.device.isProtocolV2() || this.device.getCurrentDeviceType() !== EDeviceType.Pro2) {
1005
+ return false;
1006
+ }
1007
+ if (typeof this.device.isRomloader === 'function') {
1008
+ return this.device.isRomloader();
1009
+ }
1010
+ return this.device.features?.mode === 'romloader';
871
1011
  }
872
1012
 
873
1013
  async enterProtocolV2BootloaderMode() {
1014
+ // romloader is the first update environment and forwards targets to bootloader.
1015
+ // It rejects DeviceRebootType.Bootloader, so reuse the current connection.
1016
+ if (this.isProtocolV2RomloaderMode()) {
1017
+ Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
1018
+ return false;
1019
+ }
874
1020
  if (this.isProtocolV2BootloaderMode()) {
875
- Log.debug('Protocol V2 device is already in bootloader mode, skip reboot to bootloader');
1021
+ Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
876
1022
  return false;
877
1023
  }
878
1024
 
@@ -906,12 +1052,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
906
1052
  commands: this.device.getCommands(),
907
1053
  timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
908
1054
  });
909
- const features = this.device.updateProtocolV2Features(deviceInfo);
910
- if (features?.bootloaderMode) {
1055
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
1056
+ const features = await this.device.probeProtocolV2RuntimeState(
1057
+ deviceInfo,
1058
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1059
+ );
1060
+ if (features?.mode === 'bootloader') {
911
1061
  return features;
912
1062
  }
913
1063
  lastError = new Error('Protocol V2 device is reachable but is not in bootloader mode');
914
1064
  } catch (error) {
1065
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1066
+ throw error;
1067
+ }
915
1068
  lastError = error;
916
1069
  Log.log('Protocol V2 bootloader mode not ready, polling reconnect: ', error);
917
1070
  }
@@ -927,8 +1080,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
927
1080
  }
928
1081
 
929
1082
  /**
930
- * 收集按 DeviceFirmwareTargetType 拆分的显式目标二进制。
931
- * 文件名仅用于 staging 路径展示,target_id 已显式给定。
1083
+ * Collect explicit target binaries grouped by DeviceFirmwareTargetType.
1084
+ * Filenames are display-only staging paths because target_id is explicit.
932
1085
  */
933
1086
  private collectExplicitTargetBinaries() {
934
1087
  const entries: ProtocolV2TargetBinary[] = [];
@@ -965,23 +1118,48 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
965
1118
  }
966
1119
 
967
1120
  private async executeProtocolV2Update({
968
- resourceBinaryMap,
969
1121
  fwBinaryMap,
970
1122
  bootloaderBinary,
1123
+ installItems,
1124
+ resourceBundles,
971
1125
  }: {
972
- resourceBinaryMap: ProtocolV2TargetBinary[];
973
- fwBinaryMap: ProtocolV2TargetBinary[];
974
- bootloaderBinary: ArrayBuffer | null;
1126
+ fwBinaryMap?: ProtocolV2TargetBinary[];
1127
+ bootloaderBinary?: ArrayBuffer | null;
1128
+ installItems?: ProtocolV2InstallItem[];
1129
+ resourceBundles?: ProtocolV2ResourceBundleBinary[];
975
1130
  }) {
976
- let totalSize = 0;
977
- let processedSize = 0;
978
- let transferredSize = 0;
1131
+ const orderedInstallItems =
1132
+ installItems ??
1133
+ this.buildProtocolV2InstallItems({
1134
+ bootloaderBinary: bootloaderBinary ?? null,
1135
+ fwBinaryMap: fwBinaryMap ?? [],
1136
+ });
979
1137
 
980
- for (const resource of resourceBinaryMap) totalSize += resource.binary.byteLength;
981
- for (const fwbinary of fwBinaryMap) totalSize += fwbinary.binary.byteLength;
982
- if (bootloaderBinary) totalSize += bootloaderBinary.byteLength;
1138
+ let firmwareSize = 0;
1139
+ for (const item of orderedInstallItems) firmwareSize += item.binary.byteLength;
983
1140
 
984
1141
  this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
1142
+
1143
+ let processedSize = 0;
1144
+ let totalSize = firmwareSize;
1145
+ if (resourceBundles?.length) {
1146
+ const resourceTransfer = await this.syncProtocolV2ResourceBundles(
1147
+ resourceBundles,
1148
+ firmwareSize
1149
+ );
1150
+ processedSize = resourceTransfer.processedSize;
1151
+ totalSize = resourceTransfer.totalSize;
1152
+ }
1153
+
1154
+ // Skip staging and installation when the update contains RESC bundles only.
1155
+ if (orderedInstallItems.length === 0) {
1156
+ Log.log('[FirmwareUpdateV4] no firmware targets to install (RESC bundles only)');
1157
+ if (totalSize > 0) {
1158
+ this.postProgressMessage(100, 'transferData');
1159
+ }
1160
+ return;
1161
+ }
1162
+ let transferredSize = processedSize;
985
1163
  const transferStartTime = Date.now();
986
1164
  const transferTransport = this.getProtocolV2FirmwareTransferTransport();
987
1165
  const chunkSize = this.getProtocolV2FirmwareChunkSize();
@@ -992,64 +1170,27 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
992
1170
  `[FirmwareUpdateV4] transfer started transport=${transferTransport} total=${totalSize} bytes chunk=${chunkSize} bytes`
993
1171
  );
994
1172
 
995
- const resourceTargets: Array<{ target_id: number; path: string }> = [];
996
- const targets: Array<{ target_id: number; path: string }> = [];
1173
+ const stagedInstallTargets: ProtocolV2InstallTarget[] = [];
997
1174
 
998
1175
  try {
999
- for (const resource of resourceBinaryMap) {
1000
- const resourceFilePath = `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${resource.fileName}`;
1001
- Log.log(
1002
- `[FirmwareUpdateV4] staging resource via FilesystemFileWrite target=${resource.targetId} path=${resourceFilePath} bytes=${resource.binary.byteLength}`
1003
- );
1004
- processedSize = await this.protocolV2CommonUpdateProcess({
1005
- payload: resource.binary,
1006
- filePath: resourceFilePath,
1007
- processedSize,
1008
- totalSize,
1009
- onTransferredBytes,
1010
- });
1011
- transferredSize = processedSize;
1012
- resourceTargets.push({
1013
- target_id: resource.targetId,
1014
- path: resourceFilePath,
1015
- });
1016
- }
1017
-
1018
- if (bootloaderBinary) {
1019
- const bootloaderPath = `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}bootloader.bin`;
1176
+ for (const item of orderedInstallItems) {
1177
+ const filePath = this.getProtocolV2InstallItemStagingPath(item);
1020
1178
  Log.log(
1021
- `[FirmwareUpdateV4] staging bootloader via FilesystemFileWrite target=${ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER} path=${bootloaderPath} bytes=${bootloaderBinary.byteLength}`
1179
+ `[FirmwareUpdateV4] staging ${item.kind} via FilesystemFileWrite target=${item.targetId} path=${filePath} source=${item.fileName} bytes=${item.binary.byteLength}`
1022
1180
  );
1023
1181
  processedSize = await this.protocolV2CommonUpdateProcess({
1024
- payload: bootloaderBinary,
1025
- filePath: bootloaderPath,
1182
+ payload: item.binary,
1183
+ filePath,
1026
1184
  processedSize,
1027
1185
  totalSize,
1028
1186
  onTransferredBytes,
1029
1187
  });
1030
1188
  transferredSize = processedSize;
1031
- targets.push({
1032
- target_id: ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
1033
- path: bootloaderPath,
1034
- });
1035
- }
1189
+ await this.verifyProtocolV2StagedFile(filePath, item.binary.byteLength);
1036
1190
 
1037
- for (const fwbinary of fwBinaryMap) {
1038
- const firmwarePath = `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${fwbinary.fileName}`;
1039
- Log.log(
1040
- `[FirmwareUpdateV4] staging firmware via FilesystemFileWrite target=${fwbinary.targetId} path=${firmwarePath} bytes=${fwbinary.binary.byteLength}`
1041
- );
1042
- processedSize = await this.protocolV2CommonUpdateProcess({
1043
- payload: fwbinary.binary,
1044
- filePath: firmwarePath,
1045
- processedSize,
1046
- totalSize,
1047
- onTransferredBytes,
1048
- });
1049
- transferredSize = processedSize;
1050
- targets.push({
1051
- target_id: fwbinary.targetId,
1052
- path: firmwarePath,
1191
+ stagedInstallTargets.push({
1192
+ ...item,
1193
+ path: filePath,
1053
1194
  });
1054
1195
  }
1055
1196
 
@@ -1074,155 +1215,166 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1074
1215
  }
1075
1216
 
1076
1217
  this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
1077
- for (const resourceTarget of resourceTargets) {
1078
- const resourceTargetsBatch = [resourceTarget];
1079
- Log.log(
1080
- `[FirmwareUpdateV4] DeviceFirmwareUpdateRequest resources=${JSON.stringify(
1081
- resourceTargetsBatch
1082
- )}`
1083
- );
1084
- const startResponse = await this.protocolV2StartFirmwareUpdate({
1085
- targets: resourceTargetsBatch,
1086
- });
1087
- await this.waitForProtocolV2FirmwareUpdateComplete(resourceTargetsBatch, startResponse);
1088
- }
1089
- if (targets.length > 0) {
1090
- Log.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest targets=${JSON.stringify(targets)}`);
1091
- const startResponse = await this.protocolV2StartFirmwareUpdate({ targets });
1092
- await this.waitForProtocolV2FirmwareUpdateComplete(targets, startResponse);
1093
- }
1094
- }
1095
-
1096
- private async queryProtocolV2FirmwareUpdateStatus() {
1097
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1098
- return typedCall(
1099
- 'DeviceFirmwareUpdateStatusGet',
1100
- 'DeviceFirmwareUpdateStatus',
1101
- {},
1102
- {
1103
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1104
- }
1105
- );
1106
- }
1107
1218
 
1108
- private async pingProtocolV2Device() {
1109
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1110
- await typedCall(
1111
- 'Ping',
1112
- 'Success',
1113
- { message: 'firmware-update' },
1114
- {
1115
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1116
- }
1117
- );
1219
+ const allTargets = stagedInstallTargets.map(item => ({
1220
+ target_id: item.targetId,
1221
+ path: item.path,
1222
+ }));
1223
+ Log.log(`[FirmwareUpdateV4] DeviceFirmwareUpdateRequest targets=${JSON.stringify(allTargets)}`);
1224
+ await this.protocolV2StartFirmwareUpdate({ targets: allTargets });
1225
+ await this.waitForProtocolV2FirmwareUpdateComplete(allTargets);
1118
1226
  }
1119
1227
 
1120
- private isProtocolV2NormalModeFeatures(features?: Features | null) {
1121
- return !!features && !features.bootloaderMode && features.mode !== 'bootloader';
1228
+ private getProtocolV2InstallItemStagingPath(item: ProtocolV2InstallItem) {
1229
+ return `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${item.fileName}`;
1122
1230
  }
1123
1231
 
1124
- private async probeProtocolV2NormalMode() {
1125
- const deviceInfo = await requestProtocolV2DeviceInfo({
1126
- commands: this.device.getCommands(),
1127
- timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1128
- request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1129
- });
1130
- const features = this.device.updateProtocolV2Features(deviceInfo);
1131
- if (this.isProtocolV2NormalModeFeatures(features)) {
1132
- Log.log('Protocol V2 firmware install finished; device is back in normal mode');
1133
- return true;
1232
+ private async verifyProtocolV2StagedFile(path: string, expectedSize: number) {
1233
+ const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1234
+ const response = await typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path });
1235
+ const actualSize = toProtocolV2FiniteNumber(response.message?.size);
1236
+ if (!response.message?.exist || response.message?.directory || actualSize !== expectedSize) {
1237
+ throw ERRORS.TypedError(
1238
+ HardwareErrorCode.EmmcFileWriteFirmwareError,
1239
+ `staged file verification failed: path=${path} exist=${!!response.message
1240
+ ?.exist} expected=${expectedSize} actual=${actualSize ?? 'unknown'}`
1241
+ );
1134
1242
  }
1135
- return false;
1136
1243
  }
1137
1244
 
1138
1245
  private assertProtocolV2TargetStatus(
1139
1246
  statusTargets: ProtocolV2FirmwareUpdateStatusTarget[],
1140
1247
  expectedTargetIds: Set<number>
1141
1248
  ) {
1249
+ Log.log(
1250
+ `[FirmwareUpdateV4] DeviceFirmwareUpdateStatus records=${JSON.stringify(statusTargets)}`
1251
+ );
1142
1252
  const failedTarget = statusTargets.find(
1143
1253
  target =>
1144
1254
  expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1145
1255
  isProtocolV2TargetStatusFailed(target.status)
1146
1256
  );
1147
1257
  if (failedTarget) {
1258
+ const failedTargetDetails = JSON.stringify({
1259
+ targetId: failedTarget.target_id,
1260
+ status: failedTarget.status,
1261
+ payloadVersion: failedTarget.payload_version,
1262
+ path: failedTarget.path,
1263
+ });
1264
+ Log.error(`[FirmwareUpdateV4] firmware install failed target=${failedTargetDetails}`);
1148
1265
  throw ERRORS.TypedError(
1149
1266
  HardwareErrorCode.FirmwareError,
1150
- `Protocol V2 firmware target ${failedTarget.target_id} failed`
1267
+ `Protocol V2 firmware target failed: target=${failedTarget.target_id} status=${
1268
+ failedTarget.status ?? 'unknown'
1269
+ } payloadVersion=${failedTarget.payload_version ?? 'unknown'} path=${
1270
+ failedTarget.path ?? 'unknown'
1271
+ }`
1151
1272
  );
1152
1273
  }
1153
1274
 
1154
- const completedTargets = statusTargets.filter(
1155
- target =>
1156
- expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1157
- isProtocolV2TargetStatusFinished(target.status)
1275
+ const matchingTargets = statusTargets.filter(target =>
1276
+ expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1)
1158
1277
  );
1159
- if (completedTargets.length === expectedTargetIds.size && expectedTargetIds.size > 0) {
1278
+ const completedTargetIds = new Set<number>();
1279
+ matchingTargets.forEach(target => {
1280
+ const targetId = normalizeProtocolV2TargetId(target.target_id);
1281
+ if (targetId !== undefined && isProtocolV2TargetStatusFinished(target.status)) {
1282
+ completedTargetIds.add(targetId);
1283
+ }
1284
+ });
1285
+ const allExpectedTargetsCompleted =
1286
+ expectedTargetIds.size > 0 &&
1287
+ Array.from(expectedTargetIds).every(targetId => completedTargetIds.has(targetId));
1288
+ if (allExpectedTargetsCompleted) {
1289
+ this.postProgressMessage(100, 'installingFirmware');
1160
1290
  return true;
1161
1291
  }
1162
1292
 
1163
- const inProgressTarget = statusTargets.find(
1164
- target =>
1165
- expectedTargetIds.has(normalizeProtocolV2TargetId(target.target_id) ?? -1) &&
1293
+ if (expectedTargetIds.size > 0 && matchingTargets.length > 0) {
1294
+ const hasInProgressTarget = matchingTargets.some(target =>
1166
1295
  isProtocolV2TargetStatusInProgress(target.status)
1167
- );
1168
- if (inProgressTarget) {
1169
- this.postProgressMessage(99, 'installingFirmware');
1296
+ );
1297
+ const completedProgress = Math.floor(
1298
+ (completedTargetIds.size / expectedTargetIds.size) * 100
1299
+ );
1300
+ // The protocol exposes no per-target percentage, so report coarse progress by
1301
+ // completed targets and use 1% once work starts to keep the UI responsive.
1302
+ const progress = Math.min(99, Math.max(completedProgress, hasInProgressTarget ? 1 : 0));
1303
+ this.postProgressMessage(progress, 'installingFirmware');
1170
1304
  }
1171
1305
 
1172
1306
  return false;
1173
1307
  }
1174
1308
 
1175
1309
  private async waitForProtocolV2FirmwareUpdateComplete(
1176
- targets: Array<{ target_id: number; path: string }>,
1177
- startResponse?: ProtocolV2FirmwareUpdateStartResponse
1310
+ targets: Array<{ target_id: number; path: string }>
1178
1311
  ) {
1179
1312
  const expectedTargetIds = new Set(targets.map(target => target.target_id));
1180
- if (startResponse?.type === 'DeviceFirmwareUpdateStatus') {
1181
- const statusTargets = (startResponse.message.records ??
1182
- []) as ProtocolV2FirmwareUpdateStatusTarget[];
1183
- if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
1184
- return;
1185
- }
1186
- }
1187
-
1188
1313
  const startTime = Date.now();
1189
1314
  let lastError: unknown;
1190
1315
 
1191
1316
  while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
1192
1317
  try {
1193
- const statusRes = await this.queryProtocolV2FirmwareUpdateStatus();
1194
- const statusTargets = (statusRes.message.records ??
1195
- []) as ProtocolV2FirmwareUpdateStatusTarget[];
1196
- if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds)) {
1197
- return;
1198
- }
1199
- } catch (error) {
1200
- lastError = error;
1201
- if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
1202
- throw error;
1203
- }
1204
- Log.log('Protocol V2 firmware install status polling failed: ', error);
1205
- if (isProtocolV2PollingTransientError(error)) {
1206
- try {
1207
- await this.reconnectProtocolV2Device();
1208
- if (await this.probeProtocolV2NormalMode()) {
1318
+ await this.reconnectProtocolV2Device();
1319
+ const deviceInfo = await this.verifyProtocolV2ReconnectIdentity();
1320
+ try {
1321
+ const statusResponse = await this.device.getCommands().typedCall(
1322
+ 'DeviceFirmwareUpdateStatusGet',
1323
+ 'DeviceFirmwareUpdateStatus',
1324
+ {
1325
+ fields: {
1326
+ status: true,
1327
+ payload_version: true,
1328
+ path: true,
1329
+ },
1330
+ },
1331
+ { timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT }
1332
+ );
1333
+ if (
1334
+ this.assertProtocolV2TargetStatus(
1335
+ (statusResponse.message.records ?? []) as ProtocolV2FirmwareUpdateStatusTarget[],
1336
+ expectedTargetIds
1337
+ )
1338
+ ) {
1339
+ return;
1340
+ }
1341
+ lastError = new Error('Protocol V2 firmware targets are still installing');
1342
+ } catch (error) {
1343
+ if (
1344
+ error instanceof HardwareError &&
1345
+ error.errorCode === HardwareErrorCode.FirmwareError
1346
+ ) {
1347
+ throw error;
1348
+ }
1349
+ // App firmware does not register DeviceFirmwareUpdateStatusGet. Treat the
1350
+ // missing endpoint as completion only after the runtime probe confirms App mode.
1351
+ if (isProtocolV2FirmwareStatusEndpointUnavailable(error)) {
1352
+ if (await this.probeProtocolV2NormalMode(deviceInfo)) {
1353
+ Log.log(
1354
+ '[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot'
1355
+ );
1209
1356
  return;
1210
1357
  }
1211
- } catch (reconnectError) {
1212
- lastError = reconnectError;
1358
+ lastError = new Error(
1359
+ 'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
1360
+ );
1361
+ } else {
1362
+ lastError = error;
1213
1363
  Log.log(
1214
- 'Protocol V2 firmware install reconnect/normal-mode probe failed: ',
1215
- reconnectError
1364
+ '[FirmwareUpdateV4] DeviceFirmwareUpdateStatusGet unavailable during install: ',
1365
+ error
1216
1366
  );
1217
1367
  }
1218
- try {
1219
- await this.pingProtocolV2Device();
1220
- Log.log('Protocol V2 firmware status unavailable, Ping is ready');
1221
- } catch (pingError) {
1222
- lastError = pingError;
1223
- Log.log('Protocol V2 firmware install Ping polling failed: ', pingError);
1224
- }
1225
1368
  }
1369
+ } catch (error) {
1370
+ lastError = error;
1371
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1372
+ throw error;
1373
+ }
1374
+ if (error instanceof HardwareError && error.errorCode === HardwareErrorCode.FirmwareError) {
1375
+ throw error;
1376
+ }
1377
+ Log.log('Protocol V2 firmware install device readiness probe failed: ', error);
1226
1378
  }
1227
1379
  await wait(1000);
1228
1380
  }
@@ -1234,22 +1386,24 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1234
1386
  }
1235
1387
 
1236
1388
  private async exitProtocolV2BootloaderToNormal() {
1237
- this.postTipMessage(FirmwareUpdateTipMessage.SwitchFirmwareReconnectDevice);
1238
- try {
1239
- await this.reconnectProtocolV2Device();
1240
- if (await this.probeProtocolV2NormalMode()) {
1241
- Log.log('Protocol V2 device is already in normal mode, skip normal reboot');
1242
- return;
1243
- }
1244
- } catch (error) {
1245
- Log.log('Protocol V2 normal-mode probe before reboot failed: ', error);
1246
- }
1389
+ await this.reconnectProtocolV2Device();
1390
+ await this.verifyProtocolV2ReconnectIdentity();
1391
+ // The connection may still be in bootloader. Request a Normal reboot directly;
1392
+ // repeating it after an automatic App reboot is idempotent.
1247
1393
  await this.protocolV2Reboot(DeviceRebootType.Normal);
1248
1394
  }
1249
1395
 
1396
+ private async probeProtocolV2NormalMode(deviceInfo: ProtocolV2DeviceInfo) {
1397
+ const features = await this.device.probeProtocolV2RuntimeState(
1398
+ deviceInfo,
1399
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1400
+ );
1401
+ return features.mode === 'normal' && !features.bootloaderMode;
1402
+ }
1403
+
1250
1404
  private async waitForProtocolV2FinalFeatures() {
1251
1405
  const features = await this.waitForProtocolV2ReconnectAndFeatures(
1252
- PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT
1406
+ PROTOCOL_V2_FINAL_RECONNECT_TIMEOUT
1253
1407
  );
1254
1408
 
1255
1409
  const bootloaderVersion = getDeviceBootloaderVersion(features).join('.');
@@ -1278,11 +1432,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1278
1432
  const deviceInfo = await requestProtocolV2DeviceInfo({
1279
1433
  commands: this.device.getCommands(),
1280
1434
  timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT,
1281
- // 更新完成判定只需要各 target 版本号;scope 与请求内容保持一致
1435
+ // Completion needs target versions only; keep scope aligned with the request.
1282
1436
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
1283
1437
  });
1284
- const features = this.device.updateProtocolV2Features(deviceInfo);
1285
- if (features.bootloaderMode || features.mode === 'bootloader') {
1438
+ this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
1439
+ const features = await this.device.probeProtocolV2RuntimeState(
1440
+ deviceInfo,
1441
+ PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
1442
+ );
1443
+ if (features.mode !== 'normal' || features.bootloaderMode) {
1286
1444
  throw ERRORS.TypedError(
1287
1445
  HardwareErrorCode.DeviceNotFound,
1288
1446
  'Protocol V2 device is still in bootloader mode'
@@ -1290,6 +1448,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1290
1448
  }
1291
1449
  return features;
1292
1450
  } catch (error) {
1451
+ if (this.isProtocolV2ReconnectIdentityError(error)) {
1452
+ throw error;
1453
+ }
1293
1454
  lastError = error;
1294
1455
  Log.log('Protocol V2 normal mode not ready, polling Ping: ', error);
1295
1456
  await wait(1000);
@@ -1324,15 +1485,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1324
1485
  },
1325
1486
  true
1326
1487
  );
1327
- await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, { throwOnRunPromiseError: true });
1488
+ await this.ensureProtocolV2DeviceAcquired();
1328
1489
  this.device.commands.disposed = false;
1329
1490
  this.device.getCommands().mainId = this.device.mainId ?? '';
1330
- await this.device.initialize();
1331
1491
  return;
1332
1492
  }
1333
1493
 
1334
- // App bootloader 序列号暂时可能不一致。V4 升级重连阶段只接受唯一枚举设备,
1335
- // 避免继续按旧 app connectId 查缓存导致反复输出 path mismatch 日志。
1494
+ // App and bootloader serials may differ temporarily. During V4 reconnect, accept
1495
+ // only a uniquely enumerated device instead of repeatedly using the old App path.
1336
1496
  const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
1337
1497
  connectProtocol: PROTOCOL_V2_CONNECT_PROTOCOL,
1338
1498
  });
@@ -1345,24 +1505,60 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1345
1505
  deviceList[0].getConnectId()
1346
1506
  );
1347
1507
  this.device.updateFromCache(deviceList[0]);
1348
- await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, { throwOnRunPromiseError: true });
1508
+ await this.ensureProtocolV2DeviceAcquired();
1349
1509
  this.device.commands.disposed = false;
1350
1510
  this.device.getCommands().mainId = this.device.mainId ?? '';
1351
- await this.device.initialize();
1352
1511
  }
1353
1512
 
1354
- private async protocolV2CommonUpdateProcess({
1513
+ /**
1514
+ * After acquiring a USB session, polling reuses its command channel. Reacquire only
1515
+ * after reboot or enumeration changes cause hasDeviceAcquire() to become false.
1516
+ */
1517
+ private async ensureProtocolV2DeviceAcquired() {
1518
+ const commands = this.device.getCommands();
1519
+ if (this.device.hasDeviceAcquire() && !commands.disposed) {
1520
+ return;
1521
+ }
1522
+ await this.device.acquire(PROTOCOL_V2_CONNECT_PROTOCOL, {
1523
+ throwOnRunPromiseError: true,
1524
+ });
1525
+ }
1526
+
1527
+ private isProtocolV2ReconnectIdentityError(error: unknown) {
1528
+ return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
1529
+ }
1530
+
1531
+ private async protocolV2CommonUpdateProcess(params: ProtocolV2FileTransferParams) {
1532
+ let lastError: unknown;
1533
+ for (let attempt = 1; attempt <= PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT; attempt += 1) {
1534
+ try {
1535
+ return await this.protocolV2WriteWholeFile(params);
1536
+ } catch (error) {
1537
+ lastError = error;
1538
+ Log.error(
1539
+ `Protocol V2 file transfer failed path=${params.filePath} attempt=${attempt}/${PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT}; restarting from offset 0`,
1540
+ error
1541
+ );
1542
+ if (attempt === PROTOCOL_V2_FILE_TRANSFER_RETRY_COUNT) {
1543
+ break;
1544
+ }
1545
+ await this.recoverProtocolV2FileTransfer();
1546
+ }
1547
+ }
1548
+
1549
+ throw ERRORS.TypedError(
1550
+ HardwareErrorCode.EmmcFileWriteFirmwareError,
1551
+ `transfer data error: ${getProtocolV2UnknownErrorText(lastError)}`
1552
+ );
1553
+ }
1554
+
1555
+ private async protocolV2WriteWholeFile({
1355
1556
  payload,
1356
1557
  filePath,
1357
1558
  processedSize,
1358
1559
  totalSize,
1359
1560
  onTransferredBytes,
1360
- }: PROTO.FirmwareUpload & {
1361
- filePath: string;
1362
- processedSize?: number;
1363
- totalSize?: number;
1364
- onTransferredBytes?: (transferredBytes: number) => void;
1365
- }) {
1561
+ }: ProtocolV2FileTransferParams) {
1366
1562
  const chunkSize = this.getProtocolV2FirmwareChunkSize();
1367
1563
  let offset = 0;
1368
1564
  const getUploadProgress = (fileOffset: number) => {
@@ -1383,7 +1579,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1383
1579
  totalSize ?? payload.byteLength
1384
1580
  );
1385
1581
 
1386
- const writeRes = await this.fileWriteWithRetry(
1582
+ const writeRes = await this.fileWriteChunk(
1387
1583
  filePath,
1388
1584
  payload.byteLength,
1389
1585
  offset,
@@ -1391,12 +1587,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1391
1587
  overwrite,
1392
1588
  progress
1393
1589
  );
1394
- const processedByte = Number(writeRes.message.processed_byte);
1395
- const nextOffset =
1396
- Number.isFinite(processedByte) && processedByte > offset
1397
- ? processedByte
1398
- : offset + chunkLength;
1399
- if (nextOffset <= offset || nextOffset > payload.byteLength) {
1590
+ const rawProcessedByte = writeRes.message.processed_byte;
1591
+ const processedByte = Number(rawProcessedByte);
1592
+ const nextOffset = rawProcessedByte === undefined ? offset + chunkLength : processedByte;
1593
+ if (!Number.isFinite(nextOffset) || nextOffset <= offset || nextOffset > chunkEnd) {
1400
1594
  throw ERRORS.TypedError(
1401
1595
  HardwareErrorCode.EmmcFileWriteFirmwareError,
1402
1596
  `invalid processed_byte ${writeRes.message.processed_byte} for offset ${offset}`
@@ -1424,7 +1618,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1424
1618
  return env ?? 'unknown';
1425
1619
  }
1426
1620
 
1427
- private async fileWriteWithRetry(
1621
+ private async fileWriteChunk(
1428
1622
  filePath: string,
1429
1623
  totalFileSize: number,
1430
1624
  offset: number,
@@ -1432,57 +1626,38 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1432
1626
  overwrite: boolean,
1433
1627
  progress: number | null
1434
1628
  ): Promise<TypedResponseMessage<'FilesystemFile'>> {
1435
- const writeFunc = async () => {
1436
- const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1437
- const writeRes = await typedCall('FilesystemFileWrite', 'FilesystemFile', {
1438
- file: {
1439
- path: filePath,
1440
- offset,
1441
- total_size: totalFileSize,
1442
- data: chunk,
1443
- },
1444
- overwrite,
1445
- append: false,
1446
- ui_percentage: progress ?? undefined,
1447
- });
1448
- if (writeRes.type !== 'FilesystemFile') {
1449
- if ((writeRes as any).type === 'CallMethodError') {
1450
- if (((writeRes as any).message.error ?? '').indexOf(SESSION_ERROR) > -1) {
1451
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
1452
- }
1629
+ const typedCall = this.device.getCommands().typedCall.bind(this.device.getCommands());
1630
+ const writeRes = await typedCall('FilesystemFileWrite', 'FilesystemFile', {
1631
+ file: {
1632
+ path: filePath,
1633
+ offset,
1634
+ total_size: totalFileSize,
1635
+ data: chunk,
1636
+ },
1637
+ overwrite,
1638
+ append: false,
1639
+ ui_percentage: progress ?? undefined,
1640
+ });
1641
+ if (writeRes.type !== 'FilesystemFile') {
1642
+ if ((writeRes as any).type === 'CallMethodError') {
1643
+ if (((writeRes as any).message.error ?? '').indexOf(SESSION_ERROR) > -1) {
1644
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
1453
1645
  }
1454
- throw ERRORS.TypedError(
1455
- HardwareErrorCode.EmmcFileWriteFirmwareError,
1456
- 'transfer data error'
1457
- );
1458
1646
  }
1459
- return writeRes;
1460
- };
1647
+ throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, 'transfer data error');
1648
+ }
1649
+ return writeRes;
1650
+ }
1461
1651
 
1462
- let retryCount = 10;
1463
- while (retryCount > 0) {
1464
- try {
1465
- const result = await writeFunc();
1466
- return result;
1467
- } catch (error) {
1468
- Log.error(`fileWrite error: `, error);
1469
- retryCount--;
1470
- if (retryCount === 0) {
1471
- throw ERRORS.TypedError(
1472
- HardwareErrorCode.EmmcFileWriteFirmwareError,
1473
- 'transfer data error'
1474
- );
1475
- }
1476
- const env = DataManager.getSettings('env');
1477
- if (DataManager.isBleConnect(env)) {
1478
- await wait(3000);
1479
- await this.acquireProtocolV2BleDevice();
1480
- await this.device.initialize();
1481
- }
1482
- await wait(2000);
1483
- }
1652
+ private async recoverProtocolV2FileTransfer() {
1653
+ const env = DataManager.getSettings('env');
1654
+ if (DataManager.isBleConnect(env)) {
1655
+ await wait(3000);
1484
1656
  }
1485
- throw ERRORS.TypedError(HardwareErrorCode.EmmcFileWriteFirmwareError, 'transfer data error');
1657
+ await this.reconnectProtocolV2Device();
1658
+ await this.verifyProtocolV2ReconnectIdentity();
1659
+ await this.device.initialize();
1660
+ await wait(2000);
1486
1661
  }
1487
1662
 
1488
1663
  private async acquireProtocolV2BleDevice() {
@@ -1500,35 +1675,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1500
1675
  targets: Array<{ target_id: number; path: string }>;
1501
1676
  }) {
1502
1677
  const commands = this.device.getCommands();
1503
- let response: ProtocolV2FirmwareUpdateStartResponse;
1504
- try {
1505
- response = await commands.typedCall(
1506
- 'DeviceFirmwareUpdateRequest',
1507
- PROTOCOL_V2_FIRMWARE_UPDATE_RESPONSE_TYPES,
1508
- {
1509
- targets,
1510
- },
1511
- {
1512
- intermediateTypes: ['DeviceFirmwareUpdateStatus'],
1513
- timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT,
1514
- onIntermediateResponse: (response: { type?: string }) => {
1515
- if (response.type === 'DeviceFirmwareUpdateStatus') {
1516
- this.postProgressMessage(99, 'installingFirmware');
1517
- }
1518
- },
1519
- }
1520
- );
1521
- } catch (error) {
1522
- if (isProtocolV2StartUpdateTransientError(error)) {
1523
- Log.log(
1524
- 'Protocol V2 firmware update request did not return; continue status polling',
1525
- error
1526
- );
1527
- } else {
1528
- throw error;
1529
- }
1530
- }
1678
+ const response: ProtocolV2FirmwareUpdateStartResponse = await commands.typedCall(
1679
+ 'DeviceFirmwareUpdateRequest',
1680
+ 'Success',
1681
+ { targets },
1682
+ { timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
1683
+ );
1684
+ // Success acknowledges that the device accepted installation. End confirmation
1685
+ // and begin status polling only after receiving this ACK.
1531
1686
  this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
1687
+ this.postProgressMessage(0, 'installingFirmware');
1532
1688
  return response;
1533
1689
  }
1534
1690
 
@@ -1538,9 +1694,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1538
1694
  const res = await typedCall('DeviceReboot', 'Success', {
1539
1695
  reboot_type: rebootType,
1540
1696
  });
1697
+ this.device.markProtocolV2Reboot(rebootType);
1541
1698
  return res.message;
1542
1699
  } catch (error) {
1543
1700
  if (isProtocolV2DeviceDisconnectedError(error) || isProtocolV2ReconnectProbeError(error)) {
1701
+ this.device.markProtocolV2Reboot(rebootType);
1544
1702
  return { message: 'Device rebooted successfully' };
1545
1703
  }
1546
1704
  throw error;