@onekeyfe/hd-core 1.2.0-alpha.66 → 1.2.0-alpha.67

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 (315) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +0 -313
  2. package/__tests__/DeviceCommands.test.ts +13 -59
  3. package/__tests__/DeviceEventRegistration.test.ts +0 -6
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +3 -198
  5. package/__tests__/connectSettings.test.ts +47 -5
  6. package/__tests__/device-initialize-timeout.test.ts +56 -0
  7. package/__tests__/device-lifecycle-events.test.ts +3 -105
  8. package/__tests__/device-pool-state.test.ts +0 -22
  9. package/__tests__/device-settings.test.ts +18 -39
  10. package/__tests__/device-state-contract.test.ts +0 -1
  11. package/__tests__/device-state-mapper.test.ts +1 -13
  12. package/__tests__/device-utils.test.ts +1 -48
  13. package/__tests__/deviceSettings.test.ts +1 -11
  14. package/__tests__/firmware-update/check-all-firmware-release.test.ts +175 -0
  15. package/__tests__/firmware-update/device-update-bootloader.test.ts +87 -0
  16. package/__tests__/firmware-update/firmware-artifact-source.test.ts +119 -0
  17. package/__tests__/firmware-update/firmware-host-binding.test.ts +70 -0
  18. package/__tests__/firmware-update/firmware-preparation-error.test.ts +27 -0
  19. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +200 -0
  20. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +13 -0
  21. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +394 -0
  22. package/__tests__/firmware-update/firmware-update-plan.test.ts +593 -0
  23. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +231 -0
  24. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +59 -31
  25. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +58 -0
  26. package/__tests__/firmware-update/firmware-upload-source.test.ts +70 -0
  27. package/__tests__/get-device-state.test.ts +12 -132
  28. package/__tests__/homescreen.test.ts +1 -41
  29. package/__tests__/kaspa-use-tweak-pro2.test.ts +2 -2
  30. package/__tests__/kaspaSignTransaction.test.ts +26 -3
  31. package/__tests__/logBlockEvent.test.ts +1 -1
  32. package/__tests__/method-protocol-support.test.ts +0 -19
  33. package/__tests__/open-wallet-session.test.ts +37 -568
  34. package/__tests__/protocol-v2-unlock-policy.test.ts +37 -300
  35. package/__tests__/protocol-v2.test.ts +1153 -1458
  36. package/__tests__/protocolV2FileWrite.test.ts +0 -152
  37. package/__tests__/protocolV2UiInteraction.test.ts +0 -63
  38. package/__tests__/public-pro2-api-boundary.test.ts +0 -1
  39. package/__tests__/search-devices.test.ts +3 -12
  40. package/__tests__/tron-sign-message-init.test.ts +2 -2
  41. package/dist/api/BaseMethod.d.ts +1 -3
  42. package/dist/api/BaseMethod.d.ts.map +1 -1
  43. package/dist/api/CheckAllFirmwareRelease.d.ts +1 -2
  44. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  45. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  46. package/dist/api/FirmwareUpdateV2.d.ts +10 -0
  47. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  48. package/dist/api/FirmwareUpdateV3.d.ts +7 -3
  49. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  50. package/dist/api/FirmwareUpdateV4.d.ts +27 -13
  51. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  52. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  53. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  54. package/dist/api/SearchDevices.d.ts.map +1 -1
  55. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  56. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  57. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  58. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  59. package/dist/api/device/DeviceUpdateBootloader.d.ts +5 -1
  60. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  61. package/dist/api/firmware/FirmwareArtifactSource.d.ts +25 -0
  62. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +1 -0
  63. package/dist/api/firmware/FirmwareHostBinding.d.ts +6 -0
  64. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +1 -0
  65. package/dist/api/firmware/FirmwarePreparationError.d.ts +3 -0
  66. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +1 -0
  67. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +11 -4
  68. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  69. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +3 -0
  70. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +1 -0
  71. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +25 -0
  72. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +1 -0
  73. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +32 -0
  74. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +1 -0
  75. package/dist/api/firmware/getBinary.d.ts +7 -0
  76. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  77. package/dist/api/firmware/progressThrottle.d.ts +3 -0
  78. package/dist/api/firmware/progressThrottle.d.ts.map +1 -0
  79. package/dist/api/firmware/updateBootloader.d.ts +2 -0
  80. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  81. package/dist/api/firmware/uploadFirmware.d.ts +9 -1
  82. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  83. package/dist/api/helpers/protocolV2FileWrite.d.ts +0 -9
  84. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  85. package/dist/api/index.d.ts +0 -2
  86. package/dist/api/index.d.ts.map +1 -1
  87. package/dist/api/kaspa/KaspaGetAddress.d.ts +1 -1
  88. package/dist/api/kaspa/KaspaSignTransaction.d.ts +1 -1
  89. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  90. package/dist/api/polkadot/PolkadotGetAddress.d.ts +1 -1
  91. package/dist/api/polkadot/networks.d.ts +1 -1
  92. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  93. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  94. package/dist/api/solana/SolSignMessage.d.ts +1 -1
  95. package/dist/api/solana/SolSignOffchainMessage.d.ts +1 -1
  96. package/dist/api/solana/SolSignTransaction.d.ts +2 -2
  97. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  98. package/dist/api/sui/SuiGetAddress.d.ts +1 -1
  99. package/dist/api/sui/SuiGetPublicKey.d.ts +1 -1
  100. package/dist/api/sui/SuiSignMessage.d.ts +1 -1
  101. package/dist/api/sui/SuiSignTransaction.d.ts +1 -1
  102. package/dist/api/ton/TonGetAddress.d.ts +1 -1
  103. package/dist/api/ton/TonSignMessage.d.ts +1 -1
  104. package/dist/api/ton/TonSignProof.d.ts +1 -1
  105. package/dist/api/tron/TronSignMessage.d.ts +2 -2
  106. package/dist/api/tron/TronSignTransaction.d.ts +1 -1
  107. package/dist/core/deviceEventRegistration.d.ts +0 -2
  108. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  109. package/dist/core/index.d.ts.map +1 -1
  110. package/dist/data-manager/DataManager.d.ts +4 -9
  111. package/dist/data-manager/DataManager.d.ts.map +1 -1
  112. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  113. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  114. package/dist/device/Device.d.ts +6 -29
  115. package/dist/device/Device.d.ts.map +1 -1
  116. package/dist/device/DeviceCommands.d.ts +4 -4
  117. package/dist/device/DeviceCommands.d.ts.map +1 -1
  118. package/dist/device/DeviceConnector.d.ts +1 -2
  119. package/dist/device/DeviceConnector.d.ts.map +1 -1
  120. package/dist/device/DevicePool.d.ts.map +1 -1
  121. package/dist/deviceProfile/protocolV2DeviceIdentity.d.ts.map +1 -1
  122. package/dist/events/device.d.ts +0 -4
  123. package/dist/events/device.d.ts.map +1 -1
  124. package/dist/events/logBlockEvent.d.ts.map +1 -1
  125. package/dist/events/ui-promise.d.ts +2 -4
  126. package/dist/events/ui-promise.d.ts.map +1 -1
  127. package/dist/events/ui-request.d.ts +2 -31
  128. package/dist/events/ui-request.d.ts.map +1 -1
  129. package/dist/events/ui-response.d.ts +2 -10
  130. package/dist/events/ui-response.d.ts.map +1 -1
  131. package/dist/index.d.ts +247 -243
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.js +3773 -3054
  134. package/dist/inject.d.ts +1 -6
  135. package/dist/inject.d.ts.map +1 -1
  136. package/dist/lowLevelInject.d.ts.map +1 -1
  137. package/dist/protocols/protocol-v2/features.d.ts +4 -0
  138. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  139. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  140. package/dist/protocols/protocol-v2/lockedError.d.ts +2 -0
  141. package/dist/protocols/protocol-v2/lockedError.d.ts.map +1 -0
  142. package/dist/protocols/protocol-v2/uiInteraction.d.ts +4 -7
  143. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  144. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +3 -1
  145. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  146. package/dist/protocols/protocol-v2/unlockRetry.d.ts +10 -0
  147. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -0
  148. package/dist/protocols/protocol-v2/walletSession.d.ts +1 -6
  149. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  150. package/dist/topLevelInject.d.ts.map +1 -1
  151. package/dist/types/api/checkAllFirmwareRelease.d.ts +5 -3
  152. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  153. package/dist/types/api/deviceUnlock.d.ts +1 -5
  154. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  155. package/dist/types/api/deviceUpdateBootloader.d.ts +6 -0
  156. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  157. package/dist/types/api/export.d.ts +4 -2
  158. package/dist/types/api/export.d.ts.map +1 -1
  159. package/dist/types/api/firmwareUpdate.d.ts +70 -4
  160. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  161. package/dist/types/api/firmwareUpdateCapabilities.d.ts +9 -0
  162. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +1 -0
  163. package/dist/types/api/firmwareUpdatePlan.d.ts +28 -0
  164. package/dist/types/api/firmwareUpdatePlan.d.ts.map +1 -0
  165. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +42 -0
  166. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +1 -0
  167. package/dist/types/api/index.d.ts +10 -7
  168. package/dist/types/api/index.d.ts.map +1 -1
  169. package/dist/types/api/protocolV2.d.ts +0 -3
  170. package/dist/types/api/protocolV2.d.ts.map +1 -1
  171. package/dist/types/device.d.ts +2 -2
  172. package/dist/types/device.d.ts.map +1 -1
  173. package/dist/types/params.d.ts +0 -1
  174. package/dist/types/params.d.ts.map +1 -1
  175. package/dist/types/settings.d.ts +21 -38
  176. package/dist/types/settings.d.ts.map +1 -1
  177. package/dist/utils/deviceFeaturesCompat.d.ts +1 -0
  178. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  179. package/dist/utils/deviceFeaturesUtils.d.ts +0 -4
  180. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  181. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  182. package/dist/utils/deviceSettings.d.ts.map +1 -1
  183. package/dist/utils/homescreen.d.ts +0 -4
  184. package/dist/utils/homescreen.d.ts.map +1 -1
  185. package/dist/utils/index.d.ts +1 -1
  186. package/dist/utils/index.d.ts.map +1 -1
  187. package/dist/utils/patch.d.ts +1 -1
  188. package/dist/utils/patch.d.ts.map +1 -1
  189. package/dist/utils/pro2Wallpaper.d.ts +0 -10
  190. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  191. package/package.json +4 -4
  192. package/src/api/BaseMethod.ts +10 -8
  193. package/src/api/CheckAllFirmwareRelease.ts +60 -59
  194. package/src/api/FirmwareUpdate.ts +15 -7
  195. package/src/api/FirmwareUpdateV2.ts +298 -126
  196. package/src/api/FirmwareUpdateV3.ts +265 -63
  197. package/src/api/FirmwareUpdateV4.ts +1017 -602
  198. package/src/api/GetPassphraseState.ts +1 -7
  199. package/src/api/OpenWalletSession.ts +17 -71
  200. package/src/api/SearchDevices.ts +1 -3
  201. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  202. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +11 -36
  203. package/src/api/device/DeviceSettings.ts +4 -5
  204. package/src/api/device/DeviceUnlock.ts +3 -8
  205. package/src/api/device/DeviceUpdateBootloader.ts +125 -6
  206. package/src/api/firmware/FirmwareArtifactSource.ts +278 -0
  207. package/src/api/firmware/FirmwareHostBinding.ts +100 -0
  208. package/src/api/firmware/FirmwarePreparationError.ts +12 -0
  209. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +83 -27
  210. package/src/api/firmware/FirmwareUpdateCapabilities.ts +9 -0
  211. package/src/api/firmware/FirmwareUpdatePlan.ts +772 -0
  212. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +449 -0
  213. package/src/api/firmware/progressThrottle.ts +44 -0
  214. package/src/api/firmware/updateBootloader.ts +19 -4
  215. package/src/api/firmware/uploadFirmware.ts +144 -39
  216. package/src/api/helpers/protocolV2FileWrite.ts +63 -202
  217. package/src/api/index.ts +0 -2
  218. package/src/api/kaspa/KaspaGetAddress.ts +1 -1
  219. package/src/api/kaspa/KaspaSignTransaction.ts +13 -2
  220. package/src/api/polkadot/networks.ts +3 -3
  221. package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -3
  222. package/src/api/protocol-v2/helpers.ts +1 -1
  223. package/src/api/solana/SolSignMessage.ts +1 -1
  224. package/src/api/solana/SolSignOffchainMessage.ts +1 -1
  225. package/src/api/solana/SolSignTransaction.ts +2 -2
  226. package/src/api/sui/SuiGetAddress.ts +1 -1
  227. package/src/api/sui/SuiGetPublicKey.ts +1 -1
  228. package/src/api/sui/SuiSignMessage.ts +1 -1
  229. package/src/api/sui/SuiSignTransaction.ts +1 -1
  230. package/src/api/ton/TonGetAddress.ts +1 -1
  231. package/src/api/ton/TonSignMessage.ts +1 -1
  232. package/src/api/ton/TonSignProof.ts +1 -1
  233. package/src/api/tron/TronSignMessage.ts +2 -2
  234. package/src/api/tron/TronSignTransaction.ts +1 -1
  235. package/src/core/deviceEventRegistration.ts +0 -4
  236. package/src/core/index.ts +111 -213
  237. package/src/data/messages/messages-protocol-v2.json +0 -25
  238. package/src/data-manager/DataManager.ts +41 -113
  239. package/src/data-manager/TransportManager.ts +0 -6
  240. package/src/data-manager/connectSettings.ts +11 -0
  241. package/src/device/Device.ts +49 -274
  242. package/src/device/DeviceCommands.ts +4 -31
  243. package/src/device/DeviceConnector.ts +13 -33
  244. package/src/device/DevicePool.ts +7 -21
  245. package/src/deviceProfile/buildDeviceFeatures.ts +2 -2
  246. package/src/deviceProfile/protocolV2DeviceIdentity.ts +0 -3
  247. package/src/events/device.ts +0 -4
  248. package/src/events/logBlockEvent.ts +0 -1
  249. package/src/events/ui-promise.ts +2 -4
  250. package/src/events/ui-request.ts +2 -36
  251. package/src/events/ui-response.ts +2 -12
  252. package/src/index.ts +5 -0
  253. package/src/inject.ts +24 -60
  254. package/src/lowLevelInject.ts +8 -7
  255. package/src/protocols/protocol-v2/features.ts +7 -10
  256. package/src/protocols/protocol-v2/firmware.ts +0 -2
  257. package/src/protocols/protocol-v2/lockedError.ts +10 -0
  258. package/src/protocols/protocol-v2/uiInteraction.ts +6 -46
  259. package/src/protocols/protocol-v2/unlockPolicy.ts +105 -1
  260. package/src/protocols/protocol-v2/unlockRetry.ts +109 -0
  261. package/src/protocols/protocol-v2/walletSession.ts +36 -214
  262. package/src/topLevelInject.ts +8 -7
  263. package/src/types/api/checkAllFirmwareRelease.ts +5 -3
  264. package/src/types/api/deviceUnlock.ts +1 -12
  265. package/src/types/api/deviceUpdateBootloader.ts +6 -0
  266. package/src/types/api/export.ts +18 -1
  267. package/src/types/api/firmwareUpdate.ts +78 -6
  268. package/src/types/api/firmwareUpdateCapabilities.ts +9 -0
  269. package/src/types/api/firmwareUpdatePlan.ts +38 -0
  270. package/src/types/api/firmwareUpdatePreparedPlan.ts +53 -0
  271. package/src/types/api/index.ts +14 -13
  272. package/src/types/api/protocolV2.ts +0 -13
  273. package/src/types/device.ts +3 -15
  274. package/src/types/params.ts +1 -7
  275. package/src/types/settings.ts +22 -60
  276. package/src/utils/deviceFeaturesCompat.ts +6 -5
  277. package/src/utils/deviceFeaturesUtils.ts +3 -14
  278. package/src/utils/deviceInfoUtils.ts +0 -2
  279. package/src/utils/deviceSettings.ts +0 -3
  280. package/src/utils/homescreen.ts +6 -32
  281. package/src/utils/index.ts +1 -6
  282. package/src/utils/pro2Wallpaper.ts +8 -35
  283. package/__tests__/core-initialization.test.ts +0 -23
  284. package/__tests__/device-connector-protocol.test.ts +0 -81
  285. package/__tests__/deviceUploadNft.test.ts +0 -316
  286. package/__tests__/pro2Nft.test.ts +0 -108
  287. package/__tests__/protocol-binding.test.ts +0 -89
  288. package/__tests__/protocol-v2-resources.test.ts +0 -340
  289. package/__tests__/protocol-v2-ui-lifecycle.test.ts +0 -91
  290. package/__tests__/uiProgressThrottle.test.ts +0 -74
  291. package/__tests__/uiPromiseRegistry.test.ts +0 -115
  292. package/dist/api/DetectDeviceConnectProtocol.d.ts +0 -7
  293. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +0 -1
  294. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +0 -31
  295. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +0 -1
  296. package/dist/core/uiPromiseRegistry.d.ts +0 -6
  297. package/dist/core/uiPromiseRegistry.d.ts.map +0 -1
  298. package/dist/protocols/protocol-v2/resources.d.ts +0 -30
  299. package/dist/protocols/protocol-v2/resources.d.ts.map +0 -1
  300. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +0 -22
  301. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +0 -1
  302. package/dist/types/api/detectDeviceConnectProtocol.d.ts +0 -4
  303. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +0 -1
  304. package/dist/utils/pro2Nft.d.ts +0 -31
  305. package/dist/utils/pro2Nft.d.ts.map +0 -1
  306. package/dist/utils/uiProgressThrottle.d.ts +0 -3
  307. package/dist/utils/uiProgressThrottle.d.ts.map +0 -1
  308. package/src/api/DetectDeviceConnectProtocol.ts +0 -18
  309. package/src/api/protocol-v2/DeviceUploadNft.ts +0 -197
  310. package/src/core/uiPromiseRegistry.ts +0 -63
  311. package/src/protocols/protocol-v2/resources.ts +0 -390
  312. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +0 -131
  313. package/src/types/api/detectDeviceConnectProtocol.ts +0 -6
  314. package/src/utils/pro2Nft.ts +0 -142
  315. package/src/utils/uiProgressThrottle.ts +0 -63
