@onekeyfe/hd-core 1.2.0-alpha.19 → 1.2.0-alpha.20

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 (256) hide show
  1. package/__tests__/AllNetworkGetAddressBase.tracing.test.ts +75 -0
  2. package/__tests__/DeviceCommands.test.ts +143 -7
  3. package/__tests__/RequestQueue.test.ts +106 -0
  4. package/__tests__/UploadPortfolio.test.ts +46 -0
  5. package/__tests__/core-dispose.test.ts +34 -0
  6. package/__tests__/core-error-output.test.ts +39 -0
  7. package/__tests__/device-lifecycle-events.test.ts +117 -0
  8. package/__tests__/device-pool-state.test.ts +20 -1
  9. package/__tests__/device-settings.test.ts +184 -6
  10. package/__tests__/device-state-events.test.ts +1 -2
  11. package/__tests__/device-state-mapper.test.ts +33 -26
  12. package/__tests__/device-state-store.test.ts +1 -34
  13. package/__tests__/device-utils.test.ts +106 -0
  14. package/__tests__/device-wallet-session-store.test.ts +65 -29
  15. package/__tests__/deviceSettings.test.ts +21 -12
  16. package/__tests__/evmLedgerLegacySafety.test.ts +2 -2
  17. package/__tests__/evmSignTypedData.test.ts +80 -0
  18. package/__tests__/filesystemValidation.test.ts +53 -0
  19. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +402 -0
  20. package/__tests__/get-device-state.test.ts +77 -41
  21. package/__tests__/logBlockEvent.test.ts +24 -11
  22. package/__tests__/networkUtils.test.ts +386 -0
  23. package/__tests__/open-wallet-session-error-response.test.ts +43 -0
  24. package/__tests__/open-wallet-session.test.ts +559 -0
  25. package/__tests__/protocol-v2.test.ts +756 -452
  26. package/__tests__/public-device-state-api.test.ts +113 -13
  27. package/__tests__/public-pro2-api-boundary.test.ts +91 -0
  28. package/__tests__/search-devices.test.ts +43 -0
  29. package/dist/api/BaseMethod.d.ts +3 -0
  30. package/dist/api/BaseMethod.d.ts.map +1 -1
  31. package/dist/api/CheckBootloaderRelease.d.ts.map +1 -1
  32. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  33. package/dist/api/ClearSessionCache.d.ts.map +1 -1
  34. package/dist/api/DirList.d.ts.map +1 -1
  35. package/dist/api/FileRead.d.ts.map +1 -1
  36. package/dist/api/FirmwareUpdateV2.d.ts +2 -2
  37. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  38. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  39. package/dist/api/FirmwareUpdateV4.d.ts +3 -2
  40. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  41. package/dist/api/GetPassphraseState.d.ts.map +1 -1
  42. package/dist/api/OpenWalletSession.d.ts +14 -0
  43. package/dist/api/OpenWalletSession.d.ts.map +1 -0
  44. package/dist/api/PathInfo.d.ts.map +1 -1
  45. package/dist/api/PromptWebDeviceAccess.d.ts.map +1 -1
  46. package/dist/api/SearchDevices.d.ts +3 -0
  47. package/dist/api/SearchDevices.d.ts.map +1 -1
  48. package/dist/api/UploadPortfolio.d.ts.map +1 -1
  49. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  50. package/dist/api/device/DeviceChangePin.d.ts.map +1 -1
  51. package/dist/api/device/DeviceFullyUploadResource.d.ts +1 -2
  52. package/dist/api/device/DeviceFullyUploadResource.d.ts.map +1 -1
  53. package/dist/api/device/DeviceSettings.d.ts.map +1 -1
  54. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  55. package/dist/api/device/DeviceWipe.d.ts.map +1 -1
  56. package/dist/api/evm/EVMSignTypedData.d.ts.map +1 -1
  57. package/dist/api/firmware/getBinary.d.ts +7 -3
  58. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  59. package/dist/api/helpers/filesystemValidation.d.ts +3 -0
  60. package/dist/api/helpers/filesystemValidation.d.ts.map +1 -1
  61. package/dist/api/helpers/paramsValidator.d.ts +1 -0
  62. package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
  63. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  64. package/dist/api/index.d.ts +7 -11
  65. package/dist/api/index.d.ts.map +1 -1
  66. package/dist/api/protocol-v2/DeviceGetFirmwareUpdateStatus.d.ts.map +1 -1
  67. package/dist/api/protocol-v2/DeviceSettingsPageShow.d.ts.map +1 -1
  68. package/dist/api/protocol-v2/DeviceSettingsSet.d.ts.map +1 -1
  69. package/dist/api/utils.d.ts.map +1 -1
  70. package/dist/core/RequestQueue.d.ts +17 -1
  71. package/dist/core/RequestQueue.d.ts.map +1 -1
  72. package/dist/core/index.d.ts +3 -1
  73. package/dist/core/index.d.ts.map +1 -1
  74. package/dist/device/Device.d.ts +6 -5
  75. package/dist/device/Device.d.ts.map +1 -1
  76. package/dist/device/DeviceCommands.d.ts +5 -5
  77. package/dist/device/DeviceCommands.d.ts.map +1 -1
  78. package/dist/device/DevicePool.d.ts +1 -0
  79. package/dist/device/DevicePool.d.ts.map +1 -1
  80. package/dist/device/DeviceStateMapper.d.ts +2 -2
  81. package/dist/device/DeviceStateMapper.d.ts.map +1 -1
  82. package/dist/device/DeviceStateProjector.d.ts +1 -2
  83. package/dist/device/DeviceStateProjector.d.ts.map +1 -1
  84. package/dist/device/DeviceStateStore.d.ts +1 -3
  85. package/dist/device/DeviceStateStore.d.ts.map +1 -1
  86. package/dist/device/DeviceWalletSessionStore.d.ts +6 -1
  87. package/dist/device/DeviceWalletSessionStore.d.ts.map +1 -1
  88. package/dist/device/cloneDeviceState.d.ts +2 -0
  89. package/dist/device/cloneDeviceState.d.ts.map +1 -0
  90. package/dist/deviceProfile/buildDeviceFeatures.d.ts +3 -1
  91. package/dist/deviceProfile/buildDeviceFeatures.d.ts.map +1 -1
  92. package/dist/events/logBlockEvent.d.ts.map +1 -1
  93. package/dist/index.d.ts +608 -75
  94. package/dist/index.js +2287 -1706
  95. package/dist/inject.d.ts.map +1 -1
  96. package/dist/protocols/protocol-v2/deviceSession.d.ts +7 -0
  97. package/dist/protocols/protocol-v2/deviceSession.d.ts.map +1 -0
  98. package/dist/protocols/protocol-v2/features.d.ts +11 -4
  99. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  100. package/dist/protocols/protocol-v2/index.d.ts +2 -2
  101. package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
  102. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts +16 -0
  103. package/dist/protocols/protocol-v2/settingsUnlockPolicy.d.ts.map +1 -0
  104. package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
  105. package/dist/protocols/protocol-v2/walletSession.d.ts +8 -3
  106. package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
  107. package/dist/types/api/checkAllFirmwareRelease.d.ts +1 -2
  108. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  109. package/dist/types/api/deviceSettings.d.ts +1 -0
  110. package/dist/types/api/deviceSettings.d.ts.map +1 -1
  111. package/dist/types/api/deviceUnlock.d.ts +1 -1
  112. package/dist/types/api/deviceUnlock.d.ts.map +1 -1
  113. package/dist/types/api/getFeatures.d.ts.map +1 -1
  114. package/dist/types/api/getOnekeyFeatures.d.ts.map +1 -1
  115. package/dist/types/api/getPassphraseState.d.ts.map +1 -1
  116. package/dist/types/api/index.d.ts +13 -15
  117. package/dist/types/api/index.d.ts.map +1 -1
  118. package/dist/types/api/openWalletSession.d.ts +41 -0
  119. package/dist/types/api/openWalletSession.d.ts.map +1 -0
  120. package/dist/types/api/protocolV2.d.ts +6 -11
  121. package/dist/types/api/protocolV2.d.ts.map +1 -1
  122. package/dist/types/device.d.ts +2 -9
  123. package/dist/types/device.d.ts.map +1 -1
  124. package/dist/utils/assets.d.ts +2 -1
  125. package/dist/utils/assets.d.ts.map +1 -1
  126. package/dist/utils/deviceFeaturesCompat.d.ts +13 -0
  127. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -0
  128. package/dist/utils/deviceFeaturesUtils.d.ts +11 -1
  129. package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
  130. package/dist/utils/deviceInfoUtils.d.ts +9 -8
  131. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  132. package/dist/utils/deviceSettings.d.ts +2 -0
  133. package/dist/utils/deviceSettings.d.ts.map +1 -1
  134. package/dist/utils/deviceVersionUtils.d.ts +6 -5
  135. package/dist/utils/deviceVersionUtils.d.ts.map +1 -1
  136. package/dist/utils/index.d.ts +2 -2
  137. package/dist/utils/index.d.ts.map +1 -1
  138. package/dist/utils/networkUtils.d.ts +9 -1
  139. package/dist/utils/networkUtils.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/pro2Wallpaper.d.ts.map +1 -1
  143. package/package.json +4 -4
  144. package/src/api/BaseMethod.ts +17 -10
  145. package/src/api/CheckBootloaderRelease.ts +1 -2
  146. package/src/api/CheckFirmwareRelease.ts +1 -2
  147. package/src/api/ClearSessionCache.ts +0 -4
  148. package/src/api/DirList.ts +5 -3
  149. package/src/api/DirMake.ts +3 -3
  150. package/src/api/DirRemove.ts +3 -3
  151. package/src/api/FileDelete.ts +3 -3
  152. package/src/api/FileRead.ts +9 -6
  153. package/src/api/FileWrite.ts +3 -3
  154. package/src/api/FirmwareUpdate.ts +4 -4
  155. package/src/api/FirmwareUpdateV2.ts +133 -45
  156. package/src/api/FirmwareUpdateV3.ts +3 -5
  157. package/src/api/FirmwareUpdateV4.ts +192 -154
  158. package/src/api/GetPassphraseState.ts +10 -16
  159. package/src/api/OpenWalletSession.ts +221 -0
  160. package/src/api/PathInfo.ts +5 -3
  161. package/src/api/PromptWebDeviceAccess.ts +2 -3
  162. package/src/api/SearchDevices.ts +6 -2
  163. package/src/api/UploadPortfolio.ts +12 -3
  164. package/src/api/alephium/AlephiumSignTransaction.ts +2 -2
  165. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +4 -8
  166. package/src/api/benfen/BenfenGetAddress.ts +1 -1
  167. package/src/api/btc/BTCGetPublicKey.ts +1 -1
  168. package/src/api/device/DeviceChangePin.ts +1 -0
  169. package/src/api/device/DeviceFullyUploadResource.ts +4 -5
  170. package/src/api/device/DeviceSettings.ts +93 -0
  171. package/src/api/device/DeviceUpdateBootloader.ts +1 -2
  172. package/src/api/device/DeviceWipe.ts +1 -0
  173. package/src/api/evm/EVMSignTypedData.ts +3 -5
  174. package/src/api/evm/legacyV1/getAddress.ts +2 -2
  175. package/src/api/evm/legacyV1/getPublicKey.ts +2 -2
  176. package/src/api/evm/legacyV1/signMessage.ts +2 -2
  177. package/src/api/evm/legacyV1/signTypedData.ts +2 -2
  178. package/src/api/evm/legacyV1/signTypedHash.ts +2 -2
  179. package/src/api/evm/legacyV1/verifyMessage.ts +2 -2
  180. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +3 -3
  181. package/src/api/firmware/getBinary.ts +8 -3
  182. package/src/api/helpers/batchGetPublickeys.ts +2 -2
  183. package/src/api/helpers/filesystemValidation.ts +61 -0
  184. package/src/api/helpers/paramsValidator.ts +1 -1
  185. package/src/api/helpers/protocolV2FileWrite.ts +3 -2
  186. package/src/api/index.ts +9 -12
  187. package/src/api/nervos/NervosSignTransaction.ts +2 -2
  188. package/src/api/nexa/NexaSignTransaction.ts +1 -1
  189. package/src/api/protocol-v2/DeviceFactoryInfoGet.ts +1 -1
  190. package/src/api/protocol-v2/DeviceFactoryInfoSet.ts +1 -1
  191. package/src/api/protocol-v2/DeviceFirmwareUpdate.ts +4 -4
  192. package/src/api/protocol-v2/DeviceGetFirmwareUpdateStatus.ts +6 -5
  193. package/src/api/protocol-v2/DeviceInfoGet.ts +4 -4
  194. package/src/api/protocol-v2/DeviceReboot.ts +1 -1
  195. package/src/api/protocol-v2/DeviceSettingsPageShow.ts +11 -8
  196. package/src/api/protocol-v2/DeviceSettingsSet.ts +4 -11
  197. package/src/api/protocol-v2/FilesystemFormat.ts +1 -1
  198. package/src/api/protocol-v2/FilesystemPermissionFix.ts +1 -1
  199. package/src/api/protocol-v2/Ping.ts +1 -1
  200. package/src/api/protocol-v2/ProtocolInfoRequest.ts +1 -1
  201. package/src/api/utils.ts +1 -3
  202. package/src/core/RequestQueue.ts +107 -6
  203. package/src/core/index.ts +91 -46
  204. package/src/data/messages/messages-protocol-v2.json +25 -79
  205. package/src/data-manager/DataManager.ts +6 -6
  206. package/src/device/Device.ts +186 -102
  207. package/src/device/DeviceCommands.ts +51 -21
  208. package/src/device/DeviceFeaturesState.ts +4 -4
  209. package/src/device/DevicePool.ts +17 -3
  210. package/src/device/DeviceStateMapper.ts +13 -29
  211. package/src/device/DeviceStateProjector.ts +11 -8
  212. package/src/device/DeviceStateStore.ts +11 -52
  213. package/src/device/DeviceWalletSessionStore.ts +31 -4
  214. package/src/device/cloneDeviceState.ts +39 -0
  215. package/src/device/deviceIdentity.ts +2 -2
  216. package/src/deviceProfile/buildDeviceFeatures.ts +29 -88
  217. package/src/events/logBlockEvent.ts +8 -1
  218. package/src/inject.ts +14 -24
  219. package/src/protocols/protocol-v2/deviceSession.ts +24 -0
  220. package/src/protocols/protocol-v2/features.ts +37 -49
  221. package/src/protocols/protocol-v2/firmware.ts +1 -1
  222. package/src/protocols/protocol-v2/index.ts +2 -3
  223. package/src/protocols/protocol-v2/settingsUnlockPolicy.ts +61 -0
  224. package/src/protocols/protocol-v2/uiInteraction.ts +4 -3
  225. package/src/protocols/protocol-v2/walletSession.ts +57 -146
  226. package/src/types/api/checkAllFirmwareRelease.ts +1 -2
  227. package/src/types/api/deviceSettings.ts +1 -0
  228. package/src/types/api/deviceUnlock.ts +1 -1
  229. package/src/types/api/firmwareUpdate.ts +5 -5
  230. package/src/types/api/getDeviceState.ts +1 -1
  231. package/src/types/api/getFeatures.ts +3 -0
  232. package/src/types/api/getOnekeyFeatures.ts +3 -0
  233. package/src/types/api/getPassphraseState.ts +6 -0
  234. package/src/types/api/index.ts +16 -23
  235. package/src/types/api/openWalletSession.ts +64 -0
  236. package/src/types/api/protocolV2.ts +36 -18
  237. package/src/types/device.ts +20 -14
  238. package/src/types/params.ts +1 -1
  239. package/src/types/settings.ts +8 -8
  240. package/src/utils/assets.ts +4 -1
  241. package/src/utils/deviceFeaturesCompat.ts +173 -0
  242. package/src/utils/deviceFeaturesUtils.ts +9 -8
  243. package/src/utils/deviceInfoUtils.ts +26 -64
  244. package/src/utils/deviceSettings.ts +18 -11
  245. package/src/utils/deviceVersionUtils.ts +25 -44
  246. package/src/utils/findDefectiveBatchDevice.ts +3 -3
  247. package/src/utils/index.ts +2 -5
  248. package/src/utils/networkUtils.ts +270 -14
  249. package/src/utils/pro2Wallpaper.ts +11 -13
  250. package/src/utils/tracing.ts +2 -2
  251. package/dist/api/internal.d.ts +0 -4
  252. package/dist/api/internal.d.ts.map +0 -1
  253. package/dist/api/protocol-v2/DeviceSessionOpen.d.ts +0 -28
  254. package/dist/api/protocol-v2/DeviceSessionOpen.d.ts.map +0 -1
  255. package/src/api/internal.ts +0 -9
  256. package/src/api/protocol-v2/DeviceSessionOpen.ts +0 -100
