@onekeyfe/hd-core 1.2.0-alpha.104 → 1.2.0-alpha.106

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 (46) hide show
  1. package/__tests__/DeviceCommands.test.ts +100 -28
  2. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +0 -2
  3. package/__tests__/device-lifecycle-events.test.ts +113 -2
  4. package/__tests__/device-pool-state.test.ts +1 -5
  5. package/__tests__/deviceSettings.test.ts +0 -1
  6. package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +145 -0
  7. package/__tests__/get-device-state.test.ts +0 -50
  8. package/__tests__/logBlockEvent.test.ts +13 -1
  9. package/__tests__/protocol-v2.test.ts +466 -126
  10. package/__tests__/refresh-device-state.test.ts +0 -1
  11. package/__tests__/search-devices.test.ts +0 -2
  12. package/dist/api/FirmwareUpdateV4.d.ts +7 -3
  13. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  14. package/dist/api/GetDeviceState.d.ts.map +1 -1
  15. package/dist/api/SearchDevices.d.ts.map +1 -1
  16. package/dist/api/firmware/protocolV2Release.d.ts.map +1 -1
  17. package/dist/core/index.d.ts.map +1 -1
  18. package/dist/device/Device.d.ts +1 -3
  19. package/dist/device/Device.d.ts.map +1 -1
  20. package/dist/device/DeviceCommands.d.ts.map +1 -1
  21. package/dist/device/DevicePool.d.ts +1 -1
  22. package/dist/device/DevicePool.d.ts.map +1 -1
  23. package/dist/events/logBlockEvent.d.ts.map +1 -1
  24. package/dist/index.d.ts +1 -6
  25. package/dist/index.js +260 -196
  26. package/dist/protocols/protocol-v2/features.d.ts +1 -1
  27. package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
  28. package/dist/types/api/getDeviceState.d.ts +0 -1
  29. package/dist/types/api/getDeviceState.d.ts.map +1 -1
  30. package/package.json +4 -4
  31. package/src/api/FirmwareUpdateV4.ts +262 -172
  32. package/src/api/GetDeviceState.ts +0 -1
  33. package/src/api/SearchDevices.ts +0 -2
  34. package/src/api/firmware/protocolV2Release.ts +0 -1
  35. package/src/core/index.ts +6 -6
  36. package/src/device/Device.ts +27 -63
  37. package/src/device/DeviceCommands.ts +4 -14
  38. package/src/device/DevicePool.ts +3 -11
  39. package/src/events/logBlockEvent.ts +14 -1
  40. package/src/protocols/protocol-v2/features.ts +9 -2
  41. package/src/types/api/getDeviceState.ts +0 -2
  42. package/src/utils/deviceSettings.ts +1 -1
  43. package/__tests__/protocol-v2-legacy-recovery.test.ts +0 -29
  44. package/dist/core/protocolV2LegacyRecovery.d.ts +0 -5
  45. package/dist/core/protocolV2LegacyRecovery.d.ts.map +0 -1
  46. package/src/core/protocolV2LegacyRecovery.ts +0 -12
package/dist/index.js CHANGED
@@ -41475,6 +41475,11 @@ const LogLabelMethod = new Set([
41475
41475
  'fileWrite',
41476
41476
  'fileRead',
41477
41477
  ]);