@@ -10,6 +10,7 @@ import { bytesToHex } from '../helpers/hexUtils';
10
10
  import { DataManager } from '../../data-manager';
11
11
  import { DevicePool } from '../../device/DevicePool';
12
12
  import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
13
+ import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
13
14
 
14
15
  import type { KnownDevice } from '../../types';
15
16
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -17,6 +18,7 @@ import type { PROTO } from '../../constants';
17
18
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
18
19
  import type { Success } from '@onekeyfe/hd-transport';
19
20
  import type { Device } from '../../device/Device';
21
+ import type { FirmwareByteSource } from './FirmwareArtifactSource';
20
22
 
21
23
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
22
24
  const SESSION_ERROR = 'session not found';
@@ -88,17 +90,20 @@ export const waitBleInstall = async (updateType: string) => {
88
90
  }
89
91
  };
90
92
 
91
- export const uploadFirmware = async (
93
+ const toArrayBuffer = (payload: ArrayBuffer | Buffer): ArrayBuffer => {
94
+ if (payload instanceof ArrayBuffer) {
95
+ return payload;
96
+ }
97
+ return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
98
+ };
99
+
100
+ export const uploadFirmwareFromSource = async (
92
101
  updateType: 'firmware' | 'ble',
93
102
  typedCall: TypedCall,
94
103
  postMessage: (message: CoreMessage) => void,
95
104
  device: Device,
96
- {
97
- payload,
98
- rebootOnSuccess,
99
- }: PROTO.FirmwareUpload & {
100
- rebootOnSuccess?: boolean;
101
- },
105
+ source: FirmwareByteSource,
106
+ rebootOnSuccess?: boolean,
102
107
  isUpdateBootloader?: boolean
103
108
  ) => {
104
109
  const deviceType = device.getCurrentDeviceType();
@@ -119,20 +124,20 @@ export const uploadFirmware = async (
119
124
  if (supportUpgradeFileHeader) {
120
125
  // Extract and validate firmware header (first 1KB)
121
126
  const HEADER_SIZE = 1024;
122
- if (payload.byteLength < HEADER_SIZE) {
127
+ if (source.size < HEADER_SIZE) {
123
128
  throw ERRORS.TypedError(
124
129
  HardwareErrorCode.RuntimeError,
125
- `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
130
+ `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
126
131
  );
127
132
  }
128
133
 
129
134
  Log.debug('Uploading firmware header:', {
130
135
  size: HEADER_SIZE,
131
- totalSize: payload.byteLength,
136
+ totalSize: source.size,
132
137
  });
133
138
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
134
139
 
135
- const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
140
+ const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
136
141
 
137
142
  try {
138
143
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -169,6 +174,9 @@ export const uploadFirmware = async (
169
174
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
170
175
  let updateResponse: TypedResponseMessage<'Success'>;
171
176
  try {
177
+ // Classic/Mini bootloaders accept one protobuf payload and do not expose
178
+ // a request-range protocol. Other device families remain fully streamed.
179
+ const payload = await readFirmwareByteSourceFully(source);
172
180
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
173
181
  payload,
174
182
  });
@@ -200,9 +208,7 @@ export const uploadFirmware = async (
200
208
  updateType,
201
209
  postMessage,
202
210
  device,
203
- {
204
- payload,
205
- },
211
+ source,
206
212
  rebootOnSuccess
207
213
  );
208
214
  return response.message;
@@ -211,7 +217,7 @@ export const uploadFirmware = async (
211
217
 
212
218
  postConfirmationMessage(device);
213
219
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
214
- const length = payload.byteLength;
220
+ const length = source.size;
215
221
 
216
222
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
217
223
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -220,7 +226,7 @@ export const uploadFirmware = async (
220
226
  const start = response.message.offset!;
221
227
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
222
228
  const end = response.message.offset! + response.message.length!;
223
- const chunk = payload.slice(start, end);
229
+ const chunk = await source.readAt(start, end - start);
224
230
 
225
231
  if (start > 0) {
226
232
  postProgressMessage(
@@ -249,11 +255,45 @@ export const uploadFirmware = async (
249
255
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
250
256
  };
251
257
 
258
+ export const uploadFirmware = async (
259
+ updateType: 'firmware' | 'ble',
260
+ typedCall: TypedCall,
261
+ postMessage: (message: CoreMessage) => void,
262
+ device: Device,
263
+ {
264
+ payload,
265
+ rebootOnSuccess,
266
+ }: PROTO.FirmwareUpload & {
267
+ rebootOnSuccess?: boolean;
268
+ },
269
+ isUpdateBootloader?: boolean
270
+ ) => {
271
+ const source = await openFirmwareByteSource({
272
+ binary: toArrayBuffer(payload),
273
+ });
274
+ if (!source) {
275
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
276
+ }
277
+ try {
278
+ return await uploadFirmwareFromSource(
279
+ updateType,
280
+ typedCall,
281
+ postMessage,
282
+ device,
283
+ source,
284
+ rebootOnSuccess,
285
+ isUpdateBootloader
286
+ );
287
+ } finally {
288
+ await source.close();
289
+ }
290
+ };
291
+
252
292
  const newTouchUpdateProcess = async (
253
293
  updateType: 'firmware' | 'ble',
254
294
  postMessage: (message: CoreMessage) => void,
255
295
  device: Device,
256
- { payload }: PROTO.FirmwareUpload,
296
+ source: FirmwareByteSource,
257
297
  rebootOnSuccess = true
258
298
  ) => {
259
299
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -263,13 +303,13 @@ const newTouchUpdateProcess = async (
263
303
  const env = DataManager.getSettings('env');
264
304
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
265
305
  const chunkSize = 1024 * perPackageSize;
266
- const totalChunks = Math.ceil(payload.byteLength / chunkSize);
306
+ const totalChunks = Math.ceil(source.size / chunkSize);
267
307
  let offset = 0;
268
308
  for (let i = 0; i < totalChunks; i++) {
269
309
  const chunkStart = i * chunkSize;
270
- const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
310
+ const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
271
311
  const chunkLength = chunkEnd - chunkStart;
272
- const chunk = payload.slice(chunkStart, chunkEnd);
312
+ const chunk = await source.readAt(chunkStart, chunkLength);
273
313
  const overwrite = i === 0;
274
314
  const progress = Math.round(((i + 1) / totalChunks) * 100);
275
315
  const writeRes = await emmcFileWriteWithRetry(
@@ -322,12 +362,7 @@ const newTouchUpdateProcess = async (
322
362
  try {
323
363
  if (isBleReconnect) {
324
364
  try {
325
- await device.deviceConnector?.acquire(
326
- device.originalDescriptor.id,
327
- null,
328
- true,
329
- device.originalDescriptor.protocolType
330
- );
365
+ await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
331
366
  const typedCall = device.getCommands().typedCall.bind(device.getCommands());
332
367
  await Promise.race([
333
368
  typedCall('Initialize', 'Features', {}),
@@ -346,8 +381,7 @@ const newTouchUpdateProcess = async (
346
381
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
347
382
  const { deviceList } = await DevicePool.getDevices(
348
383
  devicesDescriptor,
349
- device.originalDescriptor.id,
350
- { connectProtocol: device.originalDescriptor.protocolType }
384
+ device.originalDescriptor.id
351
385
  );
352
386
  if (deviceList.length === 1) {
353
387
  device.updateFromCache(deviceList[0]);
@@ -422,12 +456,7 @@ const emmcFileWriteWithRetry = async (
422
456
  const env = DataManager.getSettings('env');
423
457
  if (DataManager.isBleConnect(env)) {
424
458
  await wait(3000);
425
- await device.deviceConnector?.acquire(
426
- device.originalDescriptor.id,
427
- null,
428
- true,
429
- device.originalDescriptor.protocolType
430
- );
459
+ await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
431
460
  await device.initialize();
432
461
  } else if (
433
462
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -435,9 +464,7 @@ const emmcFileWriteWithRetry = async (
435
464
  ) {
436
465
  const deviceDiff = await device.deviceConnector?.enumerate();
437
466
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
438
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
439
- connectProtocol: device.originalDescriptor.protocolType,
440
- });
467
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
441
468
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
442
469
  device.updateFromCache(deviceList[0]);
443
470
  await device.acquire();
@@ -503,6 +530,67 @@ export const updateResource = async (
503
530
  return processResourceRequest(typedCall, res, data);
504
531
  };
505
532
 
533
+ export const updateResourceFromSource = async (
534
+ typedCall: TypedCall,
535
+ fileName: string,
536
+ source: FirmwareByteSource,
537
+ onConfirmAfter?: () => void
538
+ ) => {
539
+ const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
540
+ const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
541
+ let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
542
+ file_name: fileName,
543
+ data_length: source.size,
544
+ initial_data_chunk: bytesToHex(initialChunk),
545
+ hash: bytesToHex(blake2s(initialChunk)),
546
+ });
547
+ onConfirmAfter?.();
548
+
549
+ while (response.type !== 'Success') {
550
+ const { offset, data_length: dataLength } = response.message;
551
+ if (
552
+ !Number.isSafeInteger(offset) ||
553
+ offset === undefined ||
554
+ offset < 0 ||
555
+ !Number.isSafeInteger(dataLength) ||
556
+ dataLength === undefined ||
557
+ dataLength <= 0 ||
558
+ offset + dataLength > source.size
559
+ ) {
560
+ throw ERRORS.TypedError(
561
+ HardwareErrorCode.RuntimeError,
562
+ 'Device requested an invalid firmware resource range'
563
+ );
564
+ }
565
+ const chunk = new Uint8Array(await source.readAt(offset, dataLength));
566
+ response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
567
+ data_chunk: bytesToHex(chunk),
568
+ hash: bytesToHex(blake2s(chunk)),
569
+ });
570
+ }
571
+ return response.message;
572
+ };
573
+
574
+ export const updateResourcesFromSources = async (
575
+ typedCall: TypedCall,
576
+ postMessage: (message: CoreMessage) => void,
577
+ device: Device,
578
+ entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
579
+ ) => {
580
+ postProgressTip(device, 'UpdateSysResource', postMessage);
581
+ for (const [index, entry] of entries.entries()) {
582
+ await updateResourceFromSource(typedCall, entry.entryName, entry.source);
583
+ postProgressMessage(
584
+ device,
585
+ Math.floor(((index + 1) / entries.length) * 100),
586
+ 'installingFirmware',
587
+ postMessage
588
+ );
589
+ }
590
+ postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
591
+ return true;
592
+ };
593
+
506
594
  export const updateResources = async (
507
595
  typedCall: TypedCall,
508
596
  postMessage: (message: CoreMessage) => void,
@@ -537,11 +625,28 @@ export const updateBootloader = async (
537
625
  typedCall: TypedCall,
538
626
  postMessage: (message: CoreMessage) => void,
539
627
  device: Device,
540
- source: ArrayBuffer
628
+ data: ArrayBuffer
629
+ ) => {
630
+ const source = await openFirmwareByteSource({ binary: data });
631
+ if (!source) {
632
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
633
+ }
634
+ try {
635
+ return await updateBootloaderFromSource(typedCall, postMessage, device, source);
636
+ } finally {
637
+ await source.close();
638
+ }
639
+ };
640
+
641
+ export const updateBootloaderFromSource = async (
642
+ typedCall: TypedCall,
643
+ postMessage: (message: CoreMessage) => void,
644
+ device: Device,
645
+ source: FirmwareByteSource
541
646
  ) => {
542
647
  postProgressTip(device, 'UpdateBootloader', postMessage);
543
648
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
544
- await updateResource(typedCall, 'bootloader.bin', source, () => {
649
+ await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
545
650
  postProcessingMessage('resource', postMessage);
546
651
  });
547
652
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
@@ -5,12 +5,9 @@ import {
5
5
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
6
6
 
7
7
  import { DataManager } from '../../data-manager';
8
- import { LoggerNames, getLogger } from '../../utils/logger';
9
8
 
10
9
  import type { DeviceCommands } from '../../device/DeviceCommands';
11
10
 
12
- const Log = getLogger(LoggerNames.Method);
13
-
14
11
  export type ProtocolV2FileWriteData = ArrayBuffer | Uint8Array | Blob | string;
15
12
 
16
13
  export type ProtocolV2FileWriteProgress = {
@@ -21,12 +18,6 @@ export type ProtocolV2FileWriteProgress = {
21
18
  elapsedMs: number;
22
19
  };
23
20
 
24
- export type ProtocolV2FileWriteChunkContext = {
25
- offset: number;
26
- chunkLength: number;
27
- totalSize: number;
28
- };
29
-
30
21
  export type ProtocolV2FileWriteOptions = {
31
22
  commands: Pick<DeviceCommands, 'typedCall'>;
32
23
  path: string;
@@ -39,63 +30,20 @@ export type ProtocolV2FileWriteOptions = {
39
30
  append?: boolean;
40
31
  uiPercentage?: number;
41
32
  timeoutMs?: number;
42
- writeWithResponse?: boolean;
43
33
  maxChunkRetries?: number;
44
- paceMs?: number;
45
34
  throwIfAborted?: () => void;
46
- getUiPercentage?: (context: ProtocolV2FileWriteChunkContext) => number | undefined;
47
35
  onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
48
36
  };
49
37
 
50
38
  const MIN_FILE_CHUNK_SIZE = 64;
51
- const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
52
- const FILE_TRANSFER_LOG_INTERVAL_MS = 10_000;
53
- const SESSION_ERROR = 'session not found';
54
-
55
- function formatFileTransferRate(bytesPerSecond: number) {
56
- return (Math.max(bytesPerSecond, 0) / 1024).toFixed(2);
57
- }
58
-
59
- function getAverageFileTransferRate(transferredBytes: number, elapsedMs: number) {
60
- if (elapsedMs <= 0) return 0;
61
- return Math.round((Math.max(transferredBytes, 0) / elapsedMs) * 1000);
62
- }
63
39
 
64
- function getFileTransferTransport() {
65
- const env = DataManager.getSettings('env');
66
- return env && DataManager.isBleConnect(env) ? 'BLE' : String(env ?? 'unknown');
67
- }
68
-
69
- function logFileTransferMetrics({
70
- transport,
71
- status,
72
- transferredBytes,
73
- totalBytes,
74
- elapsedMs,
75
- rateBytesPerSecond,
76
- }: {
77
- transport: string;
78
- status: 'progress' | 'completed' | 'failed';
79
- transferredBytes: number;
80
- totalBytes: number;
81
- elapsedMs: number;
82
- rateBytesPerSecond: number;
83
- }) {
84
- Log.log(
85
- `[FileWrite] metrics transport=${transport} status=${status} bytes=${transferredBytes}/${totalBytes} elapsed=${(
86
- elapsedMs / 1000
87
- ).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s`
88
- );
89
- }
90
-
91
- export function isProtocolV2ResponseTimeout(error: unknown) {
40
+ function isRetryableFileWriteTimeout(error: unknown) {
92
41
  if (!error || typeof error !== 'object') return false;
93
- const candidate = error as { errorCode?: number; code?: number | string; message?: string };
42
+ const candidate = error as { errorCode?: number; code?: number; message?: string };
94
43
  const code = candidate.errorCode ?? candidate.code;
95
44
  return (
96
45
  code === HardwareErrorCode.BleTimeoutError ||
97
- code === 'response-timeout' ||
98
- /(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
46
+ /Lowlevel response timeout/i.test(candidate.message ?? '')
99
47
  );
100
48
  }
101
49
 
@@ -171,162 +119,75 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
171
119
  let chunks = 0;
172
120
  let lastMessage: Record<string, unknown> | undefined;
173
121
  const startTime = Date.now();
174
- let rateWindowStartedAt = startTime;
175
- let rateWindowStartedBytes = 0;
176
- let rateBytesPerSecond: number | undefined;
177
- let lastConfirmedAt = startTime;
178
- let logWindowStartedAt = startTime;
179
- let logWindowStartedBytes = 0;
180
- const transport = getFileTransferTransport();
181
122
 
182
- try {
183
- while (written < dataLength) {
184
- options.throwIfAborted?.();
185
- const chunk = data.slice(written, Math.min(written + chunkSize, dataLength));
186
- const offset = startOffset + written;
187
- const progress =
188
- options.uiPercentage ??
189
- options.getUiPercentage?.({
190
- offset,
191
- chunkLength: chunk.byteLength,
192
- totalSize,
193
- }) ??
194
- getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
195
- const request = {
196
- file: { path: options.path, offset, total_size: totalSize, data: chunk },
197
- overwrite: chunks === 0 ? options.overwrite ?? false : false,
198
- append: options.append ?? false,
199
- ui_percentage: progress,
200
- };
201
- const maxChunkRetries = Math.max(Math.floor(options.maxChunkRetries ?? 0), 0);
202
- let retryCount = 0;
203
- let response;
204
- let isWritePending = true;
205
- while (isWritePending) {
206
- try {
207
- const callOptions =
208
- options.writeWithResponse === undefined
209
- ? { timeoutMs: options.timeoutMs }
210
- : {
211
- ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
212
- writeWithResponse: options.writeWithResponse,
213
- };
214
- response = await options.commands.typedCall(
215
- 'FilesystemFileWrite',
216
- 'FilesystemFile',
217
- request,
218
- callOptions
219
- );
220
- isWritePending = false;
221
- } catch (error) {
222
- if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
223
- retryCount += 1;
224
- options.throwIfAborted?.();
225
- }
226
- }
227
- if (!response) {
228
- throw ERRORS.TypedError(
229
- HardwareErrorCode.RuntimeError,
230
- 'FilesystemFileWrite completed without a response'
231
- );
232
- }
233
- const responseType = (response as { type?: string }).type;
234
- if (responseType && responseType !== 'FilesystemFile') {
235
- const responseError = (response as { message?: { error?: unknown } }).message?.error;
236
- if (typeof responseError === 'string' && responseError.includes(SESSION_ERROR)) {
237
- throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, SESSION_ERROR);
238
- }
239
- throw ERRORS.TypedError(
240
- HardwareErrorCode.RuntimeError,
241
- `FilesystemFileWrite received unexpected response ${responseType}`
242
- );
243
- }
244
- options.throwIfAborted?.();
245
- lastMessage = response.message;
246
- const rawProcessedByte = response.message?.processed_byte;
247
- const processedByte = Number(rawProcessedByte);
248
- if (
249
- rawProcessedByte !== undefined &&
250
- (!Number.isFinite(processedByte) ||
251
- processedByte <= offset ||
252
- processedByte > offset + chunk.byteLength)
253
- ) {
254
- throw ERRORS.TypedError(
255
- HardwareErrorCode.RuntimeError,
256
- `FilesystemFileWrite invalid processed_byte ${processedByte}`
123
+ while (written < dataLength) {
124
+ options.throwIfAborted?.();
125
+ const chunk = data.slice(written, Math.min(written + chunkSize, dataLength));
126
+ const offset = startOffset + written;
127
+ const progress =
128
+ options.uiPercentage ??
129
+ getDeviceTransferProgress(offset, offset + chunk.byteLength, totalSize);
130
+ const request = {
131
+ file: { path: options.path, offset, total_size: totalSize, data: chunk },
132
+ overwrite: chunks === 0 ? options.overwrite ?? false : false,
133
+ append: options.append ?? false,
134
+ ui_percentage: progress,
135
+ };
136
+ const maxChunkRetries = Math.max(Math.floor(options.maxChunkRetries ?? 0), 0);
137
+ let retryCount = 0;
138
+ let response;
139
+ let isWritePending = true;
140
+ while (isWritePending) {
141
+ try {
142
+ response = await options.commands.typedCall(
143
+ 'FilesystemFileWrite',
144
+ 'FilesystemFile',
145
+ request,
146
+ { timeoutMs: options.timeoutMs }
257
147
  );
258
- }
259
- written =
260
- rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
261
- chunks += 1;
262
- const now = Date.now();
263
- lastConfirmedAt = now;
264
- const elapsedMs = now - startTime;
265
- const transferredBytes = Math.min(written, dataLength);
266
- const rateWindowElapsedMs = now - rateWindowStartedAt;
267
- if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
268
- const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
269
- rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
270
- rateWindowStartedAt = now;
271
- rateWindowStartedBytes = transferredBytes;
272
- } else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
273
- rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
274
- }
275
- options.onProgress?.({
276
- progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
277
- transferredBytes,
278
- totalBytes: dataLength,
279
- rateBytesPerSecond,
280
- elapsedMs,
281
- });
282
- const logWindowElapsedMs = now - logWindowStartedAt;
283
- if (logWindowElapsedMs >= FILE_TRANSFER_LOG_INTERVAL_MS && transferredBytes < dataLength) {
284
- const logWindowBytes = Math.max(transferredBytes - logWindowStartedBytes, 0);
285
- logFileTransferMetrics({
286
- transport,
287
- status: 'progress',
288
- transferredBytes,
289
- totalBytes: dataLength,
290
- elapsedMs,
291
- rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
292
- });
293
- logWindowStartedAt = now;
294
- logWindowStartedBytes = transferredBytes;
295
- }
296
- if (options.paceMs && options.paceMs > 0) {
297
- await new Promise(resolve => {
298
- setTimeout(resolve, options.paceMs);
299
- });
148
+ isWritePending = false;
149
+ } catch (error) {
150
+ if (retryCount >= maxChunkRetries || !isRetryableFileWriteTimeout(error)) throw error;
151
+ retryCount += 1;
152
+ options.throwIfAborted?.();
300
153
  }
301
154
  }
302
- } catch (error) {
303
- const now = Date.now();
304
- const elapsedMs = Math.max(now - startTime, 0);
305
- const logWindowElapsedMs = Math.max(now - logWindowStartedAt, 0);
306
- const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
307
- logFileTransferMetrics({
308
- transport,
309
- status: 'failed',
310
- transferredBytes: written,
155
+ if (!response) {
156
+ throw ERRORS.TypedError(
157
+ HardwareErrorCode.RuntimeError,
158
+ 'FilesystemFileWrite completed without a response'
159
+ );
160
+ }
161
+ options.throwIfAborted?.();
162
+ lastMessage = response.message;
163
+ const rawProcessedByte = response.message?.processed_byte;
164
+ const processedByte = Number(rawProcessedByte);
165
+ if (
166
+ rawProcessedByte !== undefined &&
167
+ (!Number.isFinite(processedByte) ||
168
+ processedByte <= offset ||
169
+ processedByte > offset + chunk.byteLength)
170
+ ) {
171
+ throw ERRORS.TypedError(
172
+ HardwareErrorCode.RuntimeError,
173
+ `FilesystemFileWrite invalid processed_byte ${processedByte}`
174
+ );
175
+ }
176
+ written =
177
+ rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
178
+ chunks += 1;
179
+ const elapsedMs = Date.now() - startTime;
180
+ const transferredBytes = Math.min(written, dataLength);
181
+ options.onProgress?.({
182
+ progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
183
+ transferredBytes,
311
184
  totalBytes: dataLength,
185
+ rateBytesPerSecond:
186
+ elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
312
187
  elapsedMs,
313
- rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
314
188
  });
315
- throw error;
316
189
  }
317
190
 
318
- const elapsedMs = Math.max(lastConfirmedAt - startTime, 0);
319
- const logWindowElapsedMs = Math.max(lastConfirmedAt - logWindowStartedAt, 0);
320
- const logWindowBytes = Math.max(written - logWindowStartedBytes, 0);
321
- logFileTransferMetrics({
322
- transport,
323
- status: 'completed',
324
- transferredBytes: written,
325
- totalBytes: dataLength,
326
- elapsedMs,
327
- rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
328
- });
329
-
330
191
  return {
331
192
  ...lastMessage,
332
193
  path: options.path,
package/src/api/index.ts CHANGED
@@ -3,7 +3,6 @@ export { default as testProtocolV2Ping } from './protocol-v2/Ping';
3
3
  export { default as preInitialize } from './device/PreInitialize';
4
4
 
5
5
  export { default as searchDevices } from './SearchDevices';
6
- export { default as detectDeviceConnectProtocol } from './DetectDeviceConnectProtocol';
7
6
  export { default as getFeatures } from './GetFeatures';
8
7
  export { default as getDeviceState } from './GetDeviceState';
9
8
  export { default as getOnekeyFeatures } from './GetOnekeyFeatures';
@@ -50,7 +49,6 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
50
49
  export { default as deviceReboot } from './protocol-v2/DeviceReboot';
51
50
  export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
52
51
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
53
- export { default as deviceUploadNft } from './protocol-v2/DeviceUploadNft';
54
52
  export { default as uploadPortfolio } from './UploadPortfolio';
55
53
 
56
54
  export { default as cipherKeyValue } from './CipherKeyValue';
@@ -67,7 +67,7 @@ export default class KaspaGetAddress extends BaseMethod<HardwareKaspaGetAddress[
67
67
  model_classic1s: {
68
68
  min: '3.12.0',
69
69
  },
70
- model_pro2: {
70
+ pro2: {
71
71
  min: '0.0.0',
72
72
  },
73
73
  };
@@ -190,7 +190,7 @@ export default class KaspaSignTransaction extends BaseMethod<KaspaSignTransactio
190
190
  model_classic1s: {
191
191
  min: '3.12.0',
192
192
  },
193
- model_pro2: {
193
+ pro2: {
194
194
  min: '0.0.0',
195
195
  },
196
196
  };
@@ -506,7 +506,18 @@ export default class KaspaSignTransaction extends BaseMethod<KaspaSignTransactio
506
506
  'KaspaSignTransaction: device firmware uses the streaming protocol; every output requires address or addressN'
507
507
  );
508
508
  }
509
- return this.signTxStream(typedCall, response);
509
+ try {
510
+ return await this.signTxStream(typedCall, response);
511
+ } catch (error) {
512
+ // Device rejected our refTxs; the caller decides whether to sign without them.
513
+ if (
514
+ error instanceof HardwareError &&
515
+ String(error.message).toLowerCase().includes('previous transaction id mismatch')
516
+ ) {
517
+ throw ERRORS.TypedError(HardwareErrorCode.KaspaPrevTxIdMismatch, String(error.message));
518
+ }
519
+ throw error;
520
+ }
510
521
  }
511
522
 
512
523
  // Legacy answer to a streaming-only packet: no prehash material exists.