@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
@@ -0,0 +1,278 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import type {
4
+ FirmwareArtifactReader,
5
+ FirmwareArtifactReference,
6
+ } from '../../types/api/firmwareUpdate';
7
+
8
+ export const MAX_FIRMWARE_ARTIFACT_READ_BYTES = 256 * 1024;
9
+
10
+ export interface FirmwareByteSource {
11
+ readonly size: number;
12
+ readAt(offset: number, length: number): Promise<ArrayBuffer>;
13
+ close(): Promise<void>;
14
+ }
15
+
16
+ const artifactError = (
17
+ code:
18
+ | 'FirmwareArtifactReceiptMismatch'
19
+ | 'FirmwareArtifactReaderInvalid'
20
+ | 'FirmwareArtifactReadOutOfBounds'
21
+ | 'FirmwareArtifactReadTooLarge',
22
+ message: string
23
+ ): never => {
24
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, message, {
25
+ firmwareUpdateCode: code,
26
+ });
27
+ };
28
+
29
+ const assertSafeSize = (value: number, name: string) => {
30
+ if (!Number.isSafeInteger(value) || value <= 0) {
31
+ artifactError('FirmwareArtifactReceiptMismatch', `${name} must be a positive safe integer`);
32
+ }
33
+ };
34
+
35
+ export const assertFirmwareArtifactReference = (
36
+ artifact: FirmwareArtifactReference
37
+ ): FirmwareArtifactReference => {
38
+ if (
39
+ !artifact ||
40
+ typeof artifact.artifactRef !== 'string' ||
41
+ artifact.artifactRef.length === 0 ||
42
+ artifact.artifactRef.length > 160 ||
43
+ artifact.artifactRef.includes('/') ||
44
+ artifact.artifactRef.includes('\\')
45
+ ) {
46
+ artifactError(
47
+ 'FirmwareArtifactReceiptMismatch',
48
+ 'Firmware artifactRef must be an opaque identifier'
49
+ );
50
+ }
51
+ assertSafeSize(artifact.size, 'Firmware artifact size');
52
+ if (typeof artifact.sha256 !== 'string' || !/^[a-f0-9]{64}$/i.test(artifact.sha256)) {
53
+ artifactError(
54
+ 'FirmwareArtifactReceiptMismatch',
55
+ 'Firmware artifact sha256 must be a 32-byte hexadecimal digest'
56
+ );
57
+ }
58
+ return artifact;
59
+ };
60
+
61
+ const assertFirmwareArtifactRead = (size: number, offset: number, length: number) => {
62
+ if (
63
+ !Number.isSafeInteger(offset) ||
64
+ offset < 0 ||
65
+ offset >= size ||
66
+ !Number.isSafeInteger(length) ||
67
+ length <= 0 ||
68
+ offset + length > size
69
+ ) {
70
+ artifactError(
71
+ 'FirmwareArtifactReadOutOfBounds',
72
+ `Firmware artifact read is outside size ${size}: offset=${offset}, length=${length}`
73
+ );
74
+ }
75
+ if (length > MAX_FIRMWARE_ARTIFACT_READ_BYTES) {
76
+ artifactError(
77
+ 'FirmwareArtifactReadTooLarge',
78
+ `Firmware artifact read length ${length} exceeds ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
79
+ );
80
+ }
81
+ };
82
+
83
+ const createMemoryFirmwareByteSource = (binary: ArrayBuffer): FirmwareByteSource => {
84
+ let bytes: Uint8Array | null = new Uint8Array(binary);
85
+ const { byteLength: size } = binary;
86
+ assertSafeSize(size, 'Firmware binary size');
87
+ return {
88
+ size,
89
+ readAt: (offset, length) => {
90
+ if (!bytes) {
91
+ return Promise.reject(
92
+ ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Firmware byte source is closed', {
93
+ firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
94
+ })
95
+ );
96
+ }
97
+ assertFirmwareArtifactRead(size, offset, length);
98
+ return Promise.resolve(bytes.slice(offset, offset + length).buffer);
99
+ },
100
+ close: () => {
101
+ bytes = null;
102
+ return Promise.resolve();
103
+ },
104
+ };
105
+ };
106
+
107
+ class ReaderFirmwareByteSource implements FirmwareByteSource {
108
+ readonly size: number;
109
+
110
+ private closed = false;
111
+
112
+ private reading = false;
113
+
114
+ private constructor(
115
+ private readonly reader: FirmwareArtifactReader,
116
+ private readonly readerId: string,
117
+ size: number
118
+ ) {
119
+ this.size = size;
120
+ }
121
+
122
+ static async open(
123
+ artifact: FirmwareArtifactReference,
124
+ reader: FirmwareArtifactReader
125
+ ): Promise<ReaderFirmwareByteSource> {
126
+ const opened = await reader.open({ artifactRef: artifact.artifactRef });
127
+ if (
128
+ !opened ||
129
+ typeof opened.readerId !== 'string' ||
130
+ opened.readerId.length === 0 ||
131
+ !Number.isSafeInteger(opened.size) ||
132
+ opened.size !== artifact.size
133
+ ) {
134
+ if (opened?.readerId) {
135
+ await reader.close({ readerId: opened.readerId }).catch(() => undefined);
136
+ }
137
+ return artifactError(
138
+ 'FirmwareArtifactReceiptMismatch',
139
+ `Firmware artifact opened with size ${opened?.size ?? 'unknown'}, expected ${artifact.size}`
140
+ );
141
+ }
142
+ return new ReaderFirmwareByteSource(reader, opened.readerId, opened.size);
143
+ }
144
+
145
+ async readAt(offset: number, length: number): Promise<ArrayBuffer> {
146
+ if (this.closed) {
147
+ return artifactError('FirmwareArtifactReaderInvalid', 'Firmware artifact reader is closed');
148
+ }
149
+ if (this.reading) {
150
+ return artifactError(
151
+ 'FirmwareArtifactReaderInvalid',
152
+ 'Firmware artifact reader only permits one in-flight read'
153
+ );
154
+ }
155
+ assertFirmwareArtifactRead(this.size, offset, length);
156
+ this.reading = true;
157
+ try {
158
+ const result = await this.reader.read({
159
+ readerId: this.readerId,
160
+ offset,
161
+ length,
162
+ });
163
+ const expectedEof = offset + length === this.size;
164
+ if (
165
+ !result ||
166
+ !(result.data instanceof ArrayBuffer) ||
167
+ result.data.byteLength !== length ||
168
+ result.bytesRead !== length ||
169
+ result.eof !== expectedEof
170
+ ) {
171
+ return artifactError(
172
+ 'FirmwareArtifactReaderInvalid',
173
+ 'Firmware artifact reader returned an invalid read result'
174
+ );
175
+ }
176
+ return result.data;
177
+ } finally {
178
+ this.reading = false;
179
+ }
180
+ }
181
+
182
+ async close(): Promise<void> {
183
+ if (this.closed) {
184
+ return;
185
+ }
186
+ this.closed = true;
187
+ await this.reader.close({ readerId: this.readerId });
188
+ }
189
+ }
190
+
191
+ export const openFirmwareByteSource = async ({
192
+ binary,
193
+ artifact,
194
+ reader,
195
+ }: {
196
+ binary?: ArrayBuffer;
197
+ artifact?: FirmwareArtifactReference;
198
+ reader?: FirmwareArtifactReader;
199
+ }): Promise<FirmwareByteSource | null> => {
200
+ if (binary && artifact) {
201
+ return artifactError(
202
+ 'FirmwareArtifactReceiptMismatch',
203
+ 'Firmware input must not contain both binary and artifactRef'
204
+ );
205
+ }
206
+ if (binary) {
207
+ return createMemoryFirmwareByteSource(binary);
208
+ }
209
+ if (!artifact) {
210
+ return null;
211
+ }
212
+ assertFirmwareArtifactReference(artifact);
213
+ if (!reader) {
214
+ return artifactError(
215
+ 'FirmwareArtifactReaderInvalid',
216
+ 'Firmware artifact reader is required for artifactRef input'
217
+ );
218
+ }
219
+ return ReaderFirmwareByteSource.open(artifact, reader);
220
+ };
221
+
222
+ export const readFirmwareByteSourceFully = async (
223
+ source: FirmwareByteSource
224
+ ): Promise<ArrayBuffer> => {
225
+ const output = new Uint8Array(source.size);
226
+ let offset = 0;
227
+ while (offset < source.size) {
228
+ const length = Math.min(MAX_FIRMWARE_ARTIFACT_READ_BYTES, source.size - offset);
229
+ output.set(new Uint8Array(await source.readAt(offset, length)), offset);
230
+ offset += length;
231
+ }
232
+ return output.buffer;
233
+ };
234
+
235
+ export const writeFirmwareByteSource = async ({
236
+ source,
237
+ chunkSize,
238
+ write,
239
+ }: {
240
+ source: FirmwareByteSource;
241
+ chunkSize: number;
242
+ write: (input: {
243
+ data: ArrayBuffer;
244
+ sourceOffset: number;
245
+ length: number;
246
+ first: boolean;
247
+ }) => Promise<number>;
248
+ }) => {
249
+ if (
250
+ !Number.isSafeInteger(chunkSize) ||
251
+ chunkSize <= 0 ||
252
+ chunkSize > MAX_FIRMWARE_ARTIFACT_READ_BYTES
253
+ ) {
254
+ return artifactError(
255
+ 'FirmwareArtifactReadTooLarge',
256
+ `Firmware artifact chunk size must be between 1 and ${MAX_FIRMWARE_ARTIFACT_READ_BYTES}`
257
+ );
258
+ }
259
+ let offset = 0;
260
+ while (offset < source.size) {
261
+ const length = Math.min(chunkSize, source.size - offset);
262
+ const data = await source.readAt(offset, length);
263
+ const processed = await write({
264
+ data,
265
+ sourceOffset: offset,
266
+ length,
267
+ first: offset === 0,
268
+ });
269
+ if (processed !== length) {
270
+ return artifactError(
271
+ 'FirmwareArtifactReaderInvalid',
272
+ `Firmware artifact writer processed ${processed} bytes, expected ${length}`
273
+ );
274
+ }
275
+ offset += length;
276
+ }
277
+ return offset;
278
+ };
@@ -0,0 +1,100 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ import type { FirmwareUpdateHostBinding } from '../../types/api/firmwareUpdate';
4
+
5
+ const bindingError = (message: string): never => {
6
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, message, {
7
+ firmwareUpdateCode: 'FirmwareArtifactReaderInvalid',
8
+ });
9
+ };
10
+
11
+ class FirmwareHostBindingRegistry {
12
+ private generation = 0;
13
+
14
+ private binding?: FirmwareUpdateHostBinding;
15
+
16
+ register(binding: FirmwareUpdateHostBinding): number {
17
+ if (
18
+ !binding ||
19
+ typeof binding.artifactReader?.open !== 'function' ||
20
+ typeof binding.artifactReader.read !== 'function' ||
21
+ typeof binding.artifactReader.close !== 'function'
22
+ ) {
23
+ return bindingError('Firmware host binding is invalid');
24
+ }
25
+ this.generation += 1;
26
+ this.binding = binding;
27
+ return this.generation;
28
+ }
29
+
30
+ unregister(generation?: number): boolean {
31
+ if (generation !== undefined && generation !== this.generation) {
32
+ return false;
33
+ }
34
+ this.generation += 1;
35
+ this.binding = undefined;
36
+ return true;
37
+ }
38
+
39
+ getGeneration(): number {
40
+ return this.generation;
41
+ }
42
+
43
+ resolve(generation: number): FirmwareUpdateHostBinding {
44
+ if (
45
+ !Number.isSafeInteger(generation) ||
46
+ generation <= 0 ||
47
+ generation !== this.generation ||
48
+ !this.binding
49
+ ) {
50
+ return bindingError(`Firmware host binding generation ${generation} is stale`);
51
+ }
52
+ const { binding } = this;
53
+ const assertCurrent = () => {
54
+ if (generation !== this.generation || binding !== this.binding) {
55
+ bindingError(`Firmware host binding generation ${generation} is stale`);
56
+ }
57
+ };
58
+ return {
59
+ artifactReader: {
60
+ open: async input => {
61
+ assertCurrent();
62
+ const opened = await binding.artifactReader.open(input);
63
+ try {
64
+ assertCurrent();
65
+ } catch (error) {
66
+ if (opened?.readerId) {
67
+ await binding.artifactReader
68
+ .close({ readerId: opened.readerId })
69
+ .catch(() => undefined);
70
+ }
71
+ throw error;
72
+ }
73
+ return opened;
74
+ },
75
+ read: async input => {
76
+ assertCurrent();
77
+ const result = await binding.artifactReader.read(input);
78
+ assertCurrent();
79
+ return result;
80
+ },
81
+ close: input => binding.artifactReader.close(input),
82
+ },
83
+ };
84
+ }
85
+ }
86
+
87
+ const firmwareHostBindingRegistry = new FirmwareHostBindingRegistry();
88
+
89
+ export const registerFirmwareUpdateHostBinding = (binding: FirmwareUpdateHostBinding): number =>
90
+ firmwareHostBindingRegistry.register(binding);
91
+
92
+ export const unregisterFirmwareUpdateHostBinding = (generation?: number): boolean =>
93
+ firmwareHostBindingRegistry.unregister(generation);
94
+
95
+ export const getFirmwareUpdateHostBindingGeneration = (): number =>
96
+ firmwareHostBindingRegistry.getGeneration();
97
+
98
+ export const resolveFirmwareUpdateHostBinding = (
99
+ generation: number | undefined
100
+ ): FirmwareUpdateHostBinding => firmwareHostBindingRegistry.resolve(generation ?? Number.NaN);
@@ -0,0 +1,12 @@
1
+ import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+
3
+ export const normalizeFirmwarePreparationError = (error: unknown) => {
4
+ if (error instanceof HardwareError && error.params?.firmwareUpdateCode) {
5
+ return error;
6
+ }
7
+
8
+ return ERRORS.TypedError(
9
+ HardwareErrorCode.FirmwareUpdateDownloadFailed,
10
+ error instanceof Error ? error.message : String(error)
11
+ );
12
+ };
@@ -13,9 +13,10 @@ import { DeviceModelToTypes } from '../../types';
13
13
  import { DataManager } from '../../data-manager';
14
14
  import { BaseMethod } from '../BaseMethod';
15
15
  import { DEVICE } from '../../events';
16
+ import { createFirmwareProgressThrottle } from './progressThrottle';
17
+ import { writeFirmwareByteSource } from './FirmwareArtifactSource';
16
18
 
17
19
  import type {
18
- FirmwareProgress,
19
20
  IFirmwareUpdateProgressType,
20
21
  IFirmwareUpdateTipMessage,
21
22
  } from '../../events/ui-request';
@@ -24,15 +25,21 @@ import type { RebootType } from '@onekeyfe/hd-transport';
24
25
  import type { Deferred } from '@onekeyfe/hd-shared';
25
26
  import type { KnownDevice } from '../../types';
26
27
  import type { TypedResponseMessage } from '../../device/DeviceCommands';
28
+ import type { FirmwareByteSource } from './FirmwareArtifactSource';
27
29
 
28
30
  const Log = getLogger(LoggerNames.Method);
29
31
  const SESSION_ERROR = 'session not found';
30
32
  const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
31
33
 
32
- type FirmwareTransferMetrics = Pick<
33
- FirmwareProgress['payload'],
34
- 'transferredBytes' | 'totalBytes' | 'rateBytesPerSecond' | 'elapsedMs'
35
- >;
34
+ /**
35
+ * Response timeout for each Initialize probe while polling a rebooting device over BLE.
36
+ * Overlap safety comes from the poll's in-flight guard, not from this value. Keep it
37
+ * well below the 30s reboot budget so several attempts fit: a probe written into the
38
+ * dying pre-reboot connection is never answered, and its timeout tears that stale link
39
+ * down so the next tick reconnects fresh. Raise it only if a device model is proven to
40
+ * answer bootloader Initialize slower than this on a fresh connection.
41
+ */
42
+ export const BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS = 5000;
36
43
 
37
44
  const isDeviceDisconnectedError = (error: unknown) => {
38
45
  const message = error instanceof Error ? error.message : String(error ?? '');
@@ -46,6 +53,8 @@ const isDeviceDisconnectedError = (error: unknown) => {
46
53
  export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
47
54
  checkPromise: Deferred<any> | null = null;
48
55
 
56
+ private shouldPostFirmwareProgress = createFirmwareProgressThrottle();
57
+
49
58
  init(): void {}
50
59
 
51
60
  run(): Promise<any> {
@@ -88,17 +97,16 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
88
97
  * @description Post the progress message
89
98
  * @param progress Post the percentage of the progress
90
99
  */
91
- postProgressMessage = (
92
- progress: number,
93
- progressType: IFirmwareUpdateProgressType,
94
- metrics?: FirmwareTransferMetrics
95
- ) => {
100
+ postProgressMessage = (progress: number, progressType: IFirmwareUpdateProgressType) => {
101
+ if (!this.shouldPostFirmwareProgress(progress, progressType)) {
102
+ return;
103
+ }
104
+
96
105
  this.postMessage(
97
106
  createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
98
107
  device: this.device.toMessageObject() as KnownDevice,
99
108
  progress,
100
109
  progressType,
101
- ...metrics,
102
110
  })
103
111
  );
104
112
  };
@@ -143,6 +151,10 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
143
151
  this.checkPromise = createDeferred();
144
152
  const env = DataManager.getSettings('env');
145
153
  const isBleReconnect = connectId && DataManager.isBleConnect(env);
154
+ // Tracks the in-flight BLE probe so interval ticks never overlap: a superseded
155
+ // Initialize left pending on the V1 transport is exactly what later times out
156
+ // and used to tear down the connection mid-firmware-upload.
157
+ let bleProbeInFlight = false;
146
158
 
147
159
  Log.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
148
160
 
@@ -198,14 +210,18 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
198
210
  }
199
211
 
200
212
  if (isBleReconnect) {
213
+ if (bleProbeInFlight) return;
214
+ bleProbeInFlight = true;
201
215
  try {
202
216
  await this.device.deviceConnector?.acquire(
203
217
  this.device.originalDescriptor.id,
204
218
  null,
205
- true,
206
- this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
219
+ true
207
220
  );
208
- await this.device.initialize();
221
+ // Bound each probe so a request the rebooting device never received
222
+ // frees the slot for the next tick instead of hanging into the
223
+ // 30s reboot budget.
224
+ await this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
209
225
  if (this.device.isBootloader()) {
210
226
  clearInterval(intervalTimer);
211
227
  this.checkPromise?.resolve(true);
@@ -213,6 +229,8 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
213
229
  } catch (e) {
214
230
  // ignore error because of device is not connected
215
231
  Log.log('catch Bluetooth error when device is restarting: ', e);
232
+ } finally {
233
+ bleProbeInFlight = false;
216
234
  }
217
235
  } else {
218
236
  await this._checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer);
@@ -237,9 +255,7 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
237
255
  ) {
238
256
  const deviceDiff = await this.device.deviceConnector?.enumerate();
239
257
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
240
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId, {
241
- connectProtocol: this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
242
- });
258
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId);
243
259
 
244
260
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
245
261
  // should update current device from cache
@@ -394,6 +410,54 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
394
410
  return totalSize !== undefined ? (processedSize ?? 0) + payload.byteLength : 0;
395
411
  }
396
412
 
413
+ async emmcCommonUpdateProcessFromSource({
414
+ source,
415
+ filePath,
416
+ processedSize,
417
+ totalSize,
418
+ }: {
419
+ source: FirmwareByteSource;
420
+ filePath: string;
421
+ processedSize?: number;
422
+ totalSize?: number;
423
+ }) {
424
+ if (!filePath.startsWith('0:')) {
425
+ throw new Error('filePath must start with 0:');
426
+ }
427
+ const env = DataManager.getSettings('env');
428
+ const chunkSize = 1024 * (DataManager.isBleConnect(env) ? 16 : 128);
429
+
430
+ await writeFirmwareByteSource({
431
+ source,
432
+ chunkSize,
433
+ write: async ({ data, sourceOffset, length, first }) => {
434
+ const progress =
435
+ totalSize !== undefined && processedSize !== undefined
436
+ ? Math.min(Math.ceil(((processedSize + sourceOffset + length) / totalSize) * 100), 99)
437
+ : Math.min(Math.ceil(((sourceOffset + length) / source.size) * 100), 99);
438
+ const writeRes = await this.emmcFileWriteWithRetry(
439
+ filePath,
440
+ length,
441
+ sourceOffset,
442
+ data,
443
+ first,
444
+ progress
445
+ );
446
+ if (!writeRes) {
447
+ throw ERRORS.TypedError(
448
+ HardwareErrorCode.EmmcFileWriteFirmwareError,
449
+ 'transfer data error'
450
+ );
451
+ }
452
+ const processedBytes = Number(writeRes.message.processed_byte);
453
+ this.postProgressMessage(progress, 'transferData');
454
+ return Number.isFinite(processedBytes) ? processedBytes : length;
455
+ },
456
+ });
457
+
458
+ return totalSize !== undefined ? (processedSize ?? 0) + source.size : 0;
459
+ }
460
+
397
461
  async emmcFileWriteWithRetry(
398
462
  filePath: string,
399
463
  chunkLength: number,
@@ -448,12 +512,7 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
448
512
  const env = DataManager.getSettings('env');
449
513
  if (DataManager.isBleConnect(env)) {
450
514
  await wait(3000);
451
- await this.device.deviceConnector?.acquire(
452
- this.device.originalDescriptor.id,
453
- null,
454
- true,
455
- this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
456
- );
515
+ await this.device.deviceConnector?.acquire(this.device.originalDescriptor.id, null, true);
457
516
  await this.device.initialize();
458
517
  } else if (
459
518
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -461,10 +520,7 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
461
520
  ) {
462
521
  const deviceDiff = await this.device.deviceConnector?.enumerate();
463
522
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
464
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
465
- connectProtocol:
466
- this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
467
- });
523
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
468
524
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
469
525
  this.device.updateFromCache(deviceList[0]);
470
526
  await this.device.acquire();
@@ -0,0 +1,9 @@
1
+ import type { FirmwareUpdateCapabilities } from '../../types/api/firmwareUpdateCapabilities';
2
+
3
+ export const getFirmwareUpdateCapabilities = (): FirmwareUpdateCapabilities => ({
4
+ planSchemaVersion: 2,
5
+ preparedPlanSchemaVersion: 2,
6
+ hostBindingProtocolVersion: 2,
7
+ manifestModes: ['external-only', 'sdk-managed'],
8
+ supportsArtifactReader: true,
9
+ });