@onekeyfe/hd-core 1.2.0-alpha.54 → 1.2.0-alpha.56

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 (262) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +231 -0
  2. package/__tests__/DeviceCommands.test.ts +45 -0
  3. package/__tests__/DeviceEventRegistration.test.ts +6 -0
  4. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
  5. package/__tests__/connectSettings.test.ts +5 -47
  6. package/__tests__/device-lifecycle-events.test.ts +105 -3
  7. package/__tests__/device-state-contract.test.ts +1 -0
  8. package/__tests__/device-state-mapper.test.ts +1 -1
  9. package/__tests__/deviceSettings.test.ts +1 -1
  10. package/__tests__/deviceUploadNft.test.ts +293 -0
  11. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  12. package/__tests__/get-device-state.test.ts +132 -12
  13. package/__tests__/homescreen.test.ts +41 -1
  14. package/__tests__/kaspaSignTransaction.test.ts +3 -26
  15. package/__tests__/logBlockEvent.test.ts +1 -1
  16. package/__tests__/method-protocol-support.test.ts +19 -0
  17. package/__tests__/open-wallet-session.test.ts +568 -37
  18. package/__tests__/pro2Nft.test.ts +108 -0
  19. package/__tests__/protocol-binding.test.ts +89 -0
  20. package/__tests__/protocol-v2-resources.test.ts +286 -0
  21. package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
  22. package/__tests__/protocol-v2-unlock-policy.test.ts +201 -35
  23. package/__tests__/protocol-v2.test.ts +1353 -1011
  24. package/__tests__/protocolV2FileWrite.test.ts +39 -0
  25. package/__tests__/protocolV2UiInteraction.test.ts +63 -0
  26. package/__tests__/public-pro2-api-boundary.test.ts +1 -0
  27. package/__tests__/search-devices.test.ts +12 -3
  28. package/__tests__/uiProgressThrottle.test.ts +74 -0
  29. package/__tests__/uiPromiseRegistry.test.ts +86 -0
  30. package/dist/api/BaseMethod.d.ts +3 -1
  31. package/dist/api/BaseMethod.d.ts.map +1 -1
  32. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  33. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  34. package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
  35. package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
  36. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  37. package/dist/api/FirmwareUpdateV2.d.ts +0 -11
  38. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  39. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  40. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  41. package/dist/api/FirmwareUpdateV4.d.ts +11 -25
  42. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  43. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  44. package/dist/api/OpenWalletSession.d.ts.map +1 -1
  45. package/dist/api/SearchDevices.d.ts.map +1 -1
  46. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  47. package/dist/api/device/DeviceUnlock.d.ts +2 -2
  48. package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
  49. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  50. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  51. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -9
  52. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  53. package/dist/api/firmware/getBinary.d.ts +0 -7
  54. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  55. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  56. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  57. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  58. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  59. package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
  60. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  61. package/dist/api/index.d.ts +2 -0
  62. package/dist/api/index.d.ts.map +1 -1
  63. package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
  64. package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
  65. package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
  66. package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
  67. package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
  68. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  69. package/dist/core/deviceEventRegistration.d.ts +2 -0
  70. package/dist/core/deviceEventRegistration.d.ts.map +1 -1
  71. package/dist/core/index.d.ts.map +1 -1
  72. package/dist/core/uiPromiseRegistry.d.ts +4 -0
  73. package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
  74. package/dist/data-manager/DataManager.d.ts +4 -2
  75. package/dist/data-manager/DataManager.d.ts.map +1 -1
  76. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  77. package/dist/device/Device.d.ts +29 -6
  78. package/dist/device/Device.d.ts.map +1 -1
  79. package/dist/device/DeviceCommands.d.ts +4 -4
  80. package/dist/device/DeviceCommands.d.ts.map +1 -1
  81. package/dist/device/DevicePool.d.ts.map +1 -1
  82. package/dist/events/device.d.ts +4 -0
  83. package/dist/events/device.d.ts.map +1 -1
  84. package/dist/events/logBlockEvent.d.ts.map +1 -1
  85. package/dist/events/ui-promise.d.ts +4 -2
  86. package/dist/events/ui-promise.d.ts.map +1 -1
  87. package/dist/events/ui-request.d.ts +31 -2
  88. package/dist/events/ui-request.d.ts.map +1 -1
  89. package/dist/events/ui-response.d.ts +10 -2
  90. package/dist/events/ui-response.d.ts.map +1 -1
  91. package/dist/index.d.ts +214 -231
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +2634 -3530
  94. package/dist/inject.d.ts +6 -1
  95. package/dist/inject.d.ts.map +1 -1
  96. package/dist/lowLevelInject.d.ts.map +1 -1
  97. package/dist/protocols/protocol-v2/features.d.ts +0 -4
  98. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  99. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
  100. package/dist/protocols/protocol-v2/resources.d.ts +30 -0
  101. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
  102. package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
  103. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  104. package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
  105. package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
  106. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
  107. package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
  108. package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
  109. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  110. package/dist/topLevelInject.d.ts.map +1 -1
  111. package/dist/types/api/checkAllFirmwareRelease.d.ts +2 -4
  112. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  113. package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
  114. package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
  115. package/dist/types/api/deviceUnlock.d.ts +5 -1
  116. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  117. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  118. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  119. package/dist/types/api/export.d.ts +2 -4
  120. package/dist/types/api/export.d.ts.map +1 -1
  121. package/dist/types/api/firmwareUpdate.d.ts +2 -70
  122. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  123. package/dist/types/api/index.d.ts +7 -10
  124. package/dist/types/api/index.d.ts.map +1 -1
  125. package/dist/types/api/protocolV2.d.ts +3 -0
  126. package/dist/types/api/protocolV2.d.ts.map +1 -1
  127. package/dist/types/device.d.ts.map +1 -1
  128. package/dist/types/params.d.ts +1 -0
  129. package/dist/types/params.d.ts.map +1 -1
  130. package/dist/types/settings.d.ts +22 -13
  131. package/dist/types/settings.d.ts.map +1 -1
  132. package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
  133. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  134. package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
  135. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  136. package/dist/utils/homescreen.d.ts +4 -0
  137. package/dist/utils/homescreen.d.ts.map +1 -1
  138. package/dist/utils/index.d.ts +1 -1
  139. package/dist/utils/index.d.ts.map +1 -1
  140. package/dist/utils/patch.d.ts +1 -1
  141. package/dist/utils/patch.d.ts.map +1 -1
  142. package/dist/utils/pro2Nft.d.ts +31 -0
  143. package/dist/utils/pro2Nft.d.ts.map +1 -0
  144. package/dist/utils/pro2Wallpaper.d.ts +10 -0
  145. package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
  146. package/dist/utils/uiProgressThrottle.d.ts +3 -0
  147. package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
  148. package/package.json +4 -4
  149. package/src/api/BaseMethod.ts +8 -10
  150. package/src/api/CheckAllFirmwareRelease.ts +54 -57
  151. package/src/api/DetectDeviceConnectProtocol.ts +18 -0
  152. package/src/api/FirmwareUpdate.ts +7 -15
  153. package/src/api/FirmwareUpdateV2.ts +126 -316
  154. package/src/api/FirmwareUpdateV3.ts +63 -265
  155. package/src/api/FirmwareUpdateV4.ts +584 -975
  156. package/src/api/GetPassphraseState.ts +7 -1
  157. package/src/api/OpenWalletSession.ts +70 -17
  158. package/src/api/SearchDevices.ts +3 -1
  159. package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
  160. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +34 -11
  161. package/src/api/device/DeviceUnlock.ts +8 -3
  162. package/src/api/device/DeviceUpdateBootloader.ts +6 -122
  163. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +16 -83
  164. package/src/api/firmware/updateBootloader.ts +4 -19
  165. package/src/api/firmware/uploadFirmware.ts +39 -144
  166. package/src/api/helpers/protocolV2FileWrite.ts +27 -7
  167. package/src/api/index.ts +2 -0
  168. package/src/api/kaspa/KaspaSignTransaction.ts +1 -12
  169. package/src/api/protocol-v2/DeviceUploadNft.ts +189 -0
  170. package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
  171. package/src/api/protocol-v2/helpers.ts +1 -0
  172. package/src/core/deviceEventRegistration.ts +4 -0
  173. package/src/core/index.ts +167 -83
  174. package/src/core/uiPromiseRegistry.ts +41 -0
  175. package/src/data/messages/messages-protocol-v2.json +25 -0
  176. package/src/data-manager/DataManager.ts +71 -39
  177. package/src/data-manager/connectSettings.ts +0 -11
  178. package/src/device/Device.ts +259 -43
  179. package/src/device/DeviceCommands.ts +7 -1
  180. package/src/device/DevicePool.ts +7 -2
  181. package/src/events/device.ts +4 -0
  182. package/src/events/logBlockEvent.ts +1 -0
  183. package/src/events/ui-promise.ts +4 -2
  184. package/src/events/ui-request.ts +36 -2
  185. package/src/events/ui-response.ts +12 -2
  186. package/src/index.ts +0 -5
  187. package/src/inject.ts +60 -24
  188. package/src/lowLevelInject.ts +7 -8
  189. package/src/protocols/protocol-v2/features.ts +10 -7
  190. package/src/protocols/protocol-v2/firmware.ts +2 -0
  191. package/src/protocols/protocol-v2/resources.ts +359 -0
  192. package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
  193. package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
  194. package/src/protocols/protocol-v2/unlockPolicyRunner.ts +118 -0
  195. package/src/protocols/protocol-v2/walletSession.ts +214 -36
  196. package/src/topLevelInject.ts +7 -8
  197. package/src/types/api/checkAllFirmwareRelease.ts +2 -4
  198. package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
  199. package/src/types/api/deviceUnlock.ts +12 -1
  200. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  201. package/src/types/api/export.ts +1 -18
  202. package/src/types/api/firmwareUpdate.ts +3 -76
  203. package/src/types/api/index.ts +13 -14
  204. package/src/types/api/protocolV2.ts +13 -0
  205. package/src/types/device.ts +3 -0
  206. package/src/types/params.ts +7 -1
  207. package/src/types/settings.ts +42 -13
  208. package/src/utils/deviceFeaturesCompat.ts +0 -6
  209. package/src/utils/deviceFeaturesUtils.ts +8 -0
  210. package/src/utils/homescreen.ts +32 -6
  211. package/src/utils/index.ts +6 -1
  212. package/src/utils/pro2Nft.ts +142 -0
  213. package/src/utils/pro2Wallpaper.ts +35 -8
  214. package/src/utils/uiProgressThrottle.ts +63 -0
  215. package/__tests__/device-initialize-timeout.test.ts +0 -56
  216. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
  217. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  218. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  219. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  220. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
  221. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  222. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -294
  223. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  224. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
  225. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
  226. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  227. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  228. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  229. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  230. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  231. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  232. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  233. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  234. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  235. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  236. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  237. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
  238. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  239. package/dist/api/firmware/progressThrottle.d.ts +0 -3
  240. package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
  241. package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
  242. package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
  243. package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
  244. package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
  245. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  246. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  247. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  248. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  249. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  250. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  251. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  252. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  253. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  254. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  255. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
  256. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -415
  257. package/src/api/firmware/progressThrottle.ts +0 -44
  258. package/src/protocols/protocol-v2/lockedError.ts +0 -10
  259. package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
  260. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  261. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  262. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -13,8 +13,6 @@ 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';