41478
+ const LogPayloadBlockMethod = new Set([
41479
+ 'deviceUploadNft',
41480
+ 'deviceUploadWallpaper',
41481
+ 'uploadPortfolio',
41482
+ ]);
41478
41483
  const SensitiveLogKeys = new Set([
41479
41484
  'devicestate',
41480
41485
  'entropy',
@@ -41531,7 +41536,10 @@ function getLogBlockLabel(message) {
41531
41536
  return undefined;
41532
41537
  }
41533
41538
  function getSafeLogPayload(value, blockLabel) {
41534
- if (blockLabel && (LogBlockEvent.has(blockLabel) || isSigningMethod(blockLabel))) {
41539
+ if (blockLabel &&
41540
+ (LogBlockEvent.has(blockLabel) ||
41541
+ LogPayloadBlockMethod.has(blockLabel) ||
41542
+ isSigningMethod(blockLabel))) {
41535
41543
  return { method: blockLabel, payload: '[REDACTED]' };
41536
41544
  }
41537
41545
  const redactedValue = redactLogValue(value, new WeakSet());
@@ -42465,7 +42473,7 @@ const getAutoShutDownOptions = (deviceType, protocol) => {
42465
42473
  return withNever([60000, 120000, 300000, 600000], protocol);
42466
42474
  case hdShared.EDeviceType.Pro2:
42467
42475
  case hdShared.EDeviceType.Neo:
42468
- return withNever([60000, 120000, 300000, 600000, 1800000], protocol);
42476
+ return withNever([60000, 120000, 300000, 600000], protocol);
42469
42477
  default:
42470
42478
  return [];
42471
42479
  }
@@ -43237,7 +43245,7 @@ class DevicePool extends events.exports {
43237
43245
  try {
43238
43246
  yield device.initialize(initOptions);
43239
43247
  if ((initOptions === null || initOptions === void 0 ? void 0 : initOptions.refreshRuntimeState) && device.isProtocolV2()) {
43240
- yield this._refreshProtocolV2DiscoveryState(device, initOptions);
43248
+ yield this._refreshProtocolV2DiscoveryState(device);
43241
43249
  }
43242
43250
  }
43243
43251
  finally {
@@ -43254,28 +43262,30 @@ class DevicePool extends events.exports {
43254
43262
  let refreshError;
43255
43263
  yield device.run(() => __awaiter(this, void 0, void 0, function* () {
43256
43264
  try {
43257
- yield this._refreshProtocolV2DiscoveryState(device, initOptions);
43265
+ yield this._refreshProtocolV2DiscoveryState(device);
43258
43266
  }
43259
43267
  catch (error) {
43260
43268
  refreshError = error;
43261
43269
  }
43262
- }), Object.assign({ connectProtocol: initOptions.connectProtocol, forceProtocolDetection: initOptions.forceProtocolDetection }, (initOptions.allowLegacyProtocolV2ProtocolInfo
43263
- ? { allowLegacyProtocolV2ProtocolInfo: true }
43264
- : {})));
43270
+ }), {
43271
+ connectProtocol: initOptions.connectProtocol,
43272
+ forceProtocolDetection: initOptions.forceProtocolDetection,
43273
+ });
43265
43274
  if (refreshError instanceof Error)
43266
43275
  throw refreshError;
43267
43276
  if (refreshError)
43268
43277
  throw new Error(String(refreshError));
43269
43278
  });
43270
43279
  }
43271
- static _refreshProtocolV2DiscoveryState(device, initOptions) {
43280
+ static _refreshProtocolV2DiscoveryState(device) {
43272
43281
  return __awaiter(this, void 0, void 0, function* () {
43273
- const stateReadOptions = (initOptions === null || initOptions === void 0 ? void 0 : initOptions.allowLegacyProtocolV2ProtocolInfo)
43274
- ? { allowLegacyProtocolV2ProtocolInfo: true }
43275
- : {};
43276
- yield device.getDeviceState(Object.assign({ refreshSections: ['status'] }, stateReadOptions));
43282
+ yield device.getDeviceState({
43283
+ refreshSections: ['status'],
43284
+ });
43277
43285
  try {
43278
- yield device.getDeviceState(Object.assign({ refreshSections: ['settings'] }, stateReadOptions));
43286
+ yield device.getDeviceState({
43287
+ refreshSections: ['settings'],
43288
+ });
43279
43289
  }
43280
43290
  catch (error) {
43281
43291
  Log$j.debug('Unable to refresh Protocol V2 device label during discovery', error);
@@ -43717,9 +43727,6 @@ class DeviceCommands {
43717
43727
  const promise = this.transport.call(this.mainId, type, msg !== null && msg !== void 0 ? msg : {}, options);
43718
43728
  this.callPromise = promise;
43719
43729
  const res = yield promise;
43720
- if (!shouldReduceDebug) {
43721
- LogCore.debug('[DeviceCommands] [call] Received', res.type, hdTransport.getSafeTransportLogPayload(res.message, res.type));
43722
- }
43723
43730
  return res;
43724
43731
  }
43725
43732
  catch (error) {
@@ -43812,12 +43819,10 @@ class DeviceCommands {
43812
43819
  if (!shouldReduceDebugForCall(callType)) {
43813
43820
  Log$h.debug('_filterCommonTypes: ', {
43814
43821
  request: callType,
43815
- response: callType === 'DeviceFirmwareUpdateStatusGet'
43816
- ? {
43817
- type: res.type,
43818
- message: hdTransport.getSafeTransportLogPayload(res.message, res.type),
43819
- }
43820
- : res.type,
43822
+ response: {
43823
+ type: res.type,
43824
+ message: hdTransport.getSafeTransportLogPayload(res.message, res.type),
43825
+ },
43821
43826
  });
43822
43827
  }
43823
43828
  }
@@ -44238,12 +44243,20 @@ const parseProtocolV2BuildFingerprint = (buildFingerprint) => {
44238
44243
  }
44239
44244
  return { binary, version, commit, environment, buildType };
44240
44245
  };
44241
- const getProtocolV2RuntimeMode = (protocolInfo) => {
44242
- var _a;
44246
+ const getProtocolV2RuntimeMode = (protocolInfo, deviceInfo) => {
44247
+ var _a, _b, _c, _d;
44243
44248
  const binary = (_a = parseProtocolV2BuildFingerprint(protocolInfo.build_fingerprint)) === null || _a === void 0 ? void 0 : _a.binary;
44244
44249
  if (binary === 'application')
44245
44250
  return 'normal';
44246
- return binary;
44251
+ if (binary)
44252
+ return binary;
44253
+ if (isLegacyProtocolV2ProtocolInfo(protocolInfo) && !((_b = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _b === void 0 ? void 0 : _b.application)) {
44254
+ if ((_c = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _c === void 0 ? void 0 : _c.romloader)
44255
+ return 'romloader';
44256
+ if ((_d = deviceInfo === null || deviceInfo === void 0 ? void 0 : deviceInfo.fw) === null || _d === void 0 ? void 0 : _d.bootloader)
44257
+ return 'bootloader';
44258
+ }
44259
+ return undefined;
44247
44260
  };
44248
44261
  const PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE = 60602;
44249
44262
  const supportsProtocolV2Message = (protocolInfo, messageType) => protocolInfo.supported_messages.includes(messageType);
@@ -45245,6 +45258,7 @@ class Device extends events.exports {
45245
45258
  yield this.commands.dispose(false);
45246
45259
  }
45247
45260
  this.commands = new DeviceCommands(this, (_g = this.mainId) !== null && _g !== void 0 ? _g : '');
45261
+ this.invalidateProtocolV2RuntimeState();
45248
45262
  }
45249
45263
  catch (error) {
45250
45264
  if (options === null || options === void 0 ? void 0 : options.forceProtocolDetection) {
@@ -45639,10 +45653,7 @@ class Device extends events.exports {
45639
45653
  commands: this.commands,
45640
45654
  timeoutMs: options === null || options === void 0 ? void 0 : options.protocolV2DeviceInfoTimeoutMs,
45641
45655
  });
45642
- const features = (options === null || options === void 0 ? void 0 : options.allowLegacyProtocolV2ProtocolInfo)
45643
- ? yield this.probeProtocolV2RuntimeState(deviceInfo, options.protocolV2DeviceInfoTimeoutMs, { allowLegacyProtocolV2ProtocolInfo: true })
45644
- : yield this.probeProtocolV2RuntimeState(deviceInfo, options === null || options === void 0 ? void 0 : options.protocolV2DeviceInfoTimeoutMs);
45645
- Log$g.debug('Protocol V2 features:', features);
45656
+ yield this.probeProtocolV2RuntimeState(deviceInfo, options === null || options === void 0 ? void 0 : options.protocolV2DeviceInfoTimeoutMs);
45646
45657
  }
45647
45658
  catch (error) {
45648
45659
  Log$g.error('Protocol V2 initialization failed:', error);
@@ -45682,14 +45693,7 @@ class Device extends events.exports {
45682
45693
  commands: this.commands,
45683
45694
  request: getProtocolV2DeviceInfoRequest(),
45684
45695
  });
45685
- if (params.allowLegacyProtocolV2ProtocolInfo) {
45686
- yield this.probeProtocolV2RuntimeState(deviceInfo, undefined, {
45687
- allowLegacyProtocolV2ProtocolInfo: true,
45688
- });
45689
- }
45690
- else {
45691
- yield this.probeProtocolV2RuntimeState(deviceInfo);
45692
- }
45696
+ yield this.probeProtocolV2RuntimeState(deviceInfo);
45693
45697
  refreshedDeviceInfo = deviceInfo;
45694
45698
  initializedWithDeviceInfo = true;
45695
45699
  }
@@ -45720,9 +45724,9 @@ class Device extends events.exports {
45720
45724
  }
45721
45725
  if (refresh.has('status') && !initializedWithDeviceInfo) {
45722
45726
  const cachedMode = (_c = this.state) === null || _c === void 0 ? void 0 : _c.status.mode;
45723
- yield this.probeProtocolV2RuntimeState(refreshedDeviceInfo, undefined, Object.assign({ forceRuntimeContextRefresh: cachedMode === 'bootloader' || cachedMode === 'romloader' }, (params.allowLegacyProtocolV2ProtocolInfo
45724
- ? { allowLegacyProtocolV2ProtocolInfo: true }
45725
- : {})));
45727
+ yield this.probeProtocolV2RuntimeState(refreshedDeviceInfo, undefined, {
45728
+ forceRuntimeContextRefresh: cachedMode === 'bootloader' || cachedMode === 'romloader',
45729
+ });
45726
45730
  }
45727
45731
  if (refresh.has('settings') && ((_d = this.state) === null || _d === void 0 ? void 0 : _d.status.mode) === 'normal') {
45728
45732
  const { message } = yield this.commands.typedCall('DeviceSettingsGet', 'DeviceSettings', {});
@@ -45761,9 +45765,10 @@ class Device extends events.exports {
45761
45765
  source,
45762
45766
  changedKeys: result.changedKeys,
45763
45767
  };
45764
- Log$g.debug('Device state patch committed', {
45768
+ Log$g.debug('Device state updated', {
45765
45769
  source,
45766
- keys: result.changedKeys,
45770
+ revision: result.revision,
45771
+ changedKeyCount: result.changedKeys.length,
45767
45772
  });
45768
45773
  this.emit(DEVICE.STATE, this, event);
45769
45774
  if (result.state.protocol === 'V1') {
@@ -45785,13 +45790,6 @@ class Device extends events.exports {
45785
45790
  ensureProtocolV2RuntimeContext(timeoutMs, options) {
45786
45791
  var _a, _b, _c, _d;
45787
45792
  return __awaiter(this, void 0, void 0, function* () {
45788
- const assertProtocolInfoAllowed = (protocolInfo) => {
45789
- if (isLegacyProtocolV2ProtocolInfo(protocolInfo) &&
45790
- (options === null || options === void 0 ? void 0 : options.allowLegacyProtocolV2ProtocolInfo) !== true) {
45791
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, 'Legacy Protocol V2 ProtocolInfo is supported only during device discovery and firmware update.');
45792
- }
45793
- return protocolInfo;
45794
- };
45795
45793
  const cachedProtocolInfo = (options === null || options === void 0 ? void 0 : options.forceRefresh) === true
45796
45794
  ? undefined
45797
45795
  : (_a = this.protocolV2RuntimeContext) !== null && _a !== void 0 ? _a : (!this.protocolV2StateNeedsReload
@@ -45799,10 +45797,10 @@ class Device extends events.exports {
45799
45797
  : undefined);
45800
45798
  if (cachedProtocolInfo) {
45801
45799
  this.protocolV2RuntimeContext = cachedProtocolInfo;
45802
- return assertProtocolInfoAllowed(cachedProtocolInfo);
45800
+ return cachedProtocolInfo;
45803
45801
  }
45804
45802
  if (this.protocolV2RuntimeContextPromise) {
45805
- return assertProtocolInfoAllowed(yield this.protocolV2RuntimeContextPromise);
45803
+ return this.protocolV2RuntimeContextPromise;
45806
45804
  }
45807
45805
  const requestToken = {};
45808
45806
  const pendingRequest = (() => __awaiter(this, void 0, void 0, function* () {
@@ -45819,7 +45817,7 @@ class Device extends events.exports {
45819
45817
  this.protocolV2RuntimeContextRequestToken = requestToken;
45820
45818
  this.protocolV2RuntimeContextPromise = pendingRequest;
45821
45819
  try {
45822
- return assertProtocolInfoAllowed(yield pendingRequest);
45820
+ return yield pendingRequest;
45823
45821
  }
45824
45822
  finally {
45825
45823
  if (this.protocolV2RuntimeContextPromise === pendingRequest) {
@@ -45836,11 +45834,10 @@ class Device extends events.exports {
45836
45834
  return __awaiter(this, void 0, void 0, function* () {
45837
45835
  const protocolInfo = yield this.ensureProtocolV2RuntimeContext(timeoutMs, {
45838
45836
  forceRefresh: options === null || options === void 0 ? void 0 : options.forceRuntimeContextRefresh,
45839
- allowLegacyProtocolV2ProtocolInfo: options === null || options === void 0 ? void 0 : options.allowLegacyProtocolV2ProtocolInfo,
45840
45837
  });
45841
- const runtimeMode = getProtocolV2RuntimeMode(protocolInfo);
45842
- const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
45843
45838
  const runtimeDeviceInfo = deviceInfo !== null && deviceInfo !== void 0 ? deviceInfo : (_b = (_a = this.state) === null || _a === void 0 ? void 0 : _a.raw) === null || _b === void 0 ? void 0 : _b.protocolV2DeviceInfo;
45839
+ const runtimeMode = getProtocolV2RuntimeMode(protocolInfo, runtimeDeviceInfo);
45840
+ const legacyProtocolInfo = isLegacyProtocolV2ProtocolInfo(protocolInfo);
45844
45841
  const protocolV2DeviceType = runtimeDeviceInfo
45845
45842
  ? resolveProtocolV2DeviceIdentity((_c = runtimeDeviceInfo.hw) === null || _c === void 0 ? void 0 : _c.Device_type).deviceType
45846
45843
  : this.getCurrentDeviceType();
@@ -45898,8 +45895,7 @@ class Device extends events.exports {
45898
45895
  const previousStatus = (_d = (_c = this.state) === null || _c === void 0 ? void 0 : _c.raw) === null || _d === void 0 ? void 0 : _d.protocolV2DeviceStatus;
45899
45896
  return this.updateProtocolV2Features(previousDeviceInfo, Object.assign(Object.assign({}, previousStatus), status));
45900
45897
  }
45901
- markTransportDisconnected() {
45902
- this.deviceAcquired = false;
45898
+ invalidateProtocolV2RuntimeState() {
45903
45899
  if (!this.isProtocolV2())
45904
45900
  return;
45905
45901
  this.protocolV2StateNeedsReload = true;
@@ -45908,6 +45904,10 @@ class Device extends events.exports {
45908
45904
  this.protocolV2RuntimeContextRequestToken = undefined;
45909
45905
  this.clearPreInitialized();
45910
45906
  }
45907
+ markTransportDisconnected() {
45908
+ this.deviceAcquired = false;
45909
+ this.invalidateProtocolV2RuntimeState();
45910
+ }
45911
45911
  invalidateAfterWipe() {
45912
45912
  const deviceId = this.getCurrentDeviceId();
45913
45913
  if (deviceId) {
@@ -45917,10 +45917,7 @@ class Device extends events.exports {
45917
45917
  if (this.originalDescriptor.path !== deviceId) {
45918
45918
  deviceWalletSessionStore.deleteDevice(this.originalDescriptor.path);
45919
45919
  }
45920
- this.protocolV2StateNeedsReload = true;
45921
- this.protocolV2RuntimeContext = undefined;
45922
- this.protocolV2RuntimeContextPromise = undefined;
45923
- this.protocolV2RuntimeContextRequestToken = undefined;
45920
+ this.invalidateProtocolV2RuntimeState();
45924
45921
  }
45925
45922
  this.passphraseState = undefined;
45926
45923
  this.stateStore = new DeviceStateStore();
@@ -45930,11 +45927,7 @@ class Device extends events.exports {
45930
45927
  markProtocolV2Reboot(rebootType) {
45931
45928
  if (!this.isProtocolV2())
45932
45929
  return;
45933
- this.protocolV2StateNeedsReload = true;
45934
- this.protocolV2RuntimeContext = undefined;
45935
- this.protocolV2RuntimeContextPromise = undefined;
45936
- this.protocolV2RuntimeContextRequestToken = undefined;
45937
- this.clearPreInitialized();
45930
+ this.invalidateProtocolV2RuntimeState();
45938
45931
  let loaderMode;
45939
45932
  if (rebootType === hdTransport.DeviceRebootType.Bootloader) {
45940
45933
  loaderMode = 'bootloader';
@@ -45990,6 +45983,7 @@ class Device extends events.exports {
45990
45983
  if (device.features) {
45991
45984
  this._updateFeatures(device.features);
45992
45985
  }
45986
+ this.invalidateProtocolV2RuntimeState();
45993
45987
  }
45994
45988
  run(fn, options) {
45995
45989
  return __awaiter(this, void 0, void 0, function* () {
@@ -46102,7 +46096,6 @@ class Device extends events.exports {
46102
46096
  var _a, _b;
46103
46097
  return __awaiter(this, void 0, void 0, function* () {
46104
46098
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromUser);
46105
- this.markTransportDisconnected();
46106
46099
  yield ((_a = this.cancelableAction) === null || _a === void 0 ? void 0 : _a.call(this, error));
46107
46100
  yield ((_b = this.commands) === null || _b === void 0 ? void 0 : _b.cancel());
46108
46101
  if (this.runPromise) {
@@ -46857,7 +46850,6 @@ class SearchDevices extends BaseMethod {
46857
46850
  connectProtocol: undefined,
46858
46851
  forceProtocolDetection: true,
46859
46852
  refreshRuntimeState: true,
46860
- allowLegacyProtocolV2ProtocolInfo: true,
46861
46853
  });
46862
46854
  deviceList.push(...result.deviceList);
46863
46855
  }
@@ -46941,7 +46933,9 @@ class GetDeviceState extends BaseMethod {
46941
46933
  }
46942
46934
  run() {
46943
46935
  return __awaiter(this, void 0, void 0, function* () {
46944
- const state = yield this.device.getDeviceState(Object.assign({ refreshSections: SCOPE_SECTIONS[this.params.scope] }, (this.params.scope === 'firmware' ? { allowLegacyProtocolV2ProtocolInfo: true } : {})));
46936
+ const state = yield this.device.getDeviceState({
46937
+ refreshSections: SCOPE_SECTIONS[this.params.scope],
46938
+ });
46945
46939
  if (this.params.scope === 'settings' &&
46946
46940
  this.device.isProtocolV2() &&
46947
46941
  isLoaderMode(state.status.mode)) {
@@ -47480,7 +47474,6 @@ function loadProtocolV2FirmwareReleaseContext({ device, firmwareType: firmwareTy
47480
47474
  refreshSections: checkFirmwareHash
47481
47475
  ? ['identity', 'versions', 'verification']
47482
47476
  : ['identity', 'versions'],
47483
- allowLegacyProtocolV2ProtocolInfo: true,
47484
47477
  });
47485
47478
  if (state.identity.deviceType !== 'pro2' && state.identity.deviceType !== 'neo') {
47486
47479
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportMethod, `${methodName} requires a Pro2 or Neo device for Protocol V2`);
@@ -51838,6 +51831,16 @@ const isProtocolV2ReconnectProbeError = (error) => {
51838
51831
  return ((message.includes('device protocol mismatch') && message.includes('expected v2')) ||
51839
51832
  message.includes('did not respond to expected protocol'));
51840
51833
  };
51834
+ const isProtocolV2BleTransportReleasedError = (error) => {
51835
+ const message = getProtocolV2UnknownErrorText(error).toLowerCase();
51836
+ const compactMessage = message.replace(/\s+/gu, '');
51837
+ return (message.includes('react native ble transport released') ||
51838
+ message.includes('bledevicedisconnected') ||
51839
+ message.includes('bleconnectederror') ||
51840
+ (compactMessage.includes('rxerrorerror6') &&
51841
+ (compactMessage.includes('multiplatformbleadapter') ||
51842
+ compactMessage.includes('multipalformebleadapter'))));
51843
+ };
51841
51844
  const isProtocolV2FirmwareStatusEndpointUnavailable = (error) => {
51842
51845
  const message = getProtocolV2UnknownErrorText(error).toLowerCase();
51843
51846
  return (message.includes('handler not registered') ||
@@ -51984,6 +51987,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51984
51987
  this.protocolV2BootResourceStagingSafe = false;
51985
51988
  this.protocolV2CompletedTargetVersions = new Map();
51986
51989
  this.protocolV2FinalStatusVerified = false;
51990
+ this.protocolV2InstallAckReceived = false;
51991
+ this.protocolV2InstallBaselineVersions = new Map();
51987
51992
  }
51988
51993
  getSupportedProtocols() {
51989
51994
  return ['V2'];
@@ -52161,6 +52166,9 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52161
52166
  return __awaiter(this, void 0, void 0, function* () {
52162
52167
  yield this.captureProtocolV2PhysicalIdentity();
52163
52168
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
52169
+ this.protocolV2InstallBaselineVersions =
52170
+ this.getProtocolV2ObservableTargetVersions(deviceFeatures);
52171
+ this.protocolV2LastRuntimeProbeFeatures = undefined;
52164
52172
  const currentDeviceType = this.device.getCurrentDeviceType();
52165
52173
  const capabilityDeviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
52166
52174
  ? currentDeviceType
@@ -52169,9 +52177,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52169
52177
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
52170
52178
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
52171
52179
  this.validateExpectedTargetVersions();
52180
+ const wantsResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'));
52172
52181
  if (!this.params.preparedPlan &&
52173
52182
  this.params.resourceArchiveBinary &&
52174
- ((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('resource'))) {
52183
+ ((_c = this.params.targetsToUpdate) === null || _c === void 0 ? void 0 : _c.includes('resource'))) {
52175
52184
  const localMemoryHost = yield this.prepareProtocolV2LocalMemoryHost({
52176
52185
  features: deviceFeatures,
52177
52186
  firmwareType,
@@ -52183,14 +52192,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52183
52192
  localMemoryHost.release();
52184
52193
  }
52185
52194
  }
52186
- const hasPreparedComponentArtifacts = Object.values((_c = this.params.componentArtifacts) !== null && _c !== void 0 ? _c : {}).some(Boolean);
52195
+ const hasPreparedComponentArtifacts = Object.values((_d = this.params.componentArtifacts) !== null && _d !== void 0 ? _d : {}).some(Boolean);
52187
52196
  if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
52188
52197
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
52189
52198
  }
52190
- const wantsResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
52191
52199
  let fwBinaryMap = [];
52192
52200
  let bootloaderBinary = null;
52193
52201
  let installItems;
52202
+ let resourceMemoryHost;
52194
52203
  try {
52195
52204
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
52196
52205
  fwBinaryMap = this.collectExplicitTargetBinaries();
@@ -52203,20 +52212,19 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52203
52212
  const needsRemoteFirmware = ((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.length)
52204
52213
  ? missingFirmwareTargets.length > 0
52205
52214
  : explicitInstallItems.length === 0;
52206
- if (wantsResources) {
52207
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive must be provided through a local or external PreparedPlan', {
52208
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
52209
- });
52210
- }
52211
- if (needsRemoteFirmware &&
52215
+ const needsSdkManagedArtifacts = needsRemoteFirmware || wantsResources;
52216
+ if (needsSdkManagedArtifacts &&
52212
52217
  (this.params.artifactReader ||
52213
52218
  DataManager.getSettings('firmwareManifestMode') === 'external-only')) {
52214
52219
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware artifacts must be prepared by the external firmware host', {
52215
52220
  firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
52216
52221
  });
52217
52222
  }
52218
- if (needsRemoteFirmware) {
52219
- yield DataManager.forceReloadData();
52223
+ if (needsSdkManagedArtifacts) {
52224
+ yield DataManager.forceReloadData({
52225
+ requireResources: wantsResources,
52226
+ resourceDeviceType: capabilityDeviceType === hdShared.EDeviceType.Neo ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2,
52227
+ });
52220
52228
  }
52221
52229
  if (needsRemoteFirmware) {
52222
52230
  const remoteBinaries = yield this.prepareRemoteProtocolV2Binaries(firmwareType, deviceFeatures, explicitInstallItems);
@@ -52236,9 +52244,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52236
52244
  targetId: item.targetId,
52237
52245
  }));
52238
52246
  }
52247
+ if (wantsResources) {
52248
+ this.params.resourceArchiveBinary = yield this.downloadRemoteProtocolV2ResourceArchive(deviceFeatures);
52249
+ resourceMemoryHost = yield this.prepareProtocolV2LocalMemoryHost({
52250
+ features: deviceFeatures,
52251
+ firmwareType,
52252
+ availableInstallItems: installItems !== null && installItems !== void 0 ? installItems : explicitInstallItems,
52253
+ });
52254
+ }
52239
52255
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
52240
52256
  }
52241
52257
  catch (err) {
52258
+ resourceMemoryHost === null || resourceMemoryHost === void 0 ? void 0 : resourceMemoryHost.release();
52242
52259
  if (typeof err === 'object' &&
52243
52260
  err !== null &&
52244
52261
  'params' in err &&
@@ -52250,6 +52267,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52250
52267
  }
52251
52268
  throw normalizeFirmwarePreparationError(err);
52252
52269
  }
52270
+ if (resourceMemoryHost) {
52271
+ try {
52272
+ return yield this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType, false);
52273
+ }
52274
+ finally {
52275
+ resourceMemoryHost.release();
52276
+ }
52277
+ }
52253
52278
  if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
52254
52279
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
52255
52280
  }
@@ -52349,13 +52374,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52349
52374
  return installSources;
52350
52375
  });
52351
52376
  }
52352
- prepareProtocolV2LocalMemoryHost({ features, firmwareType, }) {
52377
+ prepareProtocolV2LocalMemoryHost({ features, firmwareType, availableInstallItems = this.buildProtocolV2InstallItems({
52378
+ bootloaderBinary: this.prepareBootloaderBinary(),
52379
+ fwBinaryMap: this.collectExplicitTargetBinaries(),
52380
+ }), }) {
52353
52381
  var _a, _b;
52354
52382
  return __awaiter(this, void 0, void 0, function* () {
52355
- const availableInstallItems = this.buildProtocolV2InstallItems({
52356
- bootloaderBinary: this.prepareBootloaderBinary(),
52357
- fwBinaryMap: this.collectExplicitTargetBinaries(),
52358
- });
52359
52383
  const requestedComponentTargets = new Set(((_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter((target) => target !== 'resource' && target !== 'boot_resources'));
52360
52384
  const localComponentTargets = new Set(availableInstallItems.flatMap(item => {
52361
52385
  const target = PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(item.targetId);
@@ -52632,16 +52656,20 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52632
52656
  return sources;
52633
52657
  });
52634
52658
  }
52635
- runProtocolV2PreparedArtifacts(features, firmwareType) {
52659
+ runProtocolV2PreparedArtifacts(features, firmwareType, announceDownload = true) {
52636
52660
  return __awaiter(this, void 0, void 0, function* () {
52637
52661
  try {
52638
- this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
52662
+ if (announceDownload) {
52663
+ this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
52664
+ }
52639
52665
  const installSources = yield this.prepareProtocolV2InstallSources(firmwareType, features);
52640
52666
  const resourceSources = yield this.prepareProtocolV2ResourceSources();
52641
52667
  if (installSources.length === 0 && resourceSources.length === 0) {
52642
52668
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
52643
52669
  }
52644
- this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
52670
+ if (announceDownload) {
52671
+ this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
52672
+ }
52645
52673
  return yield this.executeProtocolV2SourceUpdate({
52646
52674
  installSources,
52647
52675
  resourceSources,
@@ -52927,6 +52955,30 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52927
52955
  return Object.assign(Object.assign({}, target), { binary });
52928
52956
  });
52929
52957
  }
52958
+ downloadRemoteProtocolV2ResourceArchive(features) {
52959
+ return __awaiter(this, void 0, void 0, function* () {
52960
+ const deviceType = getDeviceType(features);
52961
+ if (deviceType !== hdShared.EDeviceType.Pro2 && deviceType !== hdShared.EDeviceType.Neo) {
52962
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive requires a Pro2 or Neo device');
52963
+ }
52964
+ const source = DataManager.getProtocolV2ResourceSource(deviceType);
52965
+ const expectedSha256 = normalizeProtocolV2Hex(source === null || source === void 0 ? void 0 : source.archiveSha256);
52966
+ if (!(source === null || source === void 0 ? void 0 : source.archiveUrl) ||
52967
+ !Number.isSafeInteger(source.archiveSize) ||
52968
+ source.archiveSize <= 0 ||
52969
+ source.archiveSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES ||
52970
+ !expectedSha256 ||
52971
+ !/^[0-9a-f]{64}$/u.test(expectedSha256)) {
52972
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive integrity metadata is invalid', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
52973
+ }
52974
+ const { binary } = yield getSysResourceBinary(source.archiveUrl);
52975
+ if (binary.byteLength !== source.archiveSize ||
52976
+ bytesToHex(sha256.sha256(new Uint8Array(binary))) !== expectedSha256) {
52977
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive does not match the remote config', { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
52978
+ }
52979
+ return binary;
52980
+ });
52981
+ }
52930
52982
  prepareRemoteProtocolV2Binaries(firmwareType, features, explicitInstallItems = []) {
52931
52983
  var _a, _b;
52932
52984
  return __awaiter(this, void 0, void 0, function* () {
@@ -53146,7 +53198,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53146
53198
  timeoutMs: this.getProtocolV2DeviceInfoTimeout(),
53147
53199
  });
53148
53200
  this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
53149
- const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT, { allowLegacyProtocolV2ProtocolInfo: true });
53201
+ const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT);
53150
53202
  if ((features === null || features === void 0 ? void 0 : features.mode) === 'bootloader') {
53151
53203
  return features;
53152
53204
  }
@@ -53183,81 +53235,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53183
53235
  push(this.params.se04Binary, 'se04.bin', ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04);
53184
53236
  return entries;
53185
53237
  }
53186
- buildProtocolV2ExecutionPhases({ installSources, resourceSources, }) {
53187
- const phases = [];
53188
- const bootResourceSources = resourceSources.filter(source => isProtocolV2BootResourcePackagePath(source.devicePath));
53189
- const remainingResourceSources = resourceSources.filter(source => !isProtocolV2BootResourcePackagePath(source.devicePath));
53190
- if (bootResourceSources.length > 0) {
53191
- phases.push({
53192
- kind: 'resource-sync',
53193
- installSources: [],
53194
- resourceSources: bootResourceSources,
53195
- });
53196
- }
53197
- const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
53198
- if (bootloaderSources.length > 0) {
53199
- phases.push({
53200
- kind: 'bootloader-install',
53201
- installSources: bootloaderSources,
53202
- resourceSources: [],
53203
- }, {
53204
- kind: 'bootloader-verify',
53205
- installSources: [],
53206
- resourceSources: [],
53207
- });
53208
- }
53209
- if (remainingResourceSources.length > 0) {
53210
- phases.push({
53211
- kind: 'resource-sync',
53212
- installSources: [],
53213
- resourceSources: remainingResourceSources,
53214
- });
53215
- }
53216
- const componentSources = installSources.filter(source => source.kind !== 'bootloader');
53217
- if (componentSources.length > 0) {
53218
- phases.push({
53219
- kind: 'component-install',
53220
- installSources: componentSources,
53221
- resourceSources: [],
53222
- });
53223
- }
53224
- phases.push({
53225
- kind: 'final-verify',
53226
- installSources: [],
53227
- resourceSources: [],
53228
- });
53229
- return phases;
53230
- }
53231
- executeProtocolV2Phases({ installSources, resourceSources, }) {
53238
+ executeProtocolV2SourceUpdate({ installSources, resourceSources, }) {
53232
53239
  return __awaiter(this, void 0, void 0, function* () {
53233
53240
  this.protocolV2BootResourceStagingSafe = false;
53234
- const phases = this.buildProtocolV2ExecutionPhases({
53235
- installSources,
53236
- resourceSources,
53237
- });
53238
- for (const phase of phases) {
53239
- if (phase.kind === 'final-verify') {
53240
- return this.completeProtocolV2FinalVerification();
53241
- }
53242
- if (phase.kind === 'resource-sync') {
53243
- yield this.enterProtocolV2BootloaderMode();
53244
- if (!phase.resourceSources.some(source => isProtocolV2BootResourcePackagePath(source.devicePath))) {
53245
- yield this.ensureProtocolV2BootResourceStagingIsEmpty();
53246
- }
53247
- yield this.executeProtocolV2TransferPhase(phase);
53248
- }
53249
- else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
53250
- yield this.enterProtocolV2BootloaderMode();
53251
- yield this.ensureProtocolV2BootResourceStagingIsEmpty();
53252
- yield this.executeProtocolV2TransferPhase(phase);
53253
- yield this.exitProtocolV2BootloaderToNormal();
53254
- }
53255
- else if (phase.kind === 'bootloader-verify') {
53256
- yield this.waitForProtocolV2FinalFeatures();
53257
- this.assertExpectedProtocolV2Versions(['boot']);
53258
- }
53241
+ if (installSources.length > 0 || resourceSources.length > 0) {
53242
+ yield this.enterProtocolV2BootloaderMode();
53243
+ yield this.ensureProtocolV2BootResourceStagingIsEmpty();
53244
+ yield this.executeProtocolV2TransferPhase({
53245
+ installSources,
53246
+ resourceSources,
53247
+ });
53259
53248
  }
53260
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 execution has no final verification phase');
53249
+ return this.completeProtocolV2FinalVerification();
53261
53250
  });
53262
53251
  }
53263
53252
  ensureProtocolV2BootResourceStagingIsEmpty() {
@@ -53285,14 +53274,6 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53285
53274
  this.protocolV2BootResourceStagingSafe = true;
53286
53275
  });
53287
53276
  }
53288
- executeProtocolV2SourceUpdate({ installSources, resourceSources, }) {
53289
- return __awaiter(this, void 0, void 0, function* () {
53290
- return this.executeProtocolV2Phases({
53291
- installSources,
53292
- resourceSources,
53293
- });
53294
- });
53295
- }
53296
53277
  executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
53297
53278
  return __awaiter(this, void 0, void 0, function* () {
53298
53279
  const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
@@ -53308,7 +53289,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53308
53289
  kind: item.kind,
53309
53290
  });
53310
53291
  })));
53311
- return yield this.executeProtocolV2Phases({
53292
+ return yield this.executeProtocolV2SourceUpdate({
53312
53293
  installSources,
53313
53294
  resourceSources: [],
53314
53295
  });
@@ -53509,6 +53490,37 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53509
53490
  });
53510
53491
  return Array.from(expectedTargetIds).filter(targetId => !reportedTargetIds.has(targetId));
53511
53492
  }
53493
+ getProtocolV2ObservableTargetVersions(features) {
53494
+ const versions = new Map();
53495
+ versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, getDeviceBootloaderVersion(features).join('.'));
53496
+ const applicationVersion = getDeviceFirmwareVersion(features).join('.');
53497
+ versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, applicationVersion);
53498
+ versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2, applicationVersion);
53499
+ versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR, getDeviceBLEFirmwareVersion(features).join('.'));
53500
+ const secureElementVersions = [
53501
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01, features.se01Version],
53502
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02, features.se02Version],
53503
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, features.se03Version],
53504
+ [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, features.se04Version],
53505
+ ];
53506
+ secureElementVersions.forEach(([targetId, version]) => {
53507
+ if (version)
53508
+ versions.set(targetId, version);
53509
+ });
53510
+ return versions;
53511
+ }
53512
+ hasProtocolV2InstallVersionChanged(expectedTargetIds) {
53513
+ if (!this.protocolV2LastRuntimeProbeFeatures)
53514
+ return false;
53515
+ const currentVersions = this.getProtocolV2ObservableTargetVersions(this.protocolV2LastRuntimeProbeFeatures);
53516
+ return Array.from(expectedTargetIds).some(targetId => {
53517
+ const previousVersion = this.protocolV2InstallBaselineVersions.get(targetId);
53518
+ const currentVersion = currentVersions.get(targetId);
53519
+ return (previousVersion !== undefined &&
53520
+ currentVersion !== undefined &&
53521
+ previousVersion !== currentVersion);
53522
+ });
53523
+ }
53512
53524
  waitForProtocolV2FirmwareUpdateComplete(targets) {
53513
53525
  var _a, _b;
53514
53526
  return __awaiter(this, void 0, void 0, function* () {
@@ -53521,11 +53533,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53521
53533
  let deviceInfo;
53522
53534
  let missingTargetStatusSince;
53523
53535
  let missingTargetStatusKey;
53536
+ let normalModeWithoutInstallEvidenceSince;
53537
+ let installEvidenceObserved = this.protocolV2InstallAckReceived;
53524
53538
  const resetMissingTargetStatusGrace = () => {
53525
53539
  missingTargetStatusSince = undefined;
53526
53540
  missingTargetStatusKey = undefined;
53527
53541
  };
53528
53542
  while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
53543
+ this.throwIfAborted();
53529
53544
  try {
53530
53545
  if (shouldReconnect) {
53531
53546
  yield this.reconnectProtocolV2Device();
@@ -53542,16 +53557,26 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53542
53557
  },
53543
53558
  }, { timeoutMs: PROTOCOL_V2_FIRMWARE_STATUS_RESPONSE_TIMEOUT });
53544
53559
  const statusTargets = ((_a = statusResponse.message.records) !== null && _a !== void 0 ? _a : []);
53560
+ if (statusTargets.some(target => {
53561
+ const targetId = normalizeProtocolV2TargetId(target.target_id);
53562
+ return targetId !== undefined && expectedTargetIds.has(targetId);
53563
+ })) {
53564
+ installEvidenceObserved = true;
53565
+ normalModeWithoutInstallEvidenceSince = undefined;
53566
+ }
53545
53567
  if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths)) {
53546
53568
  this.protocolV2FinalStatusVerified = true;
53547
53569
  return;
53548
53570
  }
53549
- if (statusTargets.length === 0 &&
53550
- currentDeviceInfo &&
53551
- (yield this.probeProtocolV2NormalMode(currentDeviceInfo))) {
53552
- Log$6.log('[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete');
53553
- this.postProgressMessage(100, 'installingFirmware');
53554
- return;
53571
+ if (statusTargets.length === 0 && currentDeviceInfo) {
53572
+ const isNormalMode = yield this.probeProtocolV2NormalMode(currentDeviceInfo);
53573
+ if (isNormalMode &&
53574
+ (installEvidenceObserved ||
53575
+ this.hasProtocolV2InstallVersionChanged(expectedTargetIds))) {
53576
+ Log$6.log('[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete');
53577
+ this.postProgressMessage(100, 'installingFirmware');
53578
+ return;
53579
+ }
53555
53580
  }
53556
53581
  const missingTargetIds = this.getProtocolV2MissingTargetIds(statusTargets, expectedTargetIds);
53557
53582
  if (missingTargetIds.length > 0) {
@@ -53584,12 +53609,27 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53584
53609
  if (!currentDeviceInfo) {
53585
53610
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 device identity is unavailable during install polling');
53586
53611
  }
53587
- if (yield this.probeProtocolV2NormalMode(currentDeviceInfo)) {
53612
+ const isNormalMode = yield this.probeProtocolV2NormalMode(currentDeviceInfo);
53613
+ if (isNormalMode &&
53614
+ (installEvidenceObserved ||
53615
+ this.hasProtocolV2InstallVersionChanged(expectedTargetIds))) {
53588
53616
  Log$6.log('[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot');
53589
53617
  this.postProgressMessage(100, 'installingFirmware');
53590
53618
  return;
53591
53619
  }
53592
- lastError = new Error('Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode');
53620
+ if (isNormalMode) {
53621
+ const now = Date.now();
53622
+ normalModeWithoutInstallEvidenceSince !== null && normalModeWithoutInstallEvidenceSince !== void 0 ? normalModeWithoutInstallEvidenceSince : (normalModeWithoutInstallEvidenceSince = now);
53623
+ if (now - normalModeWithoutInstallEvidenceSince >=
53624
+ PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT) {
53625
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareError, 'Protocol V2 device returned to normal mode without install ACK, target status, or version change');
53626
+ }
53627
+ lastError = new Error('Protocol V2 device is in normal mode but installation is not yet confirmed');
53628
+ }
53629
+ else {
53630
+ normalModeWithoutInstallEvidenceSince = undefined;
53631
+ lastError = new Error('Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode');
53632
+ }
53593
53633
  }
53594
53634
  else {
53595
53635
  shouldReconnect = true;
@@ -53640,7 +53680,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53640
53680
  }
53641
53681
  probeProtocolV2NormalMode(deviceInfo) {
53642
53682
  return __awaiter(this, void 0, void 0, function* () {
53643
- const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT, { allowLegacyProtocolV2ProtocolInfo: true });
53683
+ const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT);
53684
+ this.protocolV2LastRuntimeProbeFeatures = features;
53644
53685
  return features.mode === 'normal' && !features.bootloaderMode;
53645
53686
  });
53646
53687
  }
@@ -53693,7 +53734,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53693
53734
  request: PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
53694
53735
  });
53695
53736
  this.assertProtocolV2DeviceInfoIdentity(deviceInfo);
53696
- const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT, { allowLegacyProtocolV2ProtocolInfo: true });
53737
+ const features = yield this.device.probeProtocolV2RuntimeState(deviceInfo, PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT);
53697
53738
  if (features.mode === 'normal' && !features.bootloaderMode) {
53698
53739
  return features;
53699
53740
  }
@@ -53819,22 +53860,41 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
53819
53860
  }
53820
53861
  protocolV2StartFirmwareUpdate({ targets, }) {
53821
53862
  return __awaiter(this, void 0, void 0, function* () {
53863
+ this.protocolV2InstallAckReceived = false;
53864
+ this.protocolV2LastRuntimeProbeFeatures = undefined;
53822
53865
  const startUpdate = () => this.device
53823
53866
  .getCommands()
53824
53867
  .typedCall('DeviceFirmwareUpdateRequest', 'Success', { targets }, { timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT });
53825
53868
  let response;
53826
53869
  try {
53827
53870
  response = yield startUpdate();
53871
+ this.protocolV2InstallAckReceived = true;
53828
53872
  }
53829
53873
  catch (error) {
53830
- if (!this.protocolV2LegacyDirectUpdate ||
53831
- !isProtocolV2FirmwareUpdateEndpointUnavailable(error)) {
53874
+ if (this.isBleReconnect() && isProtocolV2BleTransportReleasedError(error)) {
53875
+ this.throwIfAborted();
53876
+ Log$6.log('[FirmwareUpdateV4] install request interrupted by device reboot; continue status polling: ', error);
53877
+ }
53878
+ else if (this.protocolV2LegacyDirectUpdate &&
53879
+ isProtocolV2FirmwareUpdateEndpointUnavailable(error)) {
53880
+ this.protocolV2LegacyDirectUpdate = false;
53881
+ Log$6.debug('[FirmwareUpdateV4] legacy App does not expose DeviceFirmwareUpdateRequest; rebooting to bootloader');
53882
+ yield this.rebootProtocolV2ToBootloader();
53883
+ try {
53884
+ response = yield startUpdate();
53885
+ this.protocolV2InstallAckReceived = true;
53886
+ }
53887
+ catch (retryError) {
53888
+ if (!(this.isBleReconnect() && isProtocolV2BleTransportReleasedError(retryError))) {
53889
+ throw retryError;
53890
+ }
53891
+ this.throwIfAborted();
53892
+ Log$6.log('[FirmwareUpdateV4] install request interrupted after legacy reboot; continue status polling: ', retryError);
53893
+ }
53894
+ }
53895
+ else {
53832
53896
  throw error;
53833
53897
  }
53834
- this.protocolV2LegacyDirectUpdate = false;
53835
- Log$6.debug('[FirmwareUpdateV4] legacy App does not expose DeviceFirmwareUpdateRequest; rebooting to bootloader');
53836
- yield this.rebootProtocolV2ToBootloader();
53837
- response = yield startUpdate();
53838
53898
  }
53839
53899
  this.protocolV2LegacyDirectUpdate = false;
53840
53900
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FirmwareUpdating);
@@ -64922,10 +64982,6 @@ const createUiProgressMessageFilter = (intervalMs = DEFAULT_UI_PROGRESS_INTERVAL
64922
64982
  };
64923
64983
  };
64924
64984
 
64925
- const isLegacyProtocolV2FirmwareRecoveryMethod = (method) => (method === null || method === void 0 ? void 0 : method.name) === 'firmwareUpdateV4' ||
64926
- (method === null || method === void 0 ? void 0 : method.name) === 'checkAllFirmwareRelease' ||
64927
- ((method === null || method === void 0 ? void 0 : method.name) === 'getDeviceState' && method.payload.scope === 'firmware');
64928
-
64929
64985
  const Log = getLogger(exports.LoggerNames.Core);
64930
64986
  const PRE_INITIALIZE_TTL_MS = 60 * 1000;
64931
64987
  const preWarmInflight = new Map();
@@ -64940,9 +64996,15 @@ function hasDeriveCardano(method) {
64940
64996
  }
64941
64997
  return method.name.startsWith('cardano') || ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.deriveCardano);
64942
64998
  }
64943
- const parseInitOptions = (method) => (Object.assign({ initSession: method === null || method === void 0 ? void 0 : method.payload.initSession, passphraseState: (method === null || method === void 0 ? void 0 : method.payload.useEmptyPassphrase) ? undefined : method === null || method === void 0 ? void 0 : method.payload.passphraseState, deviceId: method === null || method === void 0 ? void 0 : method.payload.deviceId, deriveCardano: method && hasDeriveCardano(method), connectProtocol: method === null || method === void 0 ? void 0 : method.payload.connectProtocol, forceProtocolDetection: method === null || method === void 0 ? void 0 : method.payload.forceProtocolDetection, protocolV2DeviceInfoTimeoutMs: method === null || method === void 0 ? void 0 : method.payload.protocolV2DeviceInfoTimeoutMs }, (isLegacyProtocolV2FirmwareRecoveryMethod(method)
64944
- ? { allowLegacyProtocolV2ProtocolInfo: true }
64945
- : {})));
64999
+ const parseInitOptions = (method) => ({
65000
+ initSession: method === null || method === void 0 ? void 0 : method.payload.initSession,
65001
+ passphraseState: (method === null || method === void 0 ? void 0 : method.payload.useEmptyPassphrase) ? undefined : method === null || method === void 0 ? void 0 : method.payload.passphraseState,
65002
+ deviceId: method === null || method === void 0 ? void 0 : method.payload.deviceId,
65003
+ deriveCardano: method && hasDeriveCardano(method),
65004
+ connectProtocol: method === null || method === void 0 ? void 0 : method.payload.connectProtocol,
65005
+ forceProtocolDetection: method === null || method === void 0 ? void 0 : method.payload.forceProtocolDetection,
65006
+ protocolV2DeviceInfoTimeoutMs: method === null || method === void 0 ? void 0 : method.payload.protocolV2DeviceInfoTimeoutMs,
65007
+ });
64946
65008
  let _core;
64947
65009
  let _deviceList;
64948
65010
  let _connector;
@@ -64966,6 +65028,7 @@ const toError = (error) => {
64966
65028
  return new Error(String(error));
64967
65029
  }
64968
65030
  };
65031
+ const isExpectedCompatibilityError = (error) => error instanceof hdShared.HardwareError && error.errorCode === hdShared.HardwareErrorCode.DeviceNotSupportMethod;
64969
65032
  const updateMethodRequestContext = (method, updates) => {
64970
65033
  if (method.requestContext) {
64971
65034
  updateRequestContext(method.requestContext.responseID, updates);
@@ -65339,7 +65402,9 @@ const onCallDevice = (context, message, method) => __awaiter(void 0, void 0, voi
65339
65402
  return yield task.callPromise.promise;
65340
65403
  }
65341
65404
  catch (e) {
65342
- Log.debug('Device Run Error: ', e);
65405
+ if (!isExpectedCompatibilityError(e)) {
65406
+ Log.debug('Device Run Error: ', e);
65407
+ }
65343
65408
  completeMethodRequestContext(method, e);
65344
65409
  return createResponseMessage(method.responseID, false, { error: e });
65345
65410
  }
@@ -65768,7 +65833,6 @@ const cleanup = () => {
65768
65833
  const pendingUiPromises = _uiPromises;
65769
65834
  _uiPromises = [];
65770
65835
  rejectUiPromises(pendingUiPromises, hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.ActionCancelled, 'UI request was cancelled'));
65771
- Log.debug('Cleanup...');
65772
65836
  };
65773
65837
  const removeDeviceListener = (device) => {
65774
65838
  device.removeAllListeners();