@onekeyfe/hd-core 1.2.0-alpha.5 → 1.2.0-alpha.50

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