18
16
 
19
17
  import type {
20
18
  IFirmwareUpdateProgressType,
@@ -25,22 +23,11 @@ import type { RebootType } from '@onekeyfe/hd-transport';
25
23
  import type { Deferred } from '@onekeyfe/hd-shared';
26
24
  import type { KnownDevice } from '../../types';
27
25
  import type { TypedResponseMessage } from '../../device/DeviceCommands';
28
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
29
26
 
30
27
  const Log = getLogger(LoggerNames.Method);
31
28
  const SESSION_ERROR = 'session not found';
32
29
  const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
33
30
 
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;
43
-
44
31
  const isDeviceDisconnectedError = (error: unknown) => {
45
32
  const message = error instanceof Error ? error.message : String(error ?? '');
46
33
  return (
@@ -53,8 +40,6 @@ const isDeviceDisconnectedError = (error: unknown) => {
53
40
  export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
54
41
  checkPromise: Deferred<any> | null = null;
55
42
 
56
- private shouldPostFirmwareProgress = createFirmwareProgressThrottle();
57
-
58
43
  init(): void {}
59
44
 
60
45
  run(): Promise<any> {
@@ -98,10 +83,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
98
83
  * @param progress Post the percentage of the progress
99
84
  */
100
85
  postProgressMessage = (progress: number, progressType: IFirmwareUpdateProgressType) => {
101
- if (!this.shouldPostFirmwareProgress(progress, progressType)) {
102
- return;
103
- }
104
-
105
86
  this.postMessage(
106
87
  createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
107
88
  device: this.device.toMessageObject() as KnownDevice,
@@ -151,10 +132,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
151
132
  this.checkPromise = createDeferred();
152
133
  const env = DataManager.getSettings('env');
153
134
  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;
158
135
 
159
136
  Log.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
160
137
 
@@ -210,18 +187,14 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
210
187
  }
211
188
 
212
189
  if (isBleReconnect) {
213
- if (bleProbeInFlight) return;
214
- bleProbeInFlight = true;
215
190
  try {
216
191
  await this.device.deviceConnector?.acquire(
217
192
  this.device.originalDescriptor.id,
218
193
  null,
219
- true
194
+ true,
195
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
220
196
  );
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 });
197
+ await this.device.initialize();
225
198
  if (this.device.isBootloader()) {
226
199
  clearInterval(intervalTimer);
227
200
  this.checkPromise?.resolve(true);
@@ -229,8 +202,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
229
202
  } catch (e) {
230
203
  // ignore error because of device is not connected
231
204
  Log.log('catch Bluetooth error when device is restarting: ', e);
232
- } finally {
233
- bleProbeInFlight = false;
234
205
  }
235
206
  } else {
236
207
  await this._checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer);
@@ -255,7 +226,9 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
255
226
  ) {
256
227
  const deviceDiff = await this.device.deviceConnector?.enumerate();
257
228
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
258
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId);
229
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId, {
230
+ connectProtocol: this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
231
+ });
259
232
 
260
233
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
261
234
  // should update current device from cache
@@ -410,54 +383,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
410
383
  return totalSize !== undefined ? (processedSize ?? 0) + payload.byteLength : 0;
411
384
  }
412
385
 
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
-
461
386
  async emmcFileWriteWithRetry(
462
387
  filePath: string,
463
388
  chunkLength: number,
@@ -512,7 +437,12 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
512
437
  const env = DataManager.getSettings('env');
513
438
  if (DataManager.isBleConnect(env)) {
514
439
  await wait(3000);
515
- await this.device.deviceConnector?.acquire(this.device.originalDescriptor.id, null, true);
440
+ await this.device.deviceConnector?.acquire(
441
+ this.device.originalDescriptor.id,
442
+ null,
443
+ true,
444
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
445
+ );
516
446
  await this.device.initialize();
517
447
  } else if (
518
448
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -520,7 +450,10 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
520
450
  ) {
521
451
  const deviceDiff = await this.device.deviceConnector?.enumerate();
522
452
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
523
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
453
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
454
+ connectProtocol:
455
+ this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
456
+ });
524
457
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
525
458
  this.device.updateFromCache(deviceList[0]);
526
459
  await this.device.acquire();
@@ -8,7 +8,6 @@ import { shouldUpdateBootloaderForClassicAndMini } from './bootloaderHelper';
8
8
 
9
9
  import type { Features } from '../../types';
10
10
  import type { EFirmwareType } from '@onekeyfe/hd-shared';
11
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
12
11
 
13
12
  export function checkNeedUpdateBootForTouch(features: Features, firmwareType: EFirmwareType) {
14
13
  const deviceType = getDeviceType(features);
@@ -63,7 +62,8 @@ export function checkNeedUpdateBootForClassicAndMini({
63
62
  }
64
63
 
65
64
  const INIT_DATA_CHUNK_SIZE = 16 * 1024;
66
- const readBootloaderLength = (chunk: Uint8Array) => {
65
+ export function checkBootloaderLength(data: ArrayBuffer) {
66
+ const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
67
67
  const buffer = ByteBuffer.wrap(chunk, undefined, undefined, true);
68
68
  buffer.LE();
69
69
  // byte 'O', 'K', 'T', 'B'
@@ -77,21 +77,6 @@ const readBootloaderLength = (chunk: Uint8Array) => {
77
77
  buffer.readUint32();
78
78
  // codelen
79
79
  const codelen = buffer.readUint32();
80
- return hdrlen + codelen;
81
- };
82
-
83
- export function checkBootloaderLength(data: ArrayBuffer) {
84
- if (data.byteLength < 16) {
85
- return false;
86
- }
87
- const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
88
- return readBootloaderLength(chunk) === data.byteLength;
80
+ const bootloaderLength = hdrlen + codelen;
81
+ return bootloaderLength === data.byteLength;
89
82
  }
90
-
91
- export const checkBootloaderSourceLength = async (source: FirmwareByteSource) => {
92
- if (source.size < 16) {
93
- return false;
94
- }
95
- const chunk = new Uint8Array(await source.readAt(0, Math.min(INIT_DATA_CHUNK_SIZE, source.size)));
96
- return readBootloaderLength(chunk) === source.size;
97
- };
@@ -10,7 +10,6 @@ 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';
14
13
 
15
14
  import type { KnownDevice } from '../../types';
16
15
  import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
@@ -18,7 +17,6 @@ import type { PROTO } from '../../constants';
18
17
  import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
19
18
  import type { Success } from '@onekeyfe/hd-transport';
20
19
  import type { Device } from '../../device/Device';
21
- import type { FirmwareByteSource } from './FirmwareArtifactSource';
22
20
 
23
21
  const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
24
22
  const SESSION_ERROR = 'session not found';
@@ -90,20 +88,17 @@ export const waitBleInstall = async (updateType: string) => {
90
88
  }
91
89
  };
92
90
 
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 (
91
+ export const uploadFirmware = async (
101
92
  updateType: 'firmware' | 'ble',
102
93
  typedCall: TypedCall,
103
94
  postMessage: (message: CoreMessage) => void,
104
95
  device: Device,
105
- source: FirmwareByteSource,
106
- rebootOnSuccess?: boolean,
96
+ {
97
+ payload,
98
+ rebootOnSuccess,
99
+ }: PROTO.FirmwareUpload & {
100
+ rebootOnSuccess?: boolean;
101
+ },
107
102
  isUpdateBootloader?: boolean
108
103
  ) => {
109
104
  const deviceType = device.getCurrentDeviceType();
@@ -124,20 +119,20 @@ export const uploadFirmwareFromSource = async (
124
119
  if (supportUpgradeFileHeader) {
125
120
  // Extract and validate firmware header (first 1KB)
126
121
  const HEADER_SIZE = 1024;
127
- if (source.size < HEADER_SIZE) {
122
+ if (payload.byteLength < HEADER_SIZE) {
128
123
  throw ERRORS.TypedError(
129
124
  HardwareErrorCode.RuntimeError,
130
- `firmware payload too small: ${source.size} bytes, expected at least ${HEADER_SIZE} bytes`
125
+ `firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
131
126
  );
132
127
  }
133
128
 
134
129
  Log.debug('Uploading firmware header:', {
135
130
  size: HEADER_SIZE,
136
- totalSize: source.size,
131
+ totalSize: payload.byteLength,
137
132
  });
138
133
  postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
139
134
 
140
- const header = new Uint8Array(await source.readAt(0, HEADER_SIZE));
135
+ const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
141
136
 
142
137
  try {
143
138
  const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
@@ -174,9 +169,6 @@ export const uploadFirmwareFromSource = async (
174
169
  postProgressMessage(device, 0, 'installingFirmware', postMessage);
175
170
  let updateResponse: TypedResponseMessage<'Success'>;
176
171
  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);
180
172
  updateResponse = await typedCall('FirmwareUpload', 'Success', {
181
173
  payload,
182
174
  });
@@ -208,7 +200,9 @@ export const uploadFirmwareFromSource = async (
208
200
  updateType,
209
201
  postMessage,
210
202
  device,
211
- source,
203
+ {
204
+ payload,
205
+ },
212
206
  rebootOnSuccess
213
207
  );
214
208
  return response.message;
@@ -217,7 +211,7 @@ export const uploadFirmwareFromSource = async (
217
211
 
218
212
  postConfirmationMessage(device);
219
213
  postProgressTip(device, 'ConfirmOnDevice', postMessage);
220
- const length = source.size;
214
+ const length = payload.byteLength;
221
215
 
222
216
  let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
223
217
  postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
@@ -226,7 +220,7 @@ export const uploadFirmwareFromSource = async (
226
220
  const start = response.message.offset!;
227
221
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
228
222
  const end = response.message.offset! + response.message.length!;
229
- const chunk = await source.readAt(start, end - start);
223
+ const chunk = payload.slice(start, end);
230
224
 
231
225
  if (start > 0) {
232
226
  postProgressMessage(
@@ -255,45 +249,11 @@ export const uploadFirmwareFromSource = async (
255
249
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
256
250
  };
257
251
 
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
-
292
252
  const newTouchUpdateProcess = async (
293
253
  updateType: 'firmware' | 'ble',
294
254
  postMessage: (message: CoreMessage) => void,
295
255
  device: Device,
296
- source: FirmwareByteSource,
256
+ { payload }: PROTO.FirmwareUpload,
297
257
  rebootOnSuccess = true
298
258
  ) => {
299
259
  let typedCall = device.getCommands().typedCall.bind(device.getCommands());
@@ -303,13 +263,13 @@ const newTouchUpdateProcess = async (
303
263
  const env = DataManager.getSettings('env');
304
264
  const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
305
265
  const chunkSize = 1024 * perPackageSize;
306
- const totalChunks = Math.ceil(source.size / chunkSize);
266
+ const totalChunks = Math.ceil(payload.byteLength / chunkSize);
307
267
  let offset = 0;
308
268
  for (let i = 0; i < totalChunks; i++) {
309
269
  const chunkStart = i * chunkSize;
310
- const chunkEnd = Math.min(chunkStart + chunkSize, source.size);
270
+ const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
311
271
  const chunkLength = chunkEnd - chunkStart;
312
- const chunk = await source.readAt(chunkStart, chunkLength);
272
+ const chunk = payload.slice(chunkStart, chunkEnd);
313
273
  const overwrite = i === 0;
314
274
  const progress = Math.round(((i + 1) / totalChunks) * 100);
315
275
  const writeRes = await emmcFileWriteWithRetry(
@@ -362,7 +322,12 @@ const newTouchUpdateProcess = async (
362
322
  try {
363
323
  if (isBleReconnect) {
364
324
  try {
365
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
325
+ await device.deviceConnector?.acquire(
326
+ device.originalDescriptor.id,
327
+ null,
328
+ true,
329
+ device.originalDescriptor.protocolType
330
+ );
366
331
  const typedCall = device.getCommands().typedCall.bind(device.getCommands());
367
332
  await Promise.race([
368
333
  typedCall('Initialize', 'Features', {}),
@@ -381,7 +346,8 @@ const newTouchUpdateProcess = async (
381
346
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
382
347
  const { deviceList } = await DevicePool.getDevices(
383
348
  devicesDescriptor,
384
- device.originalDescriptor.id
349
+ device.originalDescriptor.id,
350
+ { connectProtocol: device.originalDescriptor.protocolType }
385
351
  );
386
352
  if (deviceList.length === 1) {
387
353
  device.updateFromCache(deviceList[0]);
@@ -456,7 +422,12 @@ const emmcFileWriteWithRetry = async (
456
422
  const env = DataManager.getSettings('env');
457
423
  if (DataManager.isBleConnect(env)) {
458
424
  await wait(3000);
459
- await device.deviceConnector?.acquire(device.originalDescriptor.id, null, true);
425
+ await device.deviceConnector?.acquire(
426
+ device.originalDescriptor.id,
427
+ null,
428
+ true,
429
+ device.originalDescriptor.protocolType
430
+ );
460
431
  await device.initialize();
461
432
  } else if (
462
433
  error?.message?.indexOf(SESSION_ERROR) > -1 ||
@@ -464,7 +435,9 @@ const emmcFileWriteWithRetry = async (
464
435
  ) {
465
436
  const deviceDiff = await device.deviceConnector?.enumerate();
466
437
  const devicesDescriptor = deviceDiff?.descriptors ?? [];
467
- const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined);
438
+ const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
439
+ connectProtocol: device.originalDescriptor.protocolType,
440
+ });
468
441
  if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
469
442
  device.updateFromCache(deviceList[0]);
470
443
  await device.acquire();
@@ -530,67 +503,6 @@ export const updateResource = async (
530
503
  return processResourceRequest(typedCall, res, data);
531
504
  };
532
505
 
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
-
594
506
  export const updateResources = async (
595
507
  typedCall: TypedCall,
596
508
  postMessage: (message: CoreMessage) => void,
@@ -625,28 +537,11 @@ export const updateBootloader = async (
625
537
  typedCall: TypedCall,
626
538
  postMessage: (message: CoreMessage) => void,
627
539
  device: Device,
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
540
+ source: ArrayBuffer
646
541
  ) => {
647
542
  postProgressTip(device, 'UpdateBootloader', postMessage);
648
543
  postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
649
- await updateResourceFromSource(typedCall, 'bootloader.bin', source, () => {
544
+ await updateResource(typedCall, 'bootloader.bin', source, () => {
650
545
  postProcessingMessage('resource', postMessage);
651
546
  });
652
547
  postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
@@ -31,19 +31,22 @@ export type ProtocolV2FileWriteOptions = {
31
31
  uiPercentage?: number;
32
32
  timeoutMs?: number;
33
33
  maxChunkRetries?: number;
34
+ paceMs?: number;
34
35
  throwIfAborted?: () => void;
35
36
  onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
36
37
  };
37
38
 
38
39
  const MIN_FILE_CHUNK_SIZE = 64;
40
+ const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
39
41
 
40
- function isRetryableFileWriteTimeout(error: unknown) {
42
+ export function isProtocolV2ResponseTimeout(error: unknown) {
41
43
  if (!error || typeof error !== 'object') return false;
42
- const candidate = error as { errorCode?: number; code?: number; message?: string };
44
+ const candidate = error as { errorCode?: number; code?: number | string; message?: string };
43
45
  const code = candidate.errorCode ?? candidate.code;
44
46
  return (
45
47
  code === HardwareErrorCode.BleTimeoutError ||
46
- /Lowlevel response timeout/i.test(candidate.message ?? '')
48
+ code === 'response-timeout' ||
49
+ /(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
47
50
  );
48
51
  }
49
52
 
@@ -119,6 +122,9 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
119
122
  let chunks = 0;
120
123
  let lastMessage: Record<string, unknown> | undefined;
121
124
  const startTime = Date.now();
125
+ let rateWindowStartedAt = startTime;
126
+ let rateWindowStartedBytes = 0;
127
+ let rateBytesPerSecond: number | undefined;
122
128
 
123
129
  while (written < dataLength) {
124
130
  options.throwIfAborted?.();
@@ -147,7 +153,7 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
147
153
  );
148
154
  isWritePending = false;
149
155
  } catch (error) {
150
- if (retryCount >= maxChunkRetries || !isRetryableFileWriteTimeout(error)) throw error;
156
+ if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
151
157
  retryCount += 1;
152
158
  options.throwIfAborted?.();
153
159
  }
@@ -176,16 +182,30 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
176
182
  written =
177
183
  rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
178
184
  chunks += 1;
179
- const elapsedMs = Date.now() - startTime;
185
+ const now = Date.now();
186
+ const elapsedMs = now - startTime;
180
187
  const transferredBytes = Math.min(written, dataLength);
188
+ const rateWindowElapsedMs = now - rateWindowStartedAt;
189
+ if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
190
+ const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
191
+ rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
192
+ rateWindowStartedAt = now;
193
+ rateWindowStartedBytes = transferredBytes;
194
+ } else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
195
+ rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
196
+ }
181
197
  options.onProgress?.({
182
198
  progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
183
199
  transferredBytes,
184
200
  totalBytes: dataLength,
185
- rateBytesPerSecond:
186
- elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
201
+ rateBytesPerSecond,
187
202
  elapsedMs,
188
203
  });
204
+ if (options.paceMs && options.paceMs > 0) {
205
+ await new Promise(resolve => {
206
+ setTimeout(resolve, options.paceMs);
207
+ });
208
+ }
189
209
  }
190
210
 
191
211
  return {
package/src/api/index.ts CHANGED
@@ -3,6 +3,7 @@ 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';
6
7
  export { default as getFeatures } from './GetFeatures';
7
8
  export { default as getDeviceState } from './GetDeviceState';
8
9
  export { default as getOnekeyFeatures } from './GetOnekeyFeatures';
@@ -49,6 +50,7 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
49
50
  export { default as deviceReboot } from './protocol-v2/DeviceReboot';
50
51
  export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
51
52
  export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
53
+ export { default as deviceUploadNft } from './protocol-v2/DeviceUploadNft';
52
54
  export { default as uploadPortfolio } from './UploadPortfolio';
53
55
 
54
56
  export { default as cipherKeyValue } from './CipherKeyValue';
@@ -506,18 +506,7 @@ 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
- 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
- }
509
+ return this.signTxStream(typedCall, response);
521
510
  }
522
511
 
523
512
  // Legacy answer to a streaming-only packet: no prehash material exists.