@@ -11,7 +11,7 @@ import { UI_REQUEST } from '../constants/ui-request';
11
11
  import { DEVICE, FIRMWARE, createFirmwareMessage, createUiMessage } from '../events';
12
12
  import { getHDPath, toHardened } from './helpers/pathUtils';
13
13
  import { getBleFirmwareReleaseInfo, getFirmwareReleaseInfo } from './firmware/releaseHelper';
14
- import { LoggerNames, getFirmwareType, getLogger, isMethodVersionRangeUnsupported } from '../utils';
14
+ import { LoggerNames, getLogger, isMethodVersionRangeUnsupported } from '../utils';
15
15
  import { generateInstanceId } from '../utils/tracing';
16
16
  import { DeviceModelToTypes } from '../types';
17
17
 
@@ -25,6 +25,7 @@ import type { CoreContext } from '../core';
25
25
 
26
26
  export type UnlockPolicy = 'none' | 'retry-on-locked';
27
27
  export type ProtocolV2UiMode = 'auto' | 'none';
28
+ export type MethodExecutionPriority = 'normal' | 'background';
28
29
 
29
30
  const Log = getLogger(LoggerNames.Method);
30
31
 
@@ -101,6 +102,12 @@ export abstract class BaseMethod<Params = undefined> {
101
102
  */
102
103
  useDevice: boolean;
103
104
 
105
+ /** Background methods must not block user-initiated device interactions. */
106
+ executionPriority: MethodExecutionPriority = 'normal';
107
+
108
+ /** Maximum time a background method may need to observe abort and release the device. */
109
+ maxAbortLatencyMs?: number;
110
+
104
111
  /**
105
112
  * 允许的设备模式。当前设备模式在该数组中,则可以允许运行。
106
113
  * eg. NOT_INITIALIZE, BOOTLOADER, SEEDLESS
@@ -163,20 +170,20 @@ export abstract class BaseMethod<Params = undefined> {
163
170
  strictCheckDeviceSupport = false;
164
171
 
165
172
  /**
166
- * 方法是否仅支持 Protocol V2 设备(Pro2)。
167
- * core 调度在设备协议确定(acquire + initialize)后统一守卫,
168
- * V2 设备直接抛出 NotSupport 错误,方法内部不必重复判断。
173
+ * Whether this method supports Protocol V2 devices (Pro2) only.
174
+ * Core enforces this after the protocol is established during acquire and initialize,
175
+ * so implementations do not need to repeat the check.
169
176
  * @default false
170
177
  */
171
178
  requireProtocolV2 = false;
172
179
 
173
- /** Protocol V2 业务方法锁定时默认由 Core 自动解锁并重试一次。 */
180
+ /** Core unlocks and retries Protocol V2 business methods once when the device is locked. */
174
181
  unlockPolicy: UnlockPolicy = 'retry-on-locked';
175
182
 
176
- /** Protocol V2 SDK 合成的非阻塞设备交互提示;未声明时不生成交互 Event。 */
183
+ /** Non-blocking Protocol V2 interaction synthesized by the SDK. */
177
184
  protocolV2UiInteraction?: ProtocolV2InteractionDescriptor;
178
185
 
179
- /** 特殊后台方法可关闭包括自动解锁提示在内的全部 Protocol V2 合成 UI Event。 */
186
+ /** Special background methods may suppress all synthesized Protocol V2 UI events. */
180
187
  protocolV2UiMode: ProtocolV2UiMode = 'auto';
181
188
 
182
189
  protected throwIfAborted() {
@@ -251,11 +258,11 @@ export abstract class BaseMethod<Params = undefined> {
251
258
  }
252
259
 
253
260
  checkFirmwareRelease() {
254
- // 固件 release 元数据(DataManager remote config)目前只覆盖 Protocol V1 设备;
255
- // Pro2 的更新流程由 firmwareUpdateV4 自行管理,这里显式跳过而不是依赖 features 为空。
261
+ // DataManager release metadata currently covers Protocol V1 devices only.
262
+ // firmwareUpdateV4 manages Pro2 updates, so skip them explicitly.
256
263
  if (!this.device || this.device.isProtocolV2()) return;
257
264
  if (!this.device.features) return;
258
- const firmwareType = getFirmwareType(this.device.features);
265
+ const firmwareType = this.device.getCurrentFirmwareType();
259
266
  const releaseInfo = getFirmwareReleaseInfo(this.device.features, firmwareType);
260
267
  this.postMessage(
261
268
  createFirmwareMessage(FIRMWARE.RELEASE_INFO, {
@@ -1,7 +1,6 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  import { UI_REQUEST } from '../constants/ui-request';
3
3
  import { getBootloaderReleaseInfo } from './firmware/releaseHelper';
4
- import { getFirmwareType } from '../utils';
5
4
 
6
5
  import type { CheckBootloaderReleaseParams } from '../types/api/checkBootloaderRelease';
7
6
 
@@ -19,7 +18,7 @@ export default class CheckBootloaderRelease extends BaseMethod {
19
18
  const { features } = this.device;
20
19
  const payload = this.payload as CheckBootloaderReleaseParams;
21
20
 
22
- const deviceFirmwareType = getFirmwareType(features);
21
+ const deviceFirmwareType = this.device.getCurrentFirmwareType();
23
22
  const firmwareType = payload.firmwareType ?? deviceFirmwareType;
24
23
 
25
24
  const releaseInfo = getBootloaderReleaseInfo({
@@ -1,7 +1,6 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  import { UI_REQUEST } from '../constants/ui-request';
3
3
  import { getFirmwareReleaseInfo } from './firmware/releaseHelper';
4
- import { getFirmwareType } from '../utils';
5
4
 
6
5
  import type { CheckFirmwareReleaseParams } from '../types/api/checkFirmwareRelease';
7
6
 
@@ -20,7 +19,7 @@ export default class CheckFirmwareRelease extends BaseMethod {
20
19
  const payload = this.payload as CheckFirmwareReleaseParams;
21
20
 
22
21
  if (this.device.features) {
23
- const deviceFirmwareType = getFirmwareType(this.device.features);
22
+ const deviceFirmwareType = this.device.getCurrentFirmwareType();
24
23
  const firmwareType = payload.firmwareType ?? deviceFirmwareType;
25
24
 
26
25
  const releaseInfo = getFirmwareReleaseInfo(this.device.features, firmwareType);
@@ -1,5 +1,4 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
- import { DevicePool } from '../device/DevicePool';
3
2
  import { deviceWalletSessionStore } from '../device/DeviceWalletSessionStore';
4
3
 
5
4
  import type { ClearSessionCacheParams } from '../types/api/sessionCache';
@@ -24,9 +23,6 @@ export default class ClearSessionCache extends BaseMethod<ClearSessionCacheParam
24
23
  } else {
25
24
  deviceWalletSessionStore.delete(deviceId, passphraseState);
26
25
  }
27
- Object.values(DevicePool.devicesCache).forEach(device => {
28
- device.clearCachedSession(deviceId, passphraseState);
29
- });
30
26
  return Promise.resolve({ cleared: true as const });
31
27
  }
32
28
  }
@@ -1,7 +1,7 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  import {
3
- validateNonEmptyString,
4
3
  validateOptionalNonNegativeInteger,
4
+ validateProtocolV2FilesystemPath,
5
5
  } from './helpers/filesystemValidation';
6
6
 
7
7
  export type DirListParams = {
@@ -11,12 +11,14 @@ export type DirListParams = {
11
11
 
12
12
  export default class DirList extends BaseMethod<DirListParams> {
13
13
  init() {
14
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
14
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
15
15
  this.requireProtocolV2 = true;
16
16
  this.skipForceUpdateCheck = true;
17
17
  this.useDevicePassphraseState = false;
18
18
  this.params = {
19
- path: validateNonEmptyString(this.payload.path, 'path'),
19
+ path: validateProtocolV2FilesystemPath(this.payload.path, 'path', {
20
+ allowVolumeRoot: true,
21
+ }),
20
22
  depth: validateOptionalNonNegativeInteger(this.payload.depth, 'depth'),
21
23
  };
22
24
  }
@@ -1,5 +1,5 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
- import { validateNonEmptyString } from './helpers/filesystemValidation';
2
+ import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
3
3
 
4
4
  export type DirMakeParams = {
5
5
  path: string;
@@ -7,11 +7,11 @@ export type DirMakeParams = {
7
7
 
8
8
  export default class DirMake extends BaseMethod<DirMakeParams> {
9
9
  init() {
10
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
10
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
11
11
  this.requireProtocolV2 = true;
12
12
  this.skipForceUpdateCheck = true;
13
13
  this.useDevicePassphraseState = false;
14
- this.params = { path: validateNonEmptyString(this.payload.path, 'path') };
14
+ this.params = { path: validateProtocolV2FilesystemPath(this.payload.path, 'path') };
15
15
  }
16
16
 
17
17
  async run() {
@@ -1,5 +1,5 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
- import { validateNonEmptyString } from './helpers/filesystemValidation';
2
+ import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
3
3
 
4
4
  export type DirRemoveParams = {
5
5
  path: string;
@@ -7,11 +7,11 @@ export type DirRemoveParams = {
7
7
 
8
8
  export default class DirRemove extends BaseMethod<DirRemoveParams> {
9
9
  init() {
10
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
10
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
11
11
  this.requireProtocolV2 = true;
12
12
  this.skipForceUpdateCheck = true;
13
13
  this.useDevicePassphraseState = false;
14
- this.params = { path: validateNonEmptyString(this.payload.path, 'path') };
14
+ this.params = { path: validateProtocolV2FilesystemPath(this.payload.path, 'path') };
15
15
  }
16
16
 
17
17
  async run() {
@@ -1,5 +1,5 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
- import { validateNonEmptyString } from './helpers/filesystemValidation';
2
+ import { validateProtocolV2FilesystemPath } from './helpers/filesystemValidation';
3
3
 
4
4
  export type FileDeleteParams = {
5
5
  path: string;
@@ -7,11 +7,11 @@ export type FileDeleteParams = {
7
7
 
8
8
  export default class FileDelete extends BaseMethod<FileDeleteParams> {
9
9
  init() {
10
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
10
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
11
11
  this.requireProtocolV2 = true;
12
12
  this.skipForceUpdateCheck = true;
13
13
  this.useDevicePassphraseState = false;
14
- this.params = { path: validateNonEmptyString(this.payload.path, 'path') };
14
+ this.params = { path: validateProtocolV2FilesystemPath(this.payload.path, 'path') };
15
15
  }
16
16
 
17
17
  async run() {
@@ -6,10 +6,10 @@ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
6
6
 
7
7
  import { BaseMethod } from './BaseMethod';
8
8
  import {
9
- validateNonEmptyString,
10
9
  validateNonNegativeInteger,
11
10
  validateOptionalNonNegativeInteger,
12
11
  validateOptionalPercentage,
12
+ validateProtocolV2FilesystemPath,
13
13
  } from './helpers/filesystemValidation';
14
14
  import { hexToBytes, isHexString, stripHexPrefix } from './helpers/hexUtils';
15
15
  import { DataManager } from '../data-manager';
@@ -69,7 +69,11 @@ function toUint8Array(value: unknown): Uint8Array {
69
69
  return new Uint8Array(0);
70
70
  }
71
71
 
72
- function getDeviceTransferProgress(bytesBeforeChunk: number, bytesAfterChunk: number, totalBytes: number) {
72
+ function getDeviceTransferProgress(
73
+ bytesBeforeChunk: number,
74
+ bytesAfterChunk: number,
75
+ totalBytes: number
76
+ ) {
73
77
  if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
74
78
  return 100;
75
79
  }
@@ -84,11 +88,11 @@ function getDeviceTransferProgress(bytesBeforeChunk: number, bytesAfterChunk: nu
84
88
 
85
89
  export default class FileRead extends BaseMethod<FileReadParams> {
86
90
  init() {
87
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
91
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
88
92
  this.requireProtocolV2 = true;
89
93
  this.skipForceUpdateCheck = true;
90
94
  this.useDevicePassphraseState = false;
91
- const path = validateNonEmptyString(this.payload.path, 'path');
95
+ const path = validateProtocolV2FilesystemPath(this.payload.path, 'path');
92
96
  this.params = {
93
97
  path,
94
98
  offset: validateNonNegativeInteger(this.payload.offset, 'offset', 0),
@@ -136,8 +140,7 @@ export default class FileRead extends BaseMethod<FileReadParams> {
136
140
  const readLen = Math.min(chunkSize, totalLength - read);
137
141
  const offset = startOffset + read;
138
142
  const progress =
139
- this.params.uiPercentage ??
140
- getDeviceTransferProgress(read, read + readLen, totalLength);
143
+ this.params.uiPercentage ?? getDeviceTransferProgress(read, read + readLen, totalLength);
141
144
  const res = await this.device.commands.typedCall('FilesystemFileRead', 'FilesystemFile', {
142
145
  file: {
143
146
  path: this.params.path,
@@ -1,9 +1,9 @@
1
1
  import { BaseMethod } from './BaseMethod';
2
2
  import {
3
- validateNonEmptyString,
4
3
  validateNonNegativeInteger,
5
4
  validateOptionalNonNegativeInteger,
6
5
  validateOptionalPercentage,
6
+ validateProtocolV2FilesystemPath,
7
7
  validateRequiredData,
8
8
  } from './helpers/filesystemValidation';
9
9
  import { writeProtocolV2File } from './helpers/protocolV2FileWrite';
@@ -25,12 +25,12 @@ export type FileWriteParams = {
25
25
 
26
26
  export default class FileWrite extends BaseMethod<FileWriteParams> {
27
27
  init() {
28
- // Protocol V2 (Pro2) 专属方法,core 调度层统一做非 V2 设备守卫
28
+ // Protocol V2 (Pro2) only; Core rejects non-V2 devices.
29
29
  this.requireProtocolV2 = true;
30
30
  this.skipForceUpdateCheck = true;
31
31
  this.useDevicePassphraseState = false;
32
32
  validateRequiredData(this.payload.data, 'data');
33
- const path = validateNonEmptyString(this.payload.path, 'path');
33
+ const path = validateProtocolV2FilesystemPath(this.payload.path, 'path');
34
34
  const offset = validateNonNegativeInteger(this.payload.offset, 'offset', 0);
35
35
  this.params = {
36
36
  path,
@@ -14,7 +14,7 @@ import { uploadFirmware } from './firmware/uploadFirmware';
14
14
  import { createUiMessage } from '../events';
15
15
  import { DeviceModelToTypes, type KnownDevice } from '../types';
16
16
  import { isEnteredManuallyBoot } from './firmware/bootloaderHelper';
17
- import { LoggerNames, getDeviceUUID, getLogger, wait } from '../utils';
17
+ import { LoggerNames, getLogger, wait } from '../utils';
18
18
  import { DataManager } from '../data-manager';
19
19
  import { DevicePool } from '../device/DevicePool';
20
20
 
@@ -133,7 +133,7 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
133
133
  const { features, commands } = device;
134
134
  const deviceType = device.getCurrentDeviceType();
135
135
 
136
- // Protocol V2 (Pro2) 固件升级走 DeviceFirmwareUpdate 流程,禁止进入 legacy 入口
136
+ // Protocol V2 (Pro2) uses DeviceFirmwareUpdate and must not enter this legacy flow.
137
137
  if (device.isProtocolV2()) {
138
138
  throw ERRORS.TypedError(
139
139
  HardwareErrorCode.RuntimeError,
@@ -142,7 +142,7 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
142
142
  }
143
143
 
144
144
  if (!device.isBootloader() && features) {
145
- const uuid = getDeviceUUID(features);
145
+ const serialNo = device.getCurrentSerialNo();
146
146
  // should go to bootloader mode manually
147
147
  if (isEnteredManuallyBoot(features, params.updateType)) {
148
148
  return Promise.reject(ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateManuallyEnterBoot));
@@ -161,7 +161,7 @@ export default class FirmwareUpdate extends BaseMethod<Params> {
161
161
 
162
162
  // force clean classic device cache so that the device can initialize again
163
163
  if (DeviceModelToTypes.model_classic.includes(deviceType)) {
164
- DevicePool.clearDeviceCache(uuid);
164
+ DevicePool.clearDeviceCache(serialNo);
165
165
  }
166
166
  delete DevicePool.devicesCache[''];
167
167
  await this.checkPromise?.promise;
@@ -15,20 +15,14 @@ import { validateParams } from './helpers/paramsValidator';
15
15
  import { DevicePool } from '../device/DevicePool';
16
16
  import { getBinary, getInfo, getSysResourceBinary } from './firmware/getBinary';
17
17
  import { updateResources, uploadFirmware } from './firmware/uploadFirmware';
18
- import {
19
- LoggerNames,
20
- getDeviceBootloaderVersion,
21
- getDeviceFirmwareVersion,
22
- getDeviceUUID,
23
- getLogger,
24
- wait,
25
- } from '../utils';
18
+ import { LoggerNames, getLogger, wait } from '../utils';
26
19
  import { FirmwareUpdateTipMessage, createUiMessage } from '../events/ui-request';
27
20
  import { DeviceModelToTypes } from '../types';
28
21
  import { DataManager } from '../data-manager';
29
22
  import { DEVICE } from '../events';
30
23
 
31
24
  import type { Features, KnownDevice } from '../types';
25
+ import type { FirmwareBinary } from './firmware/getBinary';
32
26
 
33
27
  type Params = {
34
28
  binary?: ArrayBuffer;
@@ -41,6 +35,77 @@ type Params = {
41
35
 
42
36
  const Log = getLogger(LoggerNames.Method);
43
37
 
38
+ const FIRMWARE_DOWNLOAD_REQUEST_OPTIONS = {
39
+ connectTimeoutMs: 60_000,
40
+ readTimeoutMs: 60_000,
41
+ overallTimeoutMs: 180_000,
42
+ maxRetries: 2,
43
+ retryDelayMs: 500,
44
+ } as const;
45
+
46
+ const normalizeFirmwareBinary = (binary: unknown): FirmwareBinary | undefined => {
47
+ if (typeof binary !== 'object' || binary === null) {
48
+ return undefined;
49
+ }
50
+
51
+ const isNodeBuffer =
52
+ typeof Buffer !== 'undefined' &&
53
+ typeof Buffer.isBuffer === 'function' &&
54
+ Buffer.isBuffer(binary);
55
+ if (isNodeBuffer) {
56
+ return binary.byteLength > 0 ? binary : undefined;
57
+ }
58
+
59
+ if (typeof ArrayBuffer !== 'undefined' && binary instanceof ArrayBuffer) {
60
+ return binary.byteLength > 0 ? binary : undefined;
61
+ }
62
+
63
+ if (
64
+ typeof ArrayBuffer !== 'undefined' &&
65
+ typeof ArrayBuffer.isView === 'function' &&
66
+ ArrayBuffer.isView(binary)
67
+ ) {
68
+ if (binary.byteLength <= 0) {
69
+ return undefined;
70
+ }
71
+ const source = new Uint8Array(binary.buffer, binary.byteOffset, binary.byteLength);
72
+ const normalized = new Uint8Array(binary.byteLength);
73
+ normalized.set(source);
74
+ return normalized.buffer;
75
+ }
76
+
77
+ const customBuffer = binary as {
78
+ [index: number]: unknown;
79
+ byteLength?: unknown;
80
+ constructor?: {
81
+ isBuffer?: (value: unknown) => boolean;
82
+ };
83
+ length?: unknown;
84
+ };
85
+ if (
86
+ typeof customBuffer.constructor?.isBuffer !== 'function' ||
87
+ !customBuffer.constructor.isBuffer(binary) ||
88
+ typeof customBuffer.byteLength !== 'number' ||
89
+ !Number.isSafeInteger(customBuffer.byteLength) ||
90
+ customBuffer.byteLength <= 0 ||
91
+ typeof customBuffer.length !== 'number' ||
92
+ customBuffer.length !== customBuffer.byteLength
93
+ ) {
94
+ return undefined;
95
+ }
96
+
97
+ const { byteLength } = customBuffer;
98
+ const normalized = new Uint8Array(byteLength);
99
+ for (let index = 0; index < byteLength; index += 1) {
100
+ const { [index]: byte } = customBuffer;
101
+ if (typeof byte !== 'number' || !Number.isInteger(byte) || byte < 0 || byte > 255) {
102
+ return undefined;
103
+ }
104
+ normalized[index] = byte;
105
+ }
106
+ return normalized.buffer;
107
+ };
108
+
44
109
  export default class FirmwareUpdateV2 extends BaseMethod<Params> {
45
110
  checkPromise: Deferred<any> | null = null;
46
111
 
@@ -223,22 +288,22 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
223
288
  return false;
224
289
  }
225
290
 
226
- isEnteredManuallyBoot(features: Features) {
291
+ isEnteredManuallyBoot() {
227
292
  const deviceType = this.device.getCurrentDeviceType();
228
293
  const isMini = deviceType === EDeviceType.Mini;
229
294
  const isBoot183ClassicUpBle =
230
295
  this.params.updateType === 'firmware' &&
231
296
  deviceType === EDeviceType.Classic &&
232
- getDeviceBootloaderVersion(features).join('.') === '1.8.3';
297
+ this.device.getCurrentBootloaderVersionString() === '1.8.3';
233
298
  return isMini || isBoot183ClassicUpBle;
234
299
  }
235
300
 
236
- isSupportResourceUpdate(features: Features, updateType: string) {
301
+ isSupportResourceUpdate(updateType: string) {
237
302
  if (updateType !== 'firmware') return false;
238
303
 
239
304
  const deviceType = this.device.getCurrentDeviceType();
240
305
  const isTouchMode = deviceType === EDeviceType.Touch || deviceType === EDeviceType.Pro;
241
- const currentVersion = getDeviceFirmwareVersion(features).join('.');
306
+ const currentVersion = this.device.getCurrentFirmwareVersionString() ?? '0.0.0';
242
307
 
243
308
  return isTouchMode && semver.gte(currentVersion, '3.2.0');
244
309
  }
@@ -250,7 +315,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
250
315
  checkVersionForCopyTouchResource(features: Features | undefined, firmwareType: EFirmwareType) {
251
316
  if (!features) return;
252
317
  const deviceType = this.device.getCurrentDeviceType();
253
- const currentVersion = getDeviceFirmwareVersion(features).join('.');
318
+ const currentVersion = this.device.getCurrentFirmwareVersionString() ?? '0.0.0';
254
319
  const targetVersion = this.params.version?.join('.');
255
320
  const { updateType } = this.params;
256
321
 
@@ -276,7 +341,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
276
341
  const { features, commands } = device;
277
342
  const deviceType = device.getCurrentDeviceType();
278
343
 
279
- // Protocol V2 (Pro2) 固件升级走 DeviceFirmwareUpdate 流程,禁止进入 legacy 入口
344
+ // Protocol V2 (Pro2) uses DeviceFirmwareUpdate and must not enter this legacy flow.
280
345
  if (device.isProtocolV2()) {
281
346
  throw ERRORS.TypedError(
282
347
  HardwareErrorCode.RuntimeError,
@@ -289,15 +354,57 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
289
354
 
290
355
  this.checkVersionForCopyTouchResource(features, firmwareType);
291
356
 
357
+ let preparedBinary: FirmwareBinary | undefined;
358
+ const acquireFirmwareBinary = async (): Promise<FirmwareBinary> => {
359
+ try {
360
+ if (preparedBinary) {
361
+ return preparedBinary;
362
+ }
363
+
364
+ if (params.binary !== undefined) {
365
+ preparedBinary = normalizeFirmwareBinary(params.binary);
366
+ if (!preparedBinary) {
367
+ throw new Error('firmware binary is empty or invalid');
368
+ }
369
+ return preparedBinary;
370
+ }
371
+
372
+ if (!device.features) {
373
+ throw ERRORS.TypedError(
374
+ HardwareErrorCode.RuntimeError,
375
+ 'no features found for this device'
376
+ );
377
+ }
378
+
379
+ this.postTipMessage('DownloadFirmware');
380
+ const firmware = await getBinary({
381
+ features: device.features,
382
+ version: params.version,
383
+ updateType: params.updateType,
384
+ isUpdateBootloader: params.isUpdateBootloader,
385
+ firmwareType,
386
+ requestOptions: FIRMWARE_DOWNLOAD_REQUEST_OPTIONS,
387
+ });
388
+ preparedBinary = normalizeFirmwareBinary(firmware.binary);
389
+ if (!preparedBinary) {
390
+ throw new Error('downloaded firmware binary is empty or invalid');
391
+ }
392
+ this.postTipMessage('DownloadFirmwareSuccess');
393
+ return preparedBinary;
394
+ } catch (err) {
395
+ throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
396
+ }
397
+ };
398
+
292
399
  if (!device.isBootloader() && features) {
293
- const uuid = getDeviceUUID(features);
400
+ const serialNo = device.getCurrentSerialNo();
294
401
  // should go to bootloader mode manually
295
- if (this.isEnteredManuallyBoot(features)) {
402
+ if (this.isEnteredManuallyBoot()) {
296
403
  return Promise.reject(ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateManuallyEnterBoot));
297
404
  }
298
405
 
299
406
  // check & upgrade firmware resource
300
- if (features && this.isSupportResourceUpdate(features, params.updateType)) {
407
+ if (this.isSupportResourceUpdate(params.updateType)) {
301
408
  this.postTipMessage('CheckLatestUiResource');
302
409
  const resourceUrl = DataManager.getSysResourcesLatestRelease({
303
410
  features,
@@ -322,6 +429,12 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
322
429
  // check if the device commands has been disposed
323
430
  this.device?.commands?.checkDisposed();
324
431
 
432
+ // A failed firmware download must leave the device in normal mode.
433
+ await acquireFirmwareBinary();
434
+
435
+ // The request may outlive the current transport command instance.
436
+ this.device?.commands?.checkDisposed();
437
+
325
438
  // auto go to bootloader mode
326
439
  try {
327
440
  this.postTipMessage('AutoRebootToBootloader');
@@ -335,7 +448,7 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
335
448
 
336
449
  // force clean classic device cache so that the device can initialize again
337
450
  if (DeviceModelToTypes.model_classic.includes(deviceType)) {
338
- DevicePool.clearDeviceCache(uuid);
451
+ DevicePool.clearDeviceCache(serialNo);
339
452
  }
340
453
  delete DevicePool.devicesCache[''];
341
454
  await this.checkPromise?.promise;
@@ -360,33 +473,8 @@ export default class FirmwareUpdateV2 extends BaseMethod<Params> {
360
473
  }
361
474
  }
362
475
 
363
- let binary;
364
-
365
- try {
366
- if (params.binary) {
367
- binary = this.params.binary;
368
- } else {
369
- if (!device.features) {
370
- throw ERRORS.TypedError(
371
- HardwareErrorCode.RuntimeError,
372
- 'no features found for this device'
373
- );
374
- }
375
- this.postTipMessage('DownloadFirmware');
376
-
377
- const firmware = await getBinary({
378
- features: device.features,
379
- version: params.version,
380
- updateType: params.updateType,
381
- isUpdateBootloader: params.isUpdateBootloader,
382
- firmwareType,
383
- });
384
- binary = firmware.binary;
385
- this.postTipMessage('DownloadFirmwareSuccess');
386
- }
387
- } catch (err) {
388
- throw ERRORS.TypedError(HardwareErrorCode.FirmwareUpdateDownloadFailed, err.message ?? err);
389
- }
476
+ // Devices already in bootloader mode still acquire through the same helper.
477
+ const binary = await acquireFirmwareBinary();
390
478
 
391
479
  // check if the device commands has been disposed
392
480
  this.device?.commands?.checkDisposed();
@@ -9,8 +9,6 @@ import {
9
9
  getDeviceBLEFirmwareVersion,
10
10
  getDeviceBootloaderVersion,
11
11
  getDeviceFirmwareVersion,
12
- getDeviceType,
13
- getFirmwareType,
14
12
  getLogger,
15
13
  } from '../utils';
16
14
  import { getBinary, getSysResourceBinary } from './firmware/getBinary';
@@ -97,8 +95,8 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
97
95
  const { device } = this;
98
96
  const { features } = device;
99
97
 
100
- const deviceType = getDeviceType(features);
101
- const bootloaderCurrVersion = getDeviceBootloaderVersion(features).join('.');
98
+ const deviceType = device.getCurrentDeviceType();
99
+ const bootloaderCurrVersion = device.getCurrentBootloaderVersionString() ?? '0.0.0';
102
100
 
103
101
  this.validateDeviceAndVersion(deviceType, bootloaderCurrVersion);
104
102
 
@@ -106,7 +104,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
106
104
  throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Device features not available');
107
105
  }
108
106
 
109
- const deviceFirmwareType = getFirmwareType(features);
107
+ const deviceFirmwareType = device.getCurrentFirmwareType();
110
108
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
111
109
  this.isSwitchFirmware = firmwareType !== deviceFirmwareType;
112
110