@onekeyfe/hwk-ledger-adapter 1.1.26 → 1.1.27-alpha.30

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.
package/dist/index.js CHANGED
@@ -39,12 +39,13 @@ __export(index_exports, {
39
39
  SignerEth: () => SignerEth,
40
40
  SignerManager: () => SignerManager,
41
41
  SignerSol: () => SignerSol,
42
- debugLog: () => debugLog,
43
42
  deviceActionToPromise: () => deviceActionToPromise,
43
+ extractBleHexId: () => extractBleHexId,
44
44
  isDeviceLockedError: () => isDeviceLockedError,
45
45
  isLedgerBleConnectionType: () => isLedgerBleConnectionType,
46
46
  isLedgerBleDescriptor: () => isLedgerBleDescriptor,
47
47
  isLedgerDmkBleTransport: () => isLedgerDmkBleTransport,
48
+ isValidLedgerBleConnectId: () => isValidLedgerBleConnectId,
48
49
  ledgerFailure: () => ledgerFailure,
49
50
  mapLedgerError: () => mapLedgerError,
50
51
  offSdkEvent: () => offSdkEvent,
@@ -68,7 +69,7 @@ var LOCKED_ERROR_CODES = /* @__PURE__ */ new Set(["5515", "21781", "6982", "2701
68
69
  var USER_REJECTED_CODES = /* @__PURE__ */ new Set(["6985", "27013"]);
69
70
  var WRONG_APP_CODES = /* @__PURE__ */ new Set(["6e00", "28160", "6d00", "27904", "6a83", "27267"]);
70
71
  var APP_NOT_INSTALLED_CODES = /* @__PURE__ */ new Set(["6807", "26631"]);
71
- var STEP_BLIND_SIGN_TRANSACTION_FALLBACK = "signer.eth.steps.blindSignTransactionFallback";
72
+ var STEP_BLIND_SIGN_FALLBACK = "signer.eth.steps.blindSignTransactionFallback";
72
73
  function getEthAppErrorCode(err) {
73
74
  if (!err || typeof err !== "object") return null;
74
75
  const e = err;
@@ -133,8 +134,13 @@ function mapBtcAppError(hex) {
133
134
  return null;
134
135
  }
135
136
  }
136
- function mapEthAppErrorCode(ethCode) {
137
+ function mapEthAppError(ethCode, lastStep) {
137
138
  switch (ethCode) {
139
+ case "6a80":
140
+ if (lastStep === STEP_BLIND_SIGN_FALLBACK) {
141
+ return import_hwk_adapter_core.HardwareErrorCode.EvmBlindSigningRequired;
142
+ }
143
+ return null;
138
144
  case "6984":
139
145
  return import_hwk_adapter_core.HardwareErrorCode.EvmClearSignPluginMissing;
140
146
  case "6a84":
@@ -147,20 +153,10 @@ function mapEthAppErrorCode(ethCode) {
147
153
  return null;
148
154
  }
149
155
  }
150
- function classifyEthAppError(err) {
151
- const ethCode = getEthAppErrorCode(err);
152
- if (!ethCode) return null;
153
- if (ethCode === "6a80") {
154
- return hasBlindSignFallbackStep(err) ? import_hwk_adapter_core.HardwareErrorCode.EvmBlindSigningRequired : null;
155
- }
156
- return mapEthAppErrorCode(ethCode);
157
- }
158
156
  var ERROR_TAG = {
159
157
  // SDK-mint
160
158
  DeviceNotAdvertising: "DeviceNotAdvertisingError",
161
159
  // BLE scan miss
162
- DeviceNotInDiscoveryCache: "DeviceNotInDiscoveryCacheError",
163
- // dm.connect() before enumerate
164
160
  BlePairingTimeout: "BlePairingTimeoutError",
165
161
  // SMP 30s timeout
166
162
  BleGattBondingFailed: "BleGattBondingFailedError",
@@ -243,25 +239,6 @@ var CONNECTION_LEVEL_TAGS = /* @__PURE__ */ new Set([
243
239
  ERROR_TAG.ReconnectionFailed,
244
240
  ERROR_TAG.WebHIDDisconnect
245
241
  ]);
246
- var DEVICE_NOT_FOUND_TAGS = /* @__PURE__ */ new Set([
247
- ERROR_TAG.NoAccessibleDevice,
248
- ERROR_TAG.UnknownDevice,
249
- ERROR_TAG.DeviceNotInitialized,
250
- // SDK-internal: dm.connect() called before _discovered was populated.
251
- // Map to DeviceNotFound so non-BLE-direct paths get a sensible error code.
252
- ERROR_TAG.DeviceNotInDiscoveryCache
253
- ]);
254
- var DEVICE_BUSY_TAGS = /* @__PURE__ */ new Set([ERROR_TAG.OpeningConnection]);
255
- var DEVICE_DISCONNECTED_TAGS = /* @__PURE__ */ new Set([
256
- ERROR_TAG.DeviceNotRecognized,
257
- ERROR_TAG.DeviceSessionNotFound,
258
- ERROR_TAG.DeviceSessionRefresher,
259
- ERROR_TAG.DeviceDisconnectedBeforeSendingApdu,
260
- ERROR_TAG.DeviceDisconnectedWhileSending,
261
- ERROR_TAG.Disconnect,
262
- ERROR_TAG.ReconnectionFailed,
263
- ERROR_TAG.WebHIDDisconnect
264
- ]);
265
242
  function isConnectionLevelError(err) {
266
243
  if (!err || typeof err !== "object") return false;
267
244
  const tag = err._tag;
@@ -283,35 +260,6 @@ function hasStatusCode(err, codeSet) {
283
260
  if (e.error != null && e._tag && hasStatusCode(e.error, codeSet)) return true;
284
261
  return false;
285
262
  }
286
- function hasBlindSignFallbackStep(err) {
287
- if (!err || typeof err !== "object") return false;
288
- const e = err;
289
- if (e._lastStep === STEP_BLIND_SIGN_TRANSACTION_FALLBACK) return true;
290
- if (Array.isArray(e._deviceActionSteps) && e._deviceActionSteps.includes(STEP_BLIND_SIGN_TRANSACTION_FALLBACK)) {
291
- return true;
292
- }
293
- if (e.originalError != null && hasBlindSignFallbackStep(e.originalError)) return true;
294
- if (e.error != null && e._tag && hasBlindSignFallbackStep(e.error)) return true;
295
- return false;
296
- }
297
- function isDeviceNotFoundError(err) {
298
- if (!err || typeof err !== "object") return false;
299
- const tag = err._tag;
300
- if (tag && DEVICE_NOT_FOUND_TAGS.has(tag)) return true;
301
- const e = err;
302
- if (e.originalError != null && isDeviceNotFoundError(e.originalError)) return true;
303
- if (e.error != null && e._tag && isDeviceNotFoundError(e.error)) return true;
304
- return false;
305
- }
306
- function isDeviceBusyError(err) {
307
- if (!err || typeof err !== "object") return false;
308
- const tag = err._tag;
309
- if (tag && DEVICE_BUSY_TAGS.has(tag)) return true;
310
- const e = err;
311
- if (e.originalError != null && isDeviceBusyError(e.originalError)) return true;
312
- if (e.error != null && e._tag && isDeviceBusyError(e.error)) return true;
313
- return false;
314
- }
315
263
  function isUserRejectedError(err) {
316
264
  if (!err || typeof err !== "object") return false;
317
265
  const e = err;
@@ -344,8 +292,8 @@ function isAppNotInstalledError(err) {
344
292
  function isDeviceDisconnectedError(err) {
345
293
  if (!err || typeof err !== "object") return false;
346
294
  const e = err;
347
- const tag = e._tag;
348
- if (typeof tag === "string" && DEVICE_DISCONNECTED_TAGS.has(tag)) return true;
295
+ if (e._tag === ERROR_TAG.DeviceNotRecognized || e._tag === ERROR_TAG.DeviceSessionNotFound)
296
+ return true;
349
297
  if (typeof e.message === "string") {
350
298
  const msg = e.message.toLowerCase();
351
299
  if (msg.includes("disconnected") || msg.includes("not found") || msg.includes("no device") || msg.includes("unplugged"))
@@ -391,10 +339,8 @@ function mapLedgerError(err, opts) {
391
339
  let code;
392
340
  if (isDeviceLockedError(err)) {
393
341
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceLocked;
394
- } else if (isDeviceNotAdvertisingError(err) || isDeviceNotFoundError(err)) {
342
+ } else if (isDeviceNotAdvertisingError(err)) {
395
343
  code = import_hwk_adapter_core.HardwareErrorCode.DeviceNotFound;
396
- } else if (isDeviceBusyError(err)) {
397
- code = import_hwk_adapter_core.HardwareErrorCode.DeviceBusy;
398
344
  } else if (isBlePairingFailureError(err)) {
399
345
  code = import_hwk_adapter_core.HardwareErrorCode.BlePairingTimeout;
400
346
  } else if (isUserRejectedError(err)) {
@@ -408,7 +354,9 @@ function mapLedgerError(err, opts) {
408
354
  } else if (isTimeoutError(err)) {
409
355
  code = import_hwk_adapter_core.HardwareErrorCode.OperationTimeout;
410
356
  } else {
411
- const ethMapped = classifyEthAppError(err);
357
+ const ethCode = getEthAppErrorCode(err);
358
+ const lastStep = err && typeof err === "object" ? err._lastStep : void 0;
359
+ const ethMapped = ethCode ? mapEthAppError(ethCode, lastStep) : null;
412
360
  const apduHex = ethMapped ? null : extractApduHex(err);
413
361
  const chainMapped = apduHex ? mapSolanaAppError(apduHex) ?? mapTronAppError(apduHex) ?? mapBtcAppError(apduHex) : null;
414
362
  code = ethMapped ?? chainMapped ?? import_hwk_adapter_core.HardwareErrorCode.UnknownError;
@@ -429,6 +377,9 @@ function isLedgerBleConnectionType(connectionType) {
429
377
  function isLedgerBleDescriptor(connectionType, descriptor) {
430
378
  return isLedgerBleConnectionType(connectionType) || isLedgerDmkBleTransport(descriptor.transport);
431
379
  }
380
+ function isValidLedgerBleConnectId(connectId) {
381
+ return /^[0-9A-Fa-f]{4}$/.test(connectId ?? "");
382
+ }
432
383
 
433
384
  // src/utils/sdkEventBus.ts
434
385
  var listeners = /* @__PURE__ */ new Set();
@@ -589,15 +540,9 @@ var _LedgerAdapter = class _LedgerAdapter {
589
540
  // ---------------------------------------------------------------------------
590
541
  // Device management
591
542
  // ---------------------------------------------------------------------------
592
- async searchDevices(options) {
593
- if (options?.resetSession) {
594
- this._doConnectAbortController?.abort();
595
- this._sessions.clear();
596
- this._connectingPromise = null;
597
- this._doConnectAbortController = null;
598
- this._btcHighIndexConfirmedThisSession = false;
599
- }
543
+ async searchDevices() {
600
544
  await this._ensureDevicePermission();
545
+ debugLog(`[LedgerAdapter] searchDevices() entry, cacheBefore=${this._discoveredDevices.size}`);
601
546
  const devices = await this.connector.searchDevices();
602
547
  this._discoveredDevices.clear();
603
548
  for (const d of devices) {
@@ -628,6 +573,16 @@ var _LedgerAdapter = class _LedgerAdapter {
628
573
  });
629
574
  }
630
575
  await this._ensureDevicePermission(connectId);
576
+ if (isLedgerBleConnectionType(this.connector.connectionType)) {
577
+ const fresh = (await this.searchDevices()).some((d) => d.connectId === connectId);
578
+ if (!fresh) {
579
+ const err = new Error(
580
+ "Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
581
+ );
582
+ err._tag = ERROR_TAG.DeviceNotAdvertising;
583
+ throw err;
584
+ }
585
+ }
631
586
  const session = await this.connector.connect(connectId);
632
587
  this._sessions.set(connectId, session.sessionId);
633
588
  if (session.deviceInfo) {
@@ -777,11 +732,21 @@ var _LedgerAdapter = class _LedgerAdapter {
777
732
  // Chain fingerprint
778
733
  // ---------------------------------------------------------------------------
779
734
  async getChainFingerprint(connectId, deviceId, chain) {
735
+ debugLog(
736
+ "[LedgerAdapter] getChainFingerprint called, chain:",
737
+ chain,
738
+ "connectId:",
739
+ connectId || "(empty)",
740
+ "sessions:",
741
+ this._sessions.size
742
+ );
743
+ debugLog("[LedgerAdapter] getChainFingerprint permission ok, computing fingerprint");
780
744
  try {
781
745
  const fingerprint = await this._computeChainFingerprint(
782
746
  chain,
783
747
  (method, params) => this.connectorCall(connectId, method, params, void 0, deviceId)
784
748
  );
749
+ debugLog("[LedgerAdapter] getChainFingerprint result:", fingerprint?.substring(0, 20));
785
750
  return (0, import_hwk_adapter_core2.success)(fingerprint);
786
751
  } catch (err) {
787
752
  debugError("[LedgerAdapter] getChainFingerprint error:", chain, err);
@@ -975,22 +940,6 @@ var _LedgerAdapter = class _LedgerAdapter {
975
940
  // Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
976
941
  // throw DeviceNotFound so the user is kicked out of the loop.
977
942
  async _doConnect(internalSignal, targetConnectId) {
978
- if (isLedgerBleConnectionType(this.connector.connectionType) && targetConnectId) {
979
- try {
980
- return await this._connectDeviceOrThrow(targetConnectId);
981
- } catch (err) {
982
- if (!isDeviceLockedError(err) && !isDeviceNotAdvertisingError(err) && !isDeviceDisconnectedError(err)) {
983
- throw err;
984
- }
985
- this._discoveredDevices.delete(targetConnectId);
986
- if (isDeviceDisconnectedError(err)) {
987
- try {
988
- this.connector.reset?.();
989
- } catch {
990
- }
991
- }
992
- }
993
- }
994
943
  let confirms = 0;
995
944
  while (!internalSignal.aborted) {
996
945
  this.emitter.emit("ui-event", {
@@ -1043,13 +992,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1043
992
  (d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
1044
993
  );
1045
994
  if (!target) {
1046
- const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
995
+ throw Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
1047
996
  code: import_hwk_adapter_core2.HardwareErrorCode.DeviceNotFound
1048
997
  });
1049
- if (isLedgerBleConnectionType(this.connector.connectionType)) {
1050
- err._tag = ERROR_TAG.DeviceNotAdvertising;
1051
- }
1052
- throw err;
1053
998
  }
1054
999
  return this._connectDeviceOrThrow(target.connectId);
1055
1000
  }
@@ -1190,6 +1135,14 @@ var _LedgerAdapter = class _LedgerAdapter {
1190
1135
  }
1191
1136
  const resolvedConnectId = await this.ensureConnected(connectId, signal);
1192
1137
  const sessionId = this._sessions.get(resolvedConnectId);
1138
+ debugLog(
1139
+ "[LedgerAdapter] connectorCall resolved:",
1140
+ method,
1141
+ "resolvedConnectId:",
1142
+ resolvedConnectId,
1143
+ "sessionId:",
1144
+ sessionId
1145
+ );
1193
1146
  if (!sessionId) {
1194
1147
  throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
1195
1148
  _tag: ERROR_TAG.DeviceSessionNotFound
@@ -1232,39 +1185,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1232
1185
  this.connector.reset?.();
1233
1186
  } catch {
1234
1187
  }
1235
- debugLog(
1236
- "[LedgerAdapter] stuck-app retry: method=",
1237
- method,
1238
- "delayMs=",
1239
- _LedgerAdapter.STUCK_APP_RETRY_DELAY_MS,
1240
- "_tag=",
1241
- err?._tag
1242
- );
1243
- try {
1244
- const retryResult = await this._retryAfterStuckApp(
1245
- resolvedConnectId,
1246
- method,
1247
- effectiveParams,
1248
- signal,
1249
- err,
1250
- fingerprint
1251
- );
1252
- debugLog("[LedgerAdapter] stuck-app retry succeeded: method=", method);
1253
- return retryResult;
1254
- } catch (retryErr) {
1255
- if (signal.aborted) throw retryErr;
1256
- if (isStuckAppStateError(retryErr)) {
1257
- debugLog("[LedgerAdapter] stuck-app retry exhausted (2nd 6901): method=", method);
1258
- throw err;
1259
- }
1260
- debugLog(
1261
- "[LedgerAdapter] stuck-app retry threw non-stuck error: method=",
1262
- method,
1263
- "retryErrTag=",
1264
- retryErr?._tag
1265
- );
1266
- throw retryErr;
1267
- }
1188
+ throw err;
1268
1189
  }
1269
1190
  if (isDeviceLockedError(err) || isDeviceNotAdvertisingError(err) || isDeviceDisconnectedError(err)) {
1270
1191
  let lastErr = err;
@@ -1338,54 +1259,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1338
1259
  throw err;
1339
1260
  }
1340
1261
  }
1341
- /**
1342
- * Stuck-app recovery: pause for the device's UI transition, then retry once.
1343
- *
1344
- * Caller has already cleared the session + reset connector. We wait so Stax
1345
- * finishes its post-CloseApp animation, then go through ensureConnected +
1346
- * fingerprint check + call exactly once. Caller decides what to do on a
1347
- * second stuck-app hit.
1348
- */
1349
- async _retryAfterStuckApp(resolvedConnectId, method, params, signal, originalErr, fingerprint) {
1350
- await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
1351
- const retryTargetConnectId = isLedgerBleConnectionType(this.connector.connectionType) ? resolvedConnectId : void 0;
1352
- const retryConnectId = await this.ensureConnected(retryTargetConnectId, signal);
1353
- const retrySessionId = this._sessions.get(retryConnectId);
1354
- if (!retrySessionId) throw originalErr;
1355
- if (fingerprint && !fingerprint.skipFingerprint && fingerprint.deviceId) {
1356
- const fp = await this._abortable(
1357
- signal,
1358
- this._verifyDeviceFingerprintWithSession(
1359
- retrySessionId,
1360
- fingerprint.deviceId,
1361
- fingerprint.chain
1362
- )
1363
- );
1364
- if (!fp.success) {
1365
- throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
1366
- code: import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch
1367
- });
1368
- }
1369
- }
1370
- return this._abortable(signal, this.connector.call(retrySessionId, method, params));
1371
- }
1372
- _sleepAbortable(ms, signal) {
1373
- return new Promise((resolve, reject) => {
1374
- if (signal.aborted) {
1375
- reject(signal.reason ?? new Error("Aborted"));
1376
- return;
1377
- }
1378
- const timer = setTimeout(() => {
1379
- signal.removeEventListener("abort", onAbort);
1380
- resolve();
1381
- }, ms);
1382
- const onAbort = () => {
1383
- clearTimeout(timer);
1384
- reject(signal.reason ?? new Error("Aborted"));
1385
- };
1386
- signal.addEventListener("abort", onAbort, { once: true });
1387
- });
1388
- }
1389
1262
  /**
1390
1263
  * Clear stale session, reconnect, and retry the call.
1391
1264
  *
@@ -1547,18 +1420,15 @@ var _LedgerAdapter = class _LedgerAdapter {
1547
1420
  // Device info mapping
1548
1421
  // ---------------------------------------------------------------------------
1549
1422
  connectorDeviceToDeviceInfo(device) {
1423
+ const isBle = device.connectId && /^[0-9A-Fa-f]{4}$/.test(device.connectId);
1550
1424
  return {
1551
1425
  vendor: "ledger",
1552
1426
  model: device.model ?? "unknown",
1553
- modelName: device.modelName,
1554
1427
  firmwareVersion: "",
1555
1428
  deviceId: device.deviceId,
1556
1429
  connectId: device.connectId,
1557
1430
  label: device.name,
1558
- connectionType: this.connector.connectionType,
1559
- rssi: device.rssi,
1560
- isConnectable: device.isConnectable,
1561
- serialNumber: device.serialNumber,
1431
+ connectionType: isBle ? "ble" : "usb",
1562
1432
  capabilities: device.capabilities
1563
1433
  };
1564
1434
  }
@@ -1566,10 +1436,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1566
1436
  // Layer 2 retry budget after connection-class error. Each round delegates
1567
1437
  // to Layer 1 (which owns the unlock prompt). Layer 2 never emits UI itself.
1568
1438
  _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET = 3;
1569
- // Stuck-app (APDU 0x6901) retry pause. Ledger Stax often returns 6901 when
1570
- // OpenAppCommand lands mid-transition right after CloseApp; a short wait
1571
- // lets the device finish its UI animation before we retry once.
1572
- _LedgerAdapter.STUCK_APP_RETRY_DELAY_MS = 500;
1573
1439
  // Layer 1 confirm budget. After N failed Confirm cycles (user keeps clicking
1574
1440
  // Confirm but device never shows up / never unlocks), throw DeviceNotFound
1575
1441
  // instead of looping forever.
@@ -1577,7 +1443,7 @@ _LedgerAdapter.MAX_DOCONNECT_CONFIRMS = 3;
1577
1443
  var LedgerAdapter = _LedgerAdapter;
1578
1444
 
1579
1445
  // src/connector/LedgerConnectorBase.ts
1580
- var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
1446
+ var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
1581
1447
 
1582
1448
  // src/device/LedgerDeviceManager.ts
1583
1449
  var LedgerDeviceManager = class {
@@ -1616,7 +1482,7 @@ var LedgerDeviceManager = class {
1616
1482
  resolved = true;
1617
1483
  this._discovered.clear();
1618
1484
  debugLog(
1619
- `[DMK] enumerate count=${devices.length} ids=[${devices.map((d) => d.id).join(",")}]`
1485
+ `[DMK] enumerate raw count=${devices.length} ids=[${devices.map((d) => d.id).join(",")}]`
1620
1486
  );
1621
1487
  for (const d of devices) {
1622
1488
  this._discovered.set(d.id, d);
@@ -1627,7 +1493,6 @@ var LedgerDeviceManager = class {
1627
1493
  devices.map((d) => ({
1628
1494
  path: d.id,
1629
1495
  type: d.deviceModel.model,
1630
- modelName: d.deviceModel.name,
1631
1496
  name: d.name,
1632
1497
  transport: d.transport,
1633
1498
  rssi: d.rssi
@@ -1651,7 +1516,6 @@ var LedgerDeviceManager = class {
1651
1516
  devices.map((d) => ({
1652
1517
  path: d.id,
1653
1518
  type: d.deviceModel.model,
1654
- modelName: d.deviceModel.name,
1655
1519
  name: d.name,
1656
1520
  transport: d.transport,
1657
1521
  rssi: d.rssi
@@ -1678,7 +1542,6 @@ var LedgerDeviceManager = class {
1678
1542
  descriptor: {
1679
1543
  path: d.id,
1680
1544
  type: d.deviceModel.model,
1681
- modelName: d.deviceModel.name,
1682
1545
  name: d.name,
1683
1546
  transport: d.transport,
1684
1547
  rssi: d.rssi
@@ -1769,29 +1632,11 @@ var LedgerDeviceManager = class {
1769
1632
  getDeviceName(deviceId) {
1770
1633
  return this._discovered.get(deviceId)?.name;
1771
1634
  }
1772
- /** Lookup minimal model/signal info from a previously-discovered device. */
1773
- getDiscoveredDeviceInfo(deviceId) {
1774
- const d = this._discovered.get(deviceId);
1775
- if (!d) return void 0;
1776
- return {
1777
- model: d.deviceModel?.model,
1778
- modelName: d.deviceModel?.name,
1779
- name: d.name,
1780
- rssi: d.rssi
1781
- };
1782
- }
1783
- hasDiscoveredDevice(deviceId) {
1784
- return this._discovered.has(deviceId);
1785
- }
1786
1635
  /** Connect to a previously discovered device. Returns sessionId. */
1787
1636
  async connect(deviceId) {
1788
1637
  const device = this._discovered.get(deviceId);
1789
1638
  if (!device) {
1790
- const err = new Error(
1791
- `Device "${deviceId}" not found in discovery cache. Call enumerate() or listen() first.`
1792
- );
1793
- err._tag = ERROR_TAG.DeviceNotInDiscoveryCache;
1794
- throw err;
1639
+ throw new Error(`Device "${deviceId}" not found. Call enumerate() or listen() first.`);
1795
1640
  }
1796
1641
  const sessionId = await this._dmk.connect({ device });
1797
1642
  this._sessions.set(deviceId, sessionId);
@@ -1859,7 +1704,6 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
1859
1704
  return new Promise((resolve, reject) => {
1860
1705
  let settled = false;
1861
1706
  let lastStep;
1862
- const observedSteps = [];
1863
1707
  let sub;
1864
1708
  let timer = null;
1865
1709
  const cancelAction = () => {
@@ -1919,12 +1763,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
1919
1763
  }
1920
1764
  armIdleWatchdog();
1921
1765
  const step = state?.intermediateValue?.step;
1922
- if (step) {
1923
- lastStep = step;
1924
- if (observedSteps[observedSteps.length - 1] !== step) {
1925
- observedSteps.push(step);
1926
- }
1927
- }
1766
+ if (step) lastStep = step;
1928
1767
  if (state.status === import_device_management_kit.DeviceActionStatus.Completed) {
1929
1768
  settled = true;
1930
1769
  if (timer) clearTimeout(timer);
@@ -1936,7 +1775,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
1936
1775
  if (timer) clearTimeout(timer);
1937
1776
  onInteraction?.("interaction-complete");
1938
1777
  sub?.unsubscribe();
1939
- rejectWithStepContext(state.error, lastStep, observedSteps, reject);
1778
+ rejectWithLastStep(state.error, lastStep, reject);
1940
1779
  } else if (state.status === import_device_management_kit.DeviceActionStatus.Pending && onInteraction) {
1941
1780
  const interaction = state.intermediateValue?.requiredUserInteraction;
1942
1781
  if (interaction && interaction !== "none") {
@@ -1953,7 +1792,7 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
1953
1792
  settled = true;
1954
1793
  if (timer) clearTimeout(timer);
1955
1794
  sub?.unsubscribe();
1956
- rejectWithStepContext(err, lastStep, observedSteps, reject);
1795
+ rejectWithLastStep(err, lastStep, reject);
1957
1796
  }
1958
1797
  },
1959
1798
  complete: () => {
@@ -1966,25 +1805,15 @@ function deviceActionToPromise(action, onInteraction, timeoutMs = IDLE_WATCHDOG_
1966
1805
  });
1967
1806
  });
1968
1807
  }
1969
- function rejectWithStepContext(err, lastStep, observedSteps, reject) {
1970
- if (err && typeof err === "object" && (lastStep || observedSteps.length > 0)) {
1808
+ function rejectWithLastStep(err, lastStep, reject) {
1809
+ if (err && typeof err === "object" && lastStep) {
1971
1810
  try {
1972
- if (lastStep) {
1973
- Object.defineProperty(err, "_lastStep", {
1974
- value: lastStep,
1975
- configurable: true,
1976
- enumerable: false,
1977
- writable: true
1978
- });
1979
- }
1980
- if (observedSteps.length > 0) {
1981
- Object.defineProperty(err, "_deviceActionSteps", {
1982
- value: [...observedSteps],
1983
- configurable: true,
1984
- enumerable: false,
1985
- writable: true
1986
- });
1987
- }
1811
+ Object.defineProperty(err, "_lastStep", {
1812
+ value: lastStep,
1813
+ configurable: true,
1814
+ enumerable: false,
1815
+ writable: true
1816
+ });
1988
1817
  } catch {
1989
1818
  }
1990
1819
  }
@@ -2050,8 +1879,7 @@ var SignerManager = class _SignerManager {
2050
1879
  async getOrCreate(sessionId) {
2051
1880
  debugLog("[DMK] SignerManager.getOrCreate:", { sessionId });
2052
1881
  const builder = await this._builderFn({ dmk: this._dmk, sessionId });
2053
- const builderWithContext = builder.withContextModule ? builder.withContextModule(_SignerManager._createContextModule()) : builder;
2054
- return new SignerEth(builderWithContext.build());
1882
+ return new SignerEth(builder.build());
2055
1883
  }
2056
1884
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
2057
1885
  invalidate(_sessionId) {
@@ -2060,24 +1888,10 @@ var SignerManager = class _SignerManager {
2060
1888
  clearAll() {
2061
1889
  }
2062
1890
  static _defaultBuilder() {
2063
- return (args) => new import_device_signer_kit_ethereum.SignerEthBuilder(args);
2064
- }
2065
- static _createContextModule() {
2066
- const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
2067
- return _SignerManager.wrapBlindSigningReportNonBlocking(contextModule);
2068
- }
2069
- static wrapBlindSigningReportNonBlocking(contextModule) {
2070
- const report = contextModule.report.bind(contextModule);
2071
- contextModule.report = async (params) => {
2072
- try {
2073
- void report(params).catch((err) => {
2074
- debugLog("[DMK] ContextModule.report failed:", err);
2075
- });
2076
- } catch (err) {
2077
- debugLog("[DMK] ContextModule.report failed:", err);
2078
- }
1891
+ return (args) => {
1892
+ const contextModule = new import_context_module.ContextModuleBuilder({}).removeDefaultLoaders().build();
1893
+ return new import_device_signer_kit_ethereum.SignerEthBuilder(args).withContextModule(contextModule);
2079
1894
  };
2080
- return contextModule;
2081
1895
  }
2082
1896
  };
2083
1897
 
@@ -2647,15 +2461,14 @@ async function _createSolSigner(ctx, sessionId) {
2647
2461
  }
2648
2462
 
2649
2463
  // src/connector/chains/tron.ts
2650
- var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
2464
+ var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
2651
2465
  var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
2652
2466
 
2653
2467
  // src/connector/chains/legacyChainCall.ts
2654
- var import_hwk_adapter_core10 = require("@onekeyfe/hwk-adapter-core");
2468
+ var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
2655
2469
 
2656
2470
  // src/app/AppManager.ts
2657
2471
  var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
2658
- var import_hwk_adapter_core9 = require("@onekeyfe/hwk-adapter-core");
2659
2472
  var APP_NAME_MAP = {
2660
2473
  ETH: "Ethereum",
2661
2474
  BTC: "Bitcoin",
@@ -2760,11 +2573,9 @@ var AppManager = class {
2760
2573
  });
2761
2574
  if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
2762
2575
  const { statusCode } = result;
2763
- const hasStatusCode2 = statusCode != null && statusCode !== "";
2764
2576
  debugLog("[AppManager] openApp failed:", appName, "statusCode:", statusCode);
2765
2577
  throw Object.assign(new Error(`Failed to open "${appName}"`), {
2766
2578
  _tag: ERROR_TAG.OpenAppCommand,
2767
- code: hasStatusCode2 ? void 0 : import_hwk_adapter_core9.HardwareErrorCode.AppNotInstalled,
2768
2579
  errorCode: String(statusCode ?? ""),
2769
2580
  statusCode,
2770
2581
  appName
@@ -2820,14 +2631,14 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
2820
2631
  const onAppOpenPrompt = () => {
2821
2632
  openAppPromptShown = true;
2822
2633
  ctx.emit("ui-event", {
2823
- type: import_hwk_adapter_core10.EConnectorInteraction.ConfirmOpenApp,
2634
+ type: import_hwk_adapter_core9.EConnectorInteraction.ConfirmOpenApp,
2824
2635
  payload: { sessionId }
2825
2636
  });
2826
2637
  };
2827
2638
  const closeOpenAppUiIfShown = () => {
2828
2639
  if (openAppPromptShown) {
2829
2640
  ctx.emit("ui-event", {
2830
- type: import_hwk_adapter_core10.EConnectorInteraction.InteractionComplete,
2641
+ type: import_hwk_adapter_core9.EConnectorInteraction.InteractionComplete,
2831
2642
  payload: { sessionId }
2832
2643
  });
2833
2644
  openAppPromptShown = false;
@@ -2848,7 +2659,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
2848
2659
  let confirmEmitted = false;
2849
2660
  if (needsConfirmation) {
2850
2661
  ctx.emit("ui-event", {
2851
- type: import_hwk_adapter_core10.EConnectorInteraction.ConfirmOnDevice,
2662
+ type: import_hwk_adapter_core9.EConnectorInteraction.ConfirmOnDevice,
2852
2663
  payload: { sessionId }
2853
2664
  });
2854
2665
  confirmEmitted = true;
@@ -2858,7 +2669,7 @@ async function withLegacyChainCall(ctx, sessionId, options, action) {
2858
2669
  } finally {
2859
2670
  if (confirmEmitted || openAppPromptShown) {
2860
2671
  ctx.emit("ui-event", {
2861
- type: import_hwk_adapter_core10.EConnectorInteraction.InteractionComplete,
2672
+ type: import_hwk_adapter_core9.EConnectorInteraction.InteractionComplete,
2862
2673
  payload: { sessionId }
2863
2674
  });
2864
2675
  openAppPromptShown = false;
@@ -2946,7 +2757,7 @@ async function tronSignTransaction(ctx, sessionId, params) {
2946
2757
  if (!params.rawTxHex) {
2947
2758
  throw Object.assign(
2948
2759
  new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
2949
- { code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
2760
+ { code: import_hwk_adapter_core10.HardwareErrorCode.InvalidParams }
2950
2761
  );
2951
2762
  }
2952
2763
  const path = normalizePath(params.path);
@@ -2990,10 +2801,6 @@ var METHOD_PREFIX_TO_APP_NAME = {
2990
2801
  sol: "Solana",
2991
2802
  tron: "Tron"
2992
2803
  };
2993
- var HARDWARE_ERROR_CODE_VALUES = new Set(
2994
- Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
2995
- );
2996
- var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
2997
2804
  async function defaultLedgerKitImporter(pkg) {
2998
2805
  switch (pkg) {
2999
2806
  case "@ledgerhq/device-management-kit":
@@ -3017,6 +2824,16 @@ var LedgerConnectorBase = class {
3017
2824
  this._dmk = null;
3018
2825
  this._eventHandlers = /* @__PURE__ */ new Map();
3019
2826
  // ---------------------------------------------------------------------------
2827
+ // ConnectId <-> DMK path mapping
2828
+ //
2829
+ // DMK uses internal paths (BLE MAC, USB UUID) that may change across sessions.
2830
+ // _resolveConnectId() maps these to stable external IDs (BLE: "A58F", USB: same).
2831
+ // This bidirectional map is the SINGLE SOURCE OF TRUTH for all connectId usage.
2832
+ // ---------------------------------------------------------------------------
2833
+ this._connectIdToPath = /* @__PURE__ */ new Map();
2834
+ // "A58F" -> "D5:75:7D:4B:51:E8"
2835
+ this._pathToConnectId = /* @__PURE__ */ new Map();
2836
+ // ---------------------------------------------------------------------------
3020
2837
  // Per-session DeviceAction cancellers
3021
2838
  //
3022
2839
  // Each chain handler registers its active DeviceAction's canceller via
@@ -3041,7 +2858,6 @@ var LedgerConnectorBase = class {
3041
2858
  this.connectionType = options?.connectionType ?? "usb";
3042
2859
  this._providedDmk = options?.dmk;
3043
2860
  this._importLedgerKit = options?.importLedgerKit ?? defaultLedgerKitImporter;
3044
- this._requirePreFlightScan = options?.requirePreFlightScan ?? false;
3045
2861
  if (this._providedDmk) {
3046
2862
  this._initManagers(this._providedDmk);
3047
2863
  }
@@ -3059,13 +2875,22 @@ var LedgerConnectorBase = class {
3059
2875
  importLedgerKit: this._importLedgerKit
3060
2876
  };
3061
2877
  }
2878
+ // "D5:75:7D:4B:51:E8" -> "A58F"
2879
+ /** Get DMK path from external connectId. Falls back to connectId itself. */
2880
+ _getPathForConnectId(connectId) {
2881
+ return this._connectIdToPath.get(connectId) ?? connectId;
2882
+ }
2883
+ /** Get external connectId from DMK path. Falls back to path itself. */
2884
+ _getConnectIdForPath(path) {
2885
+ return this._pathToConnectId.get(path) ?? path;
2886
+ }
3062
2887
  // ---------------------------------------------------------------------------
3063
2888
  // Protected — hooks for subclasses
3064
2889
  // ---------------------------------------------------------------------------
3065
2890
  /**
3066
2891
  * Resolve the connectId for a discovered device descriptor.
3067
2892
  * Default: use the DMK path (ephemeral UUID).
3068
- * Override in subclasses only when the public connectId differs from the transport path.
2893
+ * Override in subclasses to extract stable identifiers (e.g. BLE hex ID).
3069
2894
  */
3070
2895
  _resolveConnectId(descriptor) {
3071
2896
  return descriptor.path;
@@ -3090,22 +2915,50 @@ var LedgerConnectorBase = class {
3090
2915
  // IConnector -- Device discovery
3091
2916
  // ---------------------------------------------------------------------------
3092
2917
  async searchDevices() {
2918
+ debugLog("[DMK] connector.searchDevices() entry");
3093
2919
  const dm = await this._getDeviceManager();
3094
2920
  const descriptors = await this._discoverDescriptors(dm);
3095
2921
  const resolvedDescriptors = descriptors.map((d) => ({
3096
2922
  descriptor: d,
3097
2923
  connectId: this._resolveConnectId(d)
3098
2924
  }));
3099
- const result = resolvedDescriptors.map(({ descriptor: d, connectId }) => ({
3100
- connectId,
3101
- deviceId: d.path,
3102
- name: d.name || d.type || "Ledger",
3103
- model: d.type,
3104
- modelName: d.modelName,
3105
- rssi: d.rssi,
3106
- isConnectable: d.isConnectable,
3107
- serialNumber: d.serialNumber
3108
- }));
2925
+ const bleConnectIdCounts = /* @__PURE__ */ new Map();
2926
+ for (const item of resolvedDescriptors) {
2927
+ if (isLedgerBleDescriptor(this.connectionType, item.descriptor)) {
2928
+ if (!isValidLedgerBleConnectId(item.connectId)) {
2929
+ debugLog(`[DMK] connector.searchDevices() invalid BLE connectId=${item.connectId}`);
2930
+ throw Object.assign(
2931
+ new Error("Ledger BLE connectId must be the 4-character BLE identifier"),
2932
+ { code: import_hwk_adapter_core11.HardwareErrorCode.DeviceNotFound }
2933
+ );
2934
+ }
2935
+ bleConnectIdCounts.set(item.connectId, (bleConnectIdCounts.get(item.connectId) ?? 0) + 1);
2936
+ }
2937
+ }
2938
+ const duplicateBleConnectId = Array.from(bleConnectIdCounts.entries()).find(
2939
+ ([, count]) => count > 1
2940
+ )?.[0];
2941
+ if (duplicateBleConnectId) {
2942
+ debugLog(
2943
+ `[DMK] connector.searchDevices() duplicate BLE connectId=${duplicateBleConnectId} counts=${JSON.stringify(
2944
+ Array.from(bleConnectIdCounts.entries())
2945
+ )}`
2946
+ );
2947
+ throw Object.assign(
2948
+ new Error(`Duplicate Ledger BLE connectId detected: ${duplicateBleConnectId}`),
2949
+ { code: import_hwk_adapter_core11.HardwareErrorCode.DeviceNotFound }
2950
+ );
2951
+ }
2952
+ const result = resolvedDescriptors.map(({ descriptor: d, connectId }) => {
2953
+ this._connectIdToPath.set(connectId, d.path);
2954
+ this._pathToConnectId.set(d.path, connectId);
2955
+ return {
2956
+ connectId,
2957
+ deviceId: d.path,
2958
+ name: d.name || d.type || "Ledger",
2959
+ model: d.type
2960
+ };
2961
+ });
3109
2962
  debugLog(
3110
2963
  `[DMK] connector.searchDevices() return count=${result.length} ids=[${result.map((r) => r.connectId).join(",")}] paths=[${result.map((r) => r.deviceId).join(",")}]`
3111
2964
  );
@@ -3115,8 +2968,7 @@ var LedgerConnectorBase = class {
3115
2968
  // IConnector -- Connection
3116
2969
  // ---------------------------------------------------------------------------
3117
2970
  async connect(deviceId) {
3118
- const callerSuppliedConnectId = Boolean(deviceId);
3119
- let targetPath = deviceId;
2971
+ let targetPath = deviceId ? this._getPathForConnectId(deviceId) : void 0;
3120
2972
  if (!targetPath) {
3121
2973
  const discovered = await this.searchDevices();
3122
2974
  if (discovered.length === 0) {
@@ -3126,7 +2978,7 @@ var LedgerConnectorBase = class {
3126
2978
  }
3127
2979
  targetPath = discovered[0].deviceId;
3128
2980
  }
3129
- const externalConnectId = targetPath;
2981
+ const externalConnectId = this._getConnectIdForPath(targetPath);
3130
2982
  const HANG_CEILING_MS = 5 * 6e4;
3131
2983
  const dmConnectWithObserve = async (dm, path) => {
3132
2984
  if (!isLedgerBleConnectionType(this.connectionType)) return dm.connect(path);
@@ -3140,7 +2992,7 @@ var LedgerConnectorBase = class {
3140
2992
  `Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
3141
2993
  );
3142
2994
  err._tag = ERROR_TAG.BlePairingTimeout;
3143
- err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
2995
+ err.code = import_hwk_adapter_core11.HardwareErrorCode.BlePairingTimeout;
3144
2996
  reject(err);
3145
2997
  }, HANG_CEILING_MS);
3146
2998
  });
@@ -3167,45 +3019,19 @@ var LedgerConnectorBase = class {
3167
3019
  if (timeoutId) clearTimeout(timeoutId);
3168
3020
  }
3169
3021
  };
3170
- const isBleDirectConnect = isLedgerBleConnectionType(this.connectionType) && callerSuppliedConnectId;
3171
- const throwNotAdvertising = () => {
3172
- const err = new Error(
3173
- "Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
3174
- );
3175
- err._tag = ERROR_TAG.DeviceNotAdvertising;
3176
- err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
3177
- throw err;
3178
- };
3179
3022
  const doConnect = async (path) => {
3180
3023
  const dm = await this._getDeviceManager();
3181
- if (isBleDirectConnect && !dm.hasDiscoveredDevice(path)) {
3182
- const live = await dm.getLiveDevices(BLE_CONNECT_SCAN_TIMEOUT_MS);
3183
- if (this._requirePreFlightScan && !live.some((d) => d.id === path)) {
3184
- throwNotAdvertising();
3185
- }
3186
- }
3187
- let sessionId;
3188
- try {
3189
- sessionId = await dmConnectWithObserve(dm, path);
3190
- } catch (err) {
3191
- if (isBleDirectConnect && err?._tag === ERROR_TAG.DeviceNotInDiscoveryCache) {
3192
- throwNotAdvertising();
3193
- }
3194
- throw err;
3195
- }
3024
+ const sessionId = await dmConnectWithObserve(dm, path);
3196
3025
  this._watchSessionState(sessionId, externalConnectId);
3197
- const info = dm.getDiscoveredDeviceInfo(path);
3198
3026
  const session = {
3199
3027
  sessionId,
3200
3028
  deviceInfo: {
3201
3029
  vendor: "ledger",
3202
- model: info?.model ?? "unknown",
3203
- modelName: info?.modelName,
3030
+ model: "unknown",
3204
3031
  firmwareVersion: "unknown",
3205
3032
  deviceId: path,
3206
3033
  connectId: externalConnectId,
3207
3034
  connectionType: this.connectionType,
3208
- rssi: info?.rssi,
3209
3035
  capabilities: { persistentDeviceIdentity: false }
3210
3036
  }
3211
3037
  };
@@ -3228,7 +3054,7 @@ var LedgerConnectorBase = class {
3228
3054
  "Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
3229
3055
  );
3230
3056
  wrapped._tag = ERROR_TAG.BleGattBondingFailed;
3231
- wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
3057
+ wrapped.code = import_hwk_adapter_core11.HardwareErrorCode.BlePairingTimeout;
3232
3058
  wrapped.originalError = err;
3233
3059
  throw wrapped;
3234
3060
  }
@@ -3311,7 +3137,7 @@ var LedgerConnectorBase = class {
3311
3137
  this._unwatchSessionState(sessionId);
3312
3138
  this._signerManager?.invalidate(sessionId);
3313
3139
  this._cancellers.get(sessionId)?.({
3314
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
3140
+ code: import_hwk_adapter_core11.HardwareErrorCode.DeviceDisconnected,
3315
3141
  tag: "DeviceDisconnected",
3316
3142
  message: "Device disconnected"
3317
3143
  });
@@ -3328,14 +3154,14 @@ var LedgerConnectorBase = class {
3328
3154
  } catch (err) {
3329
3155
  if (isAppStuckByApdu(err)) {
3330
3156
  throw Object.assign(new Error("Ledger app is unresponsive"), {
3331
- code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
3157
+ code: import_hwk_adapter_core11.HardwareErrorCode.DeviceAppStuck,
3332
3158
  _tag: ERROR_TAG.DeviceAppStuck,
3333
3159
  originalError: err
3334
3160
  });
3335
3161
  }
3336
3162
  if (isTransportStuck(err)) {
3337
3163
  throw Object.assign(new Error("Device communication interrupted, please retry"), {
3338
- code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
3164
+ code: import_hwk_adapter_core11.HardwareErrorCode.TransportError,
3339
3165
  _tag: ERROR_TAG.DeviceTransportStuck,
3340
3166
  originalError: err
3341
3167
  });
@@ -3483,13 +3309,14 @@ var LedgerConnectorBase = class {
3483
3309
  }
3484
3310
  /**
3485
3311
  * Replace an old session with a new one after app switch.
3486
- * Emits device-connect so the adapter updates its _sessions Map.
3312
+ * Updates the connectId→path mapping so subsequent calls() use the new session,
3313
+ * and emits device-connect so the adapter updates its _sessions Map.
3487
3314
  */
3488
3315
  _replaceSession(oldSessionId, _newSessionId) {
3489
3316
  const dm = this._deviceManager;
3490
3317
  if (!dm) return;
3491
3318
  const oldDeviceId = dm.getDeviceId(oldSessionId);
3492
- const connectId = oldDeviceId;
3319
+ const connectId = oldDeviceId ? this._pathToConnectId.get(oldDeviceId) : void 0;
3493
3320
  this._signerManager?.invalidate(oldSessionId);
3494
3321
  if (connectId) {
3495
3322
  this._emit("device-connect", {
@@ -3502,7 +3329,7 @@ var LedgerConnectorBase = class {
3502
3329
  }
3503
3330
  }
3504
3331
  /**
3505
- * Light reset: clear signer/session state but keep DMK alive.
3332
+ * Light reset: clear signer/session state but keep DMK and ID mapping alive.
3506
3333
  * Used by connect() retry — we want to re-discover with the same transport.
3507
3334
  *
3508
3335
  * Note: drops the device manager but tears down its RxJS subs first via
@@ -3537,6 +3364,8 @@ var LedgerConnectorBase = class {
3537
3364
  this._deviceManager = null;
3538
3365
  this._signerManager = null;
3539
3366
  this._dmk = null;
3367
+ this._connectIdToPath.clear();
3368
+ this._pathToConnectId.clear();
3540
3369
  }
3541
3370
  // ---------------------------------------------------------------------------
3542
3371
  // Private -- Events
@@ -3570,21 +3399,15 @@ var LedgerConnectorBase = class {
3570
3399
  };
3571
3400
  }
3572
3401
  _wrapError(err, opts) {
3402
+ const mapped = mapLedgerError(err, opts);
3573
3403
  const src = err && typeof err === "object" ? err : {};
3574
- const hasSerializedCode = typeof src.code === "number" && HARDWARE_ERROR_CODE_VALUES.has(src.code);
3575
- const mapped = hasSerializedCode ? {
3576
- code: src.code,
3577
- message: typeof src.message === "string" ? src.message : "Unknown Ledger error",
3578
- appName: typeof src.appName === "string" ? src.appName : opts?.defaultAppName
3579
- } : mapLedgerError(err, opts);
3580
3404
  const error = new Error(mapped.message);
3581
3405
  Object.assign(error, {
3582
3406
  code: mapped.code,
3583
3407
  appName: mapped.appName,
3584
3408
  _tag: src._tag,
3585
3409
  errorCode: src.errorCode,
3586
- _lastStep: src._lastStep,
3587
- _deviceActionSteps: src._deviceActionSteps
3410
+ _lastStep: src._lastStep
3588
3411
  });
3589
3412
  Object.defineProperty(error, "originalError", {
3590
3413
  value: err,
@@ -3595,6 +3418,13 @@ var LedgerConnectorBase = class {
3595
3418
  return error;
3596
3419
  }
3597
3420
  };
3421
+
3422
+ // src/utils/bleIdentity.ts
3423
+ function extractBleHexId(name) {
3424
+ if (!name) return void 0;
3425
+ const match = name.match(/\b([0-9A-Fa-f]{4})$/);
3426
+ return match ? match[1].toUpperCase() : void 0;
3427
+ }
3598
3428
  // Annotate the CommonJS export names for ESM import in node:
3599
3429
  0 && (module.exports = {
3600
3430
  AppManager,
@@ -3606,12 +3436,13 @@ var LedgerConnectorBase = class {
3606
3436
  SignerEth,
3607
3437
  SignerManager,
3608
3438
  SignerSol,
3609
- debugLog,
3610
3439
  deviceActionToPromise,
3440
+ extractBleHexId,
3611
3441
  isDeviceLockedError,
3612
3442
  isLedgerBleConnectionType,
3613
3443
  isLedgerBleDescriptor,
3614
3444
  isLedgerDmkBleTransport,
3445
+ isValidLedgerBleConnectId,
3615
3446
  ledgerFailure,
3616
3447
  mapLedgerError,
3617
3448
  offSdkEvent,