@onekeyfe/hwk-ledger-adapter 1.2.3-alpha.1 → 1.2.3-alpha.2

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
@@ -550,7 +550,7 @@ var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "d
550
550
  function createAllNetworkGetAddress({
551
551
  callChain,
552
552
  getChainFingerprint,
553
- retainInteraction,
553
+ retainOperation,
554
554
  errorToFailure
555
555
  }) {
556
556
  return async function allNetworkGetAddress(connectId, _deviceId, params) {
@@ -559,19 +559,19 @@ function createAllNetworkGetAddress({
559
559
  connectId,
560
560
  itemCount: params.bundle.length
561
561
  });
562
- const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.interactionId, "ledger");
562
+ const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
563
563
  if (!target.success) return target;
564
564
  const effectiveTargetId = target.payload.targetId ?? "";
565
- let releaseInteractionRetention;
565
+ let releaseOperationRetention;
566
566
  try {
567
- releaseInteractionRetention = target.payload.interactionId ? retainInteraction(target.payload.interactionId) : void 0;
567
+ releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
568
568
  } catch (error) {
569
569
  return errorToFailure(error);
570
570
  }
571
571
  const installContext = {};
572
572
  const commonParams = {
573
573
  autoInstallApp: params.autoInstallApp,
574
- interactionId: target.payload.interactionId,
574
+ operationId: target.payload.operationId,
575
575
  knownConnections: params.knownConnections,
576
576
  extra: params.extra,
577
577
  allowDeviceSelection: params.allowDeviceSelection
@@ -622,7 +622,7 @@ function createAllNetworkGetAddress({
622
622
  });
623
623
  return result;
624
624
  } finally {
625
- releaseInteractionRetention?.();
625
+ releaseOperationRetention?.();
626
626
  }
627
627
  };
628
628
  }
@@ -631,7 +631,7 @@ function isTopLevelAllNetworkFailure(response) {
631
631
  return false;
632
632
  }
633
633
  const code = response.payload?.code;
634
- return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.InteractionEnded || code === import_hwk_adapter_core2.HardwareErrorCode.InteractionNotFound || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
634
+ return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.OperationEnded || code === import_hwk_adapter_core2.HardwareErrorCode.OperationNotFound || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
635
635
  }
636
636
  function getItemDeviceId(item) {
637
637
  const { deviceId } = item;
@@ -794,26 +794,26 @@ var _LedgerAdapter = class _LedgerAdapter {
794
794
  constructor(connector, options) {
795
795
  this.vendor = "ledger";
796
796
  this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
797
- this._interactions = new import_hwk_adapter_core3.InteractionRegistry({
797
+ this._operations = new import_hwk_adapter_core3.OperationRegistry({
798
798
  vendor: "ledger",
799
- onEnded: (interaction, reason) => {
800
- const binding = this._pendingInteractionBindings.get(interaction.interactionId);
799
+ onEnded: (operation, reason) => {
800
+ const binding = this._pendingOperationBindings.get(operation.operationId);
801
801
  if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
802
802
  this._finishBleBinding("cancelled");
803
803
  }
804
- this._pendingInteractionBindings.delete(interaction.interactionId);
805
- this.emitter.emit(import_hwk_adapter_core3.SDK.INTERACTION_ENDED, {
806
- type: import_hwk_adapter_core3.SDK.INTERACTION_ENDED,
807
- payload: { interactionId: interaction.interactionId, reason }
804
+ this._pendingOperationBindings.delete(operation.operationId);
805
+ this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
806
+ type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
807
+ payload: { operationId: operation.operationId, reason }
808
808
  });
809
809
  if (reason === "timeout") {
810
- void this._releaseInteractionConnection(interaction);
810
+ void this._releaseOperationConnection(operation);
811
811
  }
812
812
  }
813
813
  });
814
814
  this._discoveredDevices = /* @__PURE__ */ new Map();
815
815
  this._sessions = /* @__PURE__ */ new Map();
816
- this._pendingInteractionBindings = /* @__PURE__ */ new Map();
816
+ this._pendingOperationBindings = /* @__PURE__ */ new Map();
817
817
  this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
818
818
  this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
819
819
  // BTC App rejects account index >= 100 unless display=true. Cached per
@@ -834,8 +834,8 @@ var _LedgerAdapter = class _LedgerAdapter {
834
834
  this._stateGeneration = 0;
835
835
  this._connectorTeardownTail = Promise.resolve();
836
836
  this._pendingConnectorTeardowns = 0;
837
- this._activeInteractionJobs = /* @__PURE__ */ new Set();
838
- this._pendingInteractionDisconnects = /* @__PURE__ */ new Set();
837
+ this._activeOperationJobs = /* @__PURE__ */ new Set();
838
+ this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
839
839
  this._installProgressLastEmittedValue = -Infinity;
840
840
  this.allNetworkGetAddress = createAllNetworkGetAddress({
841
841
  callChain: this.callChain.bind(this),
@@ -850,7 +850,7 @@ var _LedgerAdapter = class _LedgerAdapter {
850
850
  return this.errorToFailure(error);
851
851
  }
852
852
  },
853
- retainInteraction: (interactionId) => this._interactions.retain(interactionId),
853
+ retainOperation: (operationId) => this._operations.retain(operationId),
854
854
  errorToFailure: (error) => this.errorToFailure(error)
855
855
  });
856
856
  // ---------------------------------------------------------------------------
@@ -878,11 +878,11 @@ var _LedgerAdapter = class _LedgerAdapter {
878
878
  });
879
879
  };
880
880
  this.deviceDisconnectHandler = (data) => {
881
- const activeInteraction = this._interactions.findActiveByConnectionKey(data.connectId);
882
- if (activeInteraction && this._activeInteractionJobs.has(activeInteraction.interactionId)) {
883
- this._pendingInteractionDisconnects.add(activeInteraction.interactionId);
881
+ const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
882
+ if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
883
+ this._pendingOperationDisconnects.add(activeOperation.operationId);
884
884
  } else {
885
- this._interactions.endByConnectionKey(data.connectId, "disconnect");
885
+ this._operations.endByConnectionKey(data.connectId, "disconnect");
886
886
  }
887
887
  this._discoveredDevices.delete(data.connectId);
888
888
  this._sessions.delete(data.connectId);
@@ -985,7 +985,7 @@ var _LedgerAdapter = class _LedgerAdapter {
985
985
  const sessionIds = new Set(this._sessions.values());
986
986
  this._stateGeneration += 1;
987
987
  this._finishBleBinding("cancelled");
988
- this._interactions.endAll("runtime-reset");
988
+ this._operations.endAll("runtime-reset");
989
989
  this._doConnectAbortController?.abort();
990
990
  this._discoveredDevices.clear();
991
991
  this._sessions.clear();
@@ -1094,8 +1094,8 @@ var _LedgerAdapter = class _LedgerAdapter {
1094
1094
  }));
1095
1095
  }
1096
1096
  // USB single-session invariant: evict all sessions, best-effort (see connectDevice).
1097
- async _evictAllSessions(preserveInteractionId) {
1098
- this._interactions.endAll("explicit", preserveInteractionId);
1097
+ async _evictAllSessions(preserveOperationId) {
1098
+ this._operations.endAll("explicit", preserveOperationId);
1099
1099
  if (this._sessions.size === 0) return;
1100
1100
  const stale = [...this._sessions.values()];
1101
1101
  this._sessions.clear();
@@ -1114,11 +1114,129 @@ var _LedgerAdapter = class _LedgerAdapter {
1114
1114
  });
1115
1115
  }
1116
1116
  async connectDevice(searchTargetId) {
1117
- const connected = await this._connectTarget(searchTargetId);
1118
- if (!connected.success) return connected;
1119
- return this._createInteraction(searchTargetId, connected.payload);
1117
+ try {
1118
+ return await this._jobQueue.enqueue(
1119
+ searchTargetId || "__ledger_connect__",
1120
+ async () => {
1121
+ const connected = await this._connectTarget(searchTargetId);
1122
+ if (!connected.success) return connected;
1123
+ return this._createOperation(searchTargetId, connected.payload);
1124
+ },
1125
+ {
1126
+ label: "connectDevice",
1127
+ rejectIfBusy: true,
1128
+ busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
1129
+ }
1130
+ );
1131
+ } catch (error) {
1132
+ return this.errorToFailure(error);
1133
+ }
1134
+ }
1135
+ async bindBleDevice(params) {
1136
+ if (params.identity.vendor !== "ledger" || !params.identity.value) {
1137
+ return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "Ledger wallet identity is required");
1138
+ }
1139
+ const { chain, value: expectedFingerprint } = params.identity;
1140
+ try {
1141
+ return await this._jobQueue.enqueue(
1142
+ expectedFingerprint,
1143
+ async (signal) => {
1144
+ if (!this.getAvailableTransports().includes("ble")) {
1145
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1146
+ code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
1147
+ message: "Ledger Bluetooth transport is not available"
1148
+ });
1149
+ }
1150
+ this._activeConnectionType = "ble";
1151
+ await this._ensureDevicePermission(void 0, void 0, signal);
1152
+ const attempt = {
1153
+ extra: params.extra,
1154
+ bindingReason: "manual-rebind"
1155
+ };
1156
+ try {
1157
+ for (; ; ) {
1158
+ const connectId = await this._connectFirstOrSelect(
1159
+ [],
1160
+ void 0,
1161
+ true,
1162
+ void 0,
1163
+ attempt,
1164
+ signal
1165
+ );
1166
+ const sessionId = this._sessions.get(connectId);
1167
+ if (!sessionId) {
1168
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1169
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
1170
+ message: "Selected Ledger connection ended"
1171
+ });
1172
+ }
1173
+ let saved = false;
1174
+ try {
1175
+ const installContext = {
1176
+ connection: { connectId, sessionId }
1177
+ };
1178
+ const fingerprint = await this._computeChainFingerprint(
1179
+ chain,
1180
+ (method, callParams) => this._runConnectorCall(
1181
+ connectId,
1182
+ method,
1183
+ callParams,
1184
+ signal,
1185
+ void 0,
1186
+ void 0,
1187
+ { autoInstallApp: true },
1188
+ installContext
1189
+ )
1190
+ );
1191
+ if (fingerprint !== expectedFingerprint) {
1192
+ attempt.rejectedConnectIds ?? (attempt.rejectedConnectIds = /* @__PURE__ */ new Set());
1193
+ attempt.rejectedConnectIds.add(connectId);
1194
+ attempt.rejectedConnectId = connectId;
1195
+ } else {
1196
+ const persisted = await this._publishVerifiedBleBinding(
1197
+ connectId,
1198
+ chain,
1199
+ fingerprint,
1200
+ attempt,
1201
+ void 0,
1202
+ signal
1203
+ );
1204
+ if (!persisted) {
1205
+ throw (0, import_hwk_adapter_core3.createHwkError)({
1206
+ code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
1207
+ message: "Bluetooth binding could not be saved",
1208
+ origin: "host"
1209
+ });
1210
+ }
1211
+ saved = true;
1212
+ return (0, import_hwk_adapter_core3.success)(connectId);
1213
+ }
1214
+ } finally {
1215
+ if (!saved && this._sessions.get(connectId) === sessionId) {
1216
+ this._sessions.delete(connectId);
1217
+ const teardown = this._runConnectorTeardown(
1218
+ () => this.connector.disconnect(sessionId)
1219
+ ).catch(() => void 0);
1220
+ if (!signal.aborted) await teardown;
1221
+ }
1222
+ }
1223
+ }
1224
+ } catch (error) {
1225
+ this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
1226
+ throw error;
1227
+ }
1228
+ },
1229
+ {
1230
+ label: "bindBleDevice",
1231
+ rejectIfBusy: true,
1232
+ busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
1233
+ }
1234
+ );
1235
+ } catch (error) {
1236
+ return this.errorToFailure(error);
1237
+ }
1120
1238
  }
1121
- async acquireInteraction(connectId, context) {
1239
+ async acquireOperation(connectId, context) {
1122
1240
  try {
1123
1241
  return await this._jobQueue.enqueue(
1124
1242
  connectId || "__ledger_acquire__",
@@ -1131,8 +1249,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1131
1249
  await this._ensureDevicePermission(target, void 0, signal);
1132
1250
  const attempt = {
1133
1251
  ...context,
1134
- extra: context.extra ? { ...context.extra } : void 0,
1135
- previousConnectId: target
1252
+ extra: context.extra ? { ...context.extra } : void 0
1136
1253
  };
1137
1254
  try {
1138
1255
  const resolvedConnectId = await this.ensureConnected(
@@ -1143,9 +1260,9 @@ var _LedgerAdapter = class _LedgerAdapter {
1143
1260
  attempt
1144
1261
  );
1145
1262
  _LedgerAdapter._throwIfAborted(signal);
1146
- const result = this._createInteraction(connectId, resolvedConnectId);
1263
+ const result = this._createOperation(connectId, resolvedConnectId);
1147
1264
  if (result.success && attempt.selectedConnection) {
1148
- this._pendingInteractionBindings.set(result.payload, attempt);
1265
+ this._pendingOperationBindings.set(result.payload, attempt);
1149
1266
  }
1150
1267
  return result;
1151
1268
  } catch (error) {
@@ -1154,19 +1271,19 @@ var _LedgerAdapter = class _LedgerAdapter {
1154
1271
  }
1155
1272
  },
1156
1273
  {
1157
- label: "acquireInteraction",
1274
+ label: "acquireOperation",
1158
1275
  rejectIfBusy: true,
1159
- busyError: _LedgerAdapter._createDeviceBusyError("acquireInteraction")
1276
+ busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
1160
1277
  }
1161
1278
  );
1162
1279
  } catch (error) {
1163
1280
  return this.errorToFailure(error);
1164
1281
  }
1165
1282
  }
1166
- _createInteraction(searchTargetId, resolvedConnectId) {
1167
- this._interactions.endByConnectionKey(resolvedConnectId, "explicit");
1283
+ _createOperation(searchTargetId, resolvedConnectId) {
1284
+ this._operations.endByConnectionKey(resolvedConnectId, "explicit");
1168
1285
  const sessionId = this._sessions.get(resolvedConnectId);
1169
- if (sessionId) this._interactions.endByConnectionKey(sessionId, "explicit");
1286
+ if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
1170
1287
  const device = this._discoveredDevices.get(resolvedConnectId) ?? {
1171
1288
  vendor: "ledger",
1172
1289
  model: "unknown",
@@ -1175,15 +1292,15 @@ var _LedgerAdapter = class _LedgerAdapter {
1175
1292
  connectId: resolvedConnectId,
1176
1293
  connectionType: this.connector.connectionType
1177
1294
  };
1178
- const interaction = this._interactions.create({
1295
+ const operation = this._operations.create({
1179
1296
  searchTargetId,
1180
1297
  connectId: resolvedConnectId,
1181
1298
  device,
1182
1299
  connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
1183
1300
  });
1184
- return (0, import_hwk_adapter_core3.success)(interaction.interactionId);
1301
+ return (0, import_hwk_adapter_core3.success)(operation.operationId);
1185
1302
  }
1186
- async _connectTarget(connectId, preserveInteractionId, signal) {
1303
+ async _connectTarget(connectId, preserveOperationId, signal) {
1187
1304
  debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
1188
1305
  try {
1189
1306
  this._assertConnectorReady("connectDevice");
@@ -1199,21 +1316,17 @@ var _LedgerAdapter = class _LedgerAdapter {
1199
1316
  await this._ensureDevicePermission(connectId, void 0, signal);
1200
1317
  if (signal) _LedgerAdapter._throwIfAborted(signal);
1201
1318
  if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
1202
- await this._evictAllSessions(preserveInteractionId);
1319
+ await this._evictAllSessions(preserveOperationId);
1203
1320
  } else if (this._isBleConnection()) {
1204
1321
  const previousSessionId = this._sessions.get(connectId);
1205
- this._interactions.endByConnectionKey(connectId, "explicit", preserveInteractionId);
1322
+ this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
1206
1323
  if (previousSessionId) {
1207
- this._interactions.endByConnectionKey(
1208
- previousSessionId,
1209
- "explicit",
1210
- preserveInteractionId
1211
- );
1324
+ this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
1212
1325
  this._sessions.delete(connectId);
1213
1326
  await this.connector.disconnect(previousSessionId).catch(() => void 0);
1214
1327
  }
1215
1328
  } else {
1216
- await this._evictAllSessions(preserveInteractionId);
1329
+ await this._evictAllSessions(preserveOperationId);
1217
1330
  }
1218
1331
  if (signal) _LedgerAdapter._throwIfAborted(signal);
1219
1332
  const stateGeneration = this._stateGeneration;
@@ -1250,37 +1363,37 @@ var _LedgerAdapter = class _LedgerAdapter {
1250
1363
  return failureResult;
1251
1364
  }
1252
1365
  }
1253
- async releaseInteraction(interactionId) {
1254
- const interaction = this._interactions.find(interactionId);
1255
- if (!interaction) {
1256
- this._interactions.resolve(interactionId);
1366
+ async releaseOperation(operationId) {
1367
+ const operation = this._operations.find(operationId);
1368
+ if (!operation) {
1369
+ this._operations.resolve(operationId);
1257
1370
  return;
1258
1371
  }
1259
- const endedInteraction = this._interactions.end(interactionId, "explicit");
1260
- if (!endedInteraction) return;
1261
- const { connectId } = interaction;
1372
+ const endedOperation = this._operations.end(operationId, "explicit");
1373
+ if (!endedOperation) return;
1374
+ const { connectId } = operation;
1262
1375
  debugLog("[LedgerAdapter][REQ]", {
1263
- method: "releaseInteraction",
1376
+ method: "releaseOperation",
1264
1377
  connectId,
1265
1378
  params: { connectId }
1266
1379
  });
1267
1380
  try {
1268
- await this._releaseInteractionConnection(endedInteraction);
1269
- debugLog("[LedgerAdapter][RES]", { method: "releaseInteraction", success: true });
1381
+ await this._releaseOperationConnection(endedOperation);
1382
+ debugLog("[LedgerAdapter][RES]", { method: "releaseOperation", success: true });
1270
1383
  } catch (err) {
1271
1384
  const e = err;
1272
1385
  debugLog("[LedgerAdapter][RES]", {
1273
- method: "releaseInteraction",
1386
+ method: "releaseOperation",
1274
1387
  success: false,
1275
1388
  error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
1276
1389
  });
1277
1390
  throw err;
1278
1391
  }
1279
1392
  }
1280
- async _releaseInteractionConnection(interaction) {
1393
+ async _releaseOperationConnection(operation) {
1281
1394
  const sessionIds = /* @__PURE__ */ new Set();
1282
1395
  for (const [connectId, sessionId] of this._sessions) {
1283
- if (connectId === interaction.connectId || interaction.connectionKeys.includes(connectId) || interaction.connectionKeys.includes(sessionId)) {
1396
+ if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
1284
1397
  this._sessions.delete(connectId);
1285
1398
  sessionIds.add(sessionId);
1286
1399
  }
@@ -1291,16 +1404,16 @@ var _LedgerAdapter = class _LedgerAdapter {
1291
1404
  );
1292
1405
  }
1293
1406
  }
1294
- async _releaseLostInteractionConnection(interactionId) {
1295
- const endedInteraction = this._interactions.end(interactionId, "disconnect");
1296
- if (!endedInteraction) return;
1297
- this._discoveredDevices.delete(endedInteraction.connectId);
1298
- await this._releaseInteractionConnection(endedInteraction);
1407
+ async _releaseLostOperationConnection(operationId) {
1408
+ const endedOperation = this._operations.end(operationId, "disconnect");
1409
+ if (!endedOperation) return;
1410
+ this._discoveredDevices.delete(endedOperation.connectId);
1411
+ await this._releaseOperationConnection(endedOperation);
1299
1412
  }
1300
- async getDeviceInfo(connectIdOrInteractionId, deviceId) {
1413
+ async getDeviceInfo(connectIdOrOperationId, deviceId) {
1301
1414
  let connectId;
1302
1415
  try {
1303
- connectId = (0, import_hwk_adapter_core3.isHardwareInteractionId)(connectIdOrInteractionId) ? this._interactions.resolve(connectIdOrInteractionId).connectId : connectIdOrInteractionId;
1416
+ connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
1304
1417
  } catch (error) {
1305
1418
  return this.errorToFailure(error);
1306
1419
  }
@@ -1341,9 +1454,6 @@ var _LedgerAdapter = class _LedgerAdapter {
1341
1454
  throw err;
1342
1455
  }
1343
1456
  }
1344
- getSupportedChains() {
1345
- return ["evm", "btc", "sol", "tron", "zcash"];
1346
- }
1347
1457
  // ---------------------------------------------------------------------------
1348
1458
  // Chain call helper
1349
1459
  // ---------------------------------------------------------------------------
@@ -1378,7 +1488,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1378
1488
  if (params && typeof params === "object") {
1379
1489
  const {
1380
1490
  autoInstallApp,
1381
- interactionId,
1491
+ operationId,
1382
1492
  passphraseState: _passphraseState,
1383
1493
  useEmptyPassphrase: _useEmptyPassphrase,
1384
1494
  knownConnections,
@@ -1389,7 +1499,7 @@ var _LedgerAdapter = class _LedgerAdapter {
1389
1499
  return {
1390
1500
  commonParams: {
1391
1501
  autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0,
1392
- interactionId: typeof interactionId === "string" ? interactionId : void 0,
1502
+ operationId: typeof operationId === "string" ? operationId : void 0,
1393
1503
  knownConnections,
1394
1504
  extra,
1395
1505
  allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
@@ -1718,6 +1828,20 @@ var _LedgerAdapter = class _LedgerAdapter {
1718
1828
  this.emitter.off(event, listener);
1719
1829
  }
1720
1830
  cancel(connectId) {
1831
+ const namedOperationIsLive = (id) => {
1832
+ try {
1833
+ this._operations.resolve(id);
1834
+ return true;
1835
+ } catch {
1836
+ return false;
1837
+ }
1838
+ };
1839
+ if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
1840
+ debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
1841
+ connectId
1842
+ });
1843
+ return;
1844
+ }
1721
1845
  const userAbortReason = Object.assign(new Error("User aborted operation"), {
1722
1846
  code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
1723
1847
  _tag: ERROR_TAG.UserAborted
@@ -1728,29 +1852,29 @@ var _LedgerAdapter = class _LedgerAdapter {
1728
1852
  this._lastCancelReason = void 0;
1729
1853
  }
1730
1854
  }, 2e3);
1731
- this._uiRegistry.cancel();
1732
- this._finishBleBinding("cancelled");
1733
1855
  const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
1734
- let interactionId;
1735
- if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId)) {
1736
- interactionId = connectId;
1737
- } else if (!connectId && (0, import_hwk_adapter_core3.isHardwareInteractionId)(activeJobId)) {
1738
- interactionId = activeJobId;
1856
+ let operationId;
1857
+ if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
1858
+ operationId = connectId;
1859
+ } else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
1860
+ operationId = activeJobId;
1739
1861
  }
1740
1862
  let resolvedConnectId = connectId;
1741
- if (interactionId) {
1863
+ if (operationId) {
1742
1864
  try {
1743
- resolvedConnectId = this._interactions.resolve(interactionId).connectId;
1865
+ resolvedConnectId = this._operations.resolve(operationId).connectId;
1744
1866
  } catch {
1745
1867
  resolvedConnectId = void 0;
1746
1868
  }
1747
1869
  }
1748
- const interactionForPhysicalId = !interactionId && connectId ? this._interactions.findActiveByConnectionKey(connectId) : void 0;
1749
- const queueKey = interactionId ?? (activeJobId === connectId ? connectId : interactionForPhysicalId?.interactionId) ?? connectId;
1750
- const pendingInteractionId = interactionId ?? interactionForPhysicalId?.interactionId;
1751
- if (!connectId) this._pendingInteractionBindings.clear();
1752
- else if (pendingInteractionId) {
1753
- this._pendingInteractionBindings.delete(pendingInteractionId);
1870
+ this._uiRegistry.cancel();
1871
+ this._finishBleBinding("cancelled");
1872
+ const interactionForPhysicalId = !operationId && connectId ? this._operations.findActiveByConnectionKey(connectId) : void 0;
1873
+ const queueKey = operationId ?? (activeJobId === connectId ? connectId : interactionForPhysicalId?.operationId) ?? connectId;
1874
+ const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
1875
+ if (!connectId) this._pendingOperationBindings.clear();
1876
+ else if (pendingOperationId) {
1877
+ this._pendingOperationBindings.delete(pendingOperationId);
1754
1878
  }
1755
1879
  if (queueKey) {
1756
1880
  this._jobQueue.cancelActiveAndPending(queueKey, userAbortReason);
@@ -1784,10 +1908,10 @@ var _LedgerAdapter = class _LedgerAdapter {
1784
1908
  formatDeviceMismatchError(deviceId, fingerprint)
1785
1909
  );
1786
1910
  }
1787
- if ((0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId)) {
1788
- const interaction = this._interactions.resolve(connectId);
1911
+ if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
1912
+ const operation = this._operations.resolve(connectId);
1789
1913
  await this._publishVerifiedBleBinding(
1790
- interaction.connectId,
1914
+ operation.connectId,
1791
1915
  chain,
1792
1916
  fingerprint,
1793
1917
  void 0,
@@ -1802,39 +1926,53 @@ var _LedgerAdapter = class _LedgerAdapter {
1802
1926
  }
1803
1927
  }
1804
1928
  /** Discovery may select a BLE target before a later call verifies its wallet. */
1805
- async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, interactionId, previousConnectId = "", signal) {
1806
- const binding = interactionId ? this._pendingInteractionBindings.get(interactionId) : attempt;
1807
- if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) return;
1808
- const acknowledged = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
1809
- this.emitter,
1810
- this._uiRegistry,
1811
- {
1812
- selectionRequestId: binding.selectedConnection.requestId,
1813
- connection: { transport: "ble", connectId },
1814
- identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
1815
- extra: binding.extra
1816
- },
1817
- signal
1818
- );
1819
- if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
1820
- this._bindingSelectionRequestId = void 0;
1821
- }
1822
- if (interactionId) {
1823
- this._interactions.resolve(interactionId);
1824
- this._pendingInteractionBindings.delete(interactionId);
1929
+ async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, operationId, signal) {
1930
+ const binding = operationId ? this._pendingOperationBindings.get(operationId) : attempt;
1931
+ if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) {
1932
+ return false;
1825
1933
  }
1826
- if (acknowledged) return;
1827
- this.emitter.emit(import_hwk_adapter_core3.DEVICE.LEDGER_CONNECTION_VERIFIED, {
1828
- type: import_hwk_adapter_core3.DEVICE.LEDGER_CONNECTION_VERIFIED,
1829
- payload: {
1830
- previousConnectId: binding.previousConnectId ?? previousConnectId,
1831
- connectId,
1832
- chain,
1833
- fingerprint,
1834
- extra: binding.extra,
1835
- selectionRequestId: binding.selectedConnection.requestId
1934
+ try {
1935
+ const outcome = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
1936
+ this.emitter,
1937
+ this._uiRegistry,
1938
+ {
1939
+ selectionRequestId: binding.selectedConnection.requestId,
1940
+ connection: { transport: "ble", connectId },
1941
+ identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
1942
+ extra: binding.extra
1943
+ },
1944
+ signal
1945
+ );
1946
+ if (operationId) this._operations.resolve(operationId);
1947
+ if (!outcome.saved) {
1948
+ debugLog("[LedgerAdapter] BLE binding not persisted by host", {
1949
+ connectId,
1950
+ reason: outcome.reason
1951
+ });
1836
1952
  }
1837
- });
1953
+ return outcome.saved;
1954
+ } catch (error) {
1955
+ if (operationId) {
1956
+ this._pendingOperationBindings.delete(operationId);
1957
+ this._operations.end(operationId, "explicit");
1958
+ }
1959
+ const sessionId = this._sessions.get(connectId);
1960
+ this._sessions.delete(connectId);
1961
+ if (sessionId) {
1962
+ const teardown = this._runConnectorTeardown(
1963
+ () => this.connector.disconnect(sessionId)
1964
+ ).catch(() => void 0);
1965
+ if (!signal?.aborted) await teardown;
1966
+ }
1967
+ throw error;
1968
+ } finally {
1969
+ if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
1970
+ this._bindingSelectionRequestId = void 0;
1971
+ }
1972
+ if (operationId) {
1973
+ this._pendingOperationBindings.delete(operationId);
1974
+ }
1975
+ }
1838
1976
  }
1839
1977
  /** Verify on the acquired session without re-entering the job queue. */
1840
1978
  async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
@@ -2006,7 +2144,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2006
2144
  // Layer 1 entry. Caller signal only races the outer awaiter; the shared
2007
2145
  // `_doConnect` runs under its own internal controller so caller A's cancel
2008
2146
  // doesn't kill caller B's await.
2009
- async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveInteractionId, context) {
2147
+ async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveOperationId, context) {
2010
2148
  if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
2011
2149
  this._assertConnectorReady("connectDevice");
2012
2150
  if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
@@ -2036,7 +2174,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2036
2174
  innerSignal,
2037
2175
  connectId,
2038
2176
  allowUsbEphemeralFallback,
2039
- preserveInteractionId,
2177
+ preserveOperationId,
2040
2178
  context
2041
2179
  );
2042
2180
  } finally {
@@ -2052,7 +2190,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2052
2190
  // Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
2053
2191
  // Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
2054
2192
  // throw DeviceNotFound so the user is kicked out of the loop.
2055
- async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveInteractionId, context) {
2193
+ async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveOperationId, context) {
2056
2194
  _LedgerAdapter._throwIfAborted(internalSignal);
2057
2195
  if (this.connector.availableTransports?.includes("usb") && this.connector.availableTransports.includes("ble")) {
2058
2196
  this._activeConnectionType = "usb";
@@ -2067,7 +2205,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2067
2205
  usbDevices,
2068
2206
  usbTarget,
2069
2207
  allowUsbEphemeralFallback,
2070
- preserveInteractionId,
2208
+ preserveOperationId,
2071
2209
  context,
2072
2210
  internalSignal
2073
2211
  );
@@ -2077,24 +2215,26 @@ var _LedgerAdapter = class _LedgerAdapter {
2077
2215
  (connection) => connection.transport === "ble"
2078
2216
  );
2079
2217
  if (knownBle?.transport === "ble") {
2080
- return this._connectDeviceOrThrow(
2081
- knownBle.connectId,
2082
- preserveInteractionId,
2083
- internalSignal
2084
- );
2218
+ return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
2219
+ }
2220
+ if (targetConnectId && context?.knownConnections === void 0) {
2221
+ throw (0, import_hwk_adapter_core3.createHwkError)({
2222
+ code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
2223
+ message: "Ledger connection metadata is required before starting Bluetooth binding"
2224
+ });
2085
2225
  }
2086
2226
  const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
2087
2227
  return this._connectFirstOrSelect(
2088
2228
  bleDevices,
2089
2229
  void 0,
2090
2230
  allowUsbEphemeralFallback,
2091
- preserveInteractionId,
2231
+ preserveOperationId,
2092
2232
  context,
2093
2233
  internalSignal
2094
2234
  );
2095
2235
  }
2096
2236
  if (this._isBleConnection() && targetConnectId) {
2097
- return this._connectDeviceOrThrow(targetConnectId, preserveInteractionId, internalSignal);
2237
+ return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
2098
2238
  }
2099
2239
  let confirms = 0;
2100
2240
  while (!internalSignal.aborted) {
@@ -2121,7 +2261,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2121
2261
  devices,
2122
2262
  targetConnectId,
2123
2263
  allowUsbEphemeralFallback,
2124
- preserveInteractionId,
2264
+ preserveOperationId,
2125
2265
  context,
2126
2266
  internalSignal
2127
2267
  );
@@ -2152,20 +2292,20 @@ var _LedgerAdapter = class _LedgerAdapter {
2152
2292
  _LedgerAdapter._throwIfAborted(internalSignal);
2153
2293
  throw new Error("_doConnect aborted");
2154
2294
  }
2155
- async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback = false, preserveInteractionId, context, signal) {
2156
- if (signal) _LedgerAdapter._throwIfAborted(signal);
2295
+ async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback, preserveOperationId, context, signal) {
2296
+ _LedgerAdapter._throwIfAborted(signal);
2157
2297
  if (targetConnectId) {
2158
2298
  const target = devices.find(
2159
2299
  (d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
2160
2300
  );
2161
2301
  if (target) {
2162
- return this._connectDeviceOrThrow(target.connectId, preserveInteractionId, signal);
2302
+ return this._connectDeviceOrThrow(target.connectId, preserveOperationId, signal);
2163
2303
  }
2164
2304
  if (!this._isBleConnection() && devices.length === 1 && allowUsbEphemeralFallback) {
2165
2305
  debugLog(
2166
2306
  `[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
2167
2307
  );
2168
- return this._connectDeviceOrThrow(devices[0].connectId, preserveInteractionId, signal);
2308
+ return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
2169
2309
  }
2170
2310
  if (!this._isBleConnection() || !allowUsbEphemeralFallback) {
2171
2311
  const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
@@ -2186,11 +2326,26 @@ var _LedgerAdapter = class _LedgerAdapter {
2186
2326
  if (requiresBleSelection && context?.allowDeviceSelection !== false) {
2187
2327
  const bindingSessionId = context?.bindingSessionId ?? this._uiRegistry.createRequestId();
2188
2328
  if (context) context.bindingSessionId = bindingSessionId;
2329
+ const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
2330
+ const knownUsb = context?.knownConnections?.find(
2331
+ (connection) => connection.transport === "usb"
2332
+ );
2333
+ const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
2189
2334
  const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
2190
2335
  emitter: this.emitter,
2191
2336
  registry: this._uiRegistry,
2192
- signal: signal ?? new AbortController().signal,
2193
- scan: async () => (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
2337
+ signal,
2338
+ allowUsbFallback,
2339
+ scan: async () => {
2340
+ if (allowUsbFallback) {
2341
+ const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
2342
+ const candidate = usbDevices.find(
2343
+ (device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
2344
+ ) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
2345
+ if (candidate) return [candidate];
2346
+ }
2347
+ return (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId));
2348
+ },
2194
2349
  request: {
2195
2350
  devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
2196
2351
  bindingSessionId,
@@ -2198,14 +2353,25 @@ var _LedgerAdapter = class _LedgerAdapter {
2198
2353
  context: {
2199
2354
  kind: "bind-connection",
2200
2355
  transport: "ble",
2201
- reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
2356
+ reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
2202
2357
  },
2203
2358
  extra: context?.extra
2204
2359
  }
2205
2360
  });
2361
+ if (device.connectionType === "usb") {
2362
+ this._activeConnectionType = "usb";
2363
+ if (context) context.selectedConnection = void 0;
2364
+ if (preserveOperationId) this._pendingOperationBindings.delete(preserveOperationId);
2365
+ this._bindingSelectionRequestId = void 0;
2366
+ this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
2367
+ type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
2368
+ payload: { selectionRequestId: requestId, status: "cancelled" }
2369
+ });
2370
+ return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2371
+ }
2206
2372
  if (context) context.selectedConnection = { connectId: device.connectId, requestId };
2207
2373
  this._bindingSelectionRequestId = requestId;
2208
- return this._connectDeviceOrThrow(device.connectId, preserveInteractionId, signal);
2374
+ return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
2209
2375
  }
2210
2376
  if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
2211
2377
  if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
@@ -2242,17 +2408,17 @@ var _LedgerAdapter = class _LedgerAdapter {
2242
2408
  }
2243
2409
  if (context && requiresBleSelection)
2244
2410
  context.selectedConnection = { connectId: selected.connectId, requestId };
2245
- return this._connectDeviceOrThrow(selected.connectId, preserveInteractionId, signal);
2411
+ return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
2246
2412
  }
2247
2413
  if (devices.length !== 1) {
2248
2414
  throw Object.assign(new Error("Ledger device not found."), {
2249
2415
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
2250
2416
  });
2251
2417
  }
2252
- return this._connectDeviceOrThrow(devices[0].connectId, preserveInteractionId, signal);
2418
+ return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
2253
2419
  }
2254
- async _connectDeviceOrThrow(chosenConnectId, preserveInteractionId, signal) {
2255
- const result = await this._connectTarget(chosenConnectId, preserveInteractionId, signal);
2420
+ async _connectDeviceOrThrow(chosenConnectId, preserveOperationId, signal) {
2421
+ const result = await this._connectTarget(chosenConnectId, preserveOperationId, signal);
2256
2422
  if (!result.success) {
2257
2423
  const payload = result.payload;
2258
2424
  const rethrow = Object.assign(new Error(payload.error), {
@@ -2294,6 +2460,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2294
2460
  */
2295
2461
  async _callConnector(sessionId, method, params, signal) {
2296
2462
  this._assertConnectorReady(method);
2463
+ if (signal?.aborted) throw this._abortReason(signal);
2297
2464
  const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
2298
2465
  let promise;
2299
2466
  try {
@@ -2358,32 +2525,32 @@ var _LedgerAdapter = class _LedgerAdapter {
2358
2525
  };
2359
2526
  }
2360
2527
  async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
2361
- const positionalInteractionId = (0, import_hwk_adapter_core3.isHardwareInteractionId)(connectId) ? connectId : void 0;
2362
- if (positionalInteractionId && commonParams?.interactionId && positionalInteractionId !== commonParams.interactionId) {
2528
+ const positionalOperationId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) ? connectId : void 0;
2529
+ if (positionalOperationId && commonParams?.operationId && positionalOperationId !== commonParams.operationId) {
2363
2530
  throw (0, import_hwk_adapter_core3.createHwkError)({
2364
2531
  code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
2365
- message: "Conflicting Ledger interaction ids",
2532
+ message: "Conflicting Ledger operation ids",
2366
2533
  params: {
2367
- positionalInteractionId,
2368
- commonInteractionId: commonParams.interactionId
2534
+ positionalOperationId,
2535
+ commonOperationId: commonParams.operationId
2369
2536
  }
2370
2537
  });
2371
2538
  }
2372
- const interactionId = commonParams?.interactionId ?? positionalInteractionId;
2373
- const interaction = interactionId ? this._interactions.resolve(interactionId) : void 0;
2374
- const releaseInteractionRetention = interactionId ? this._interactions.retain(interactionId) : void 0;
2375
- const effectiveConnectId = interaction?.connectId ?? connectId;
2539
+ const operationId = commonParams?.operationId ?? positionalOperationId;
2540
+ const operation = operationId ? this._operations.resolve(operationId) : void 0;
2541
+ const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
2542
+ const effectiveConnectId = operation?.connectId ?? connectId;
2376
2543
  debugLog("[LedgerAdapter][REQ]", {
2377
2544
  method,
2378
2545
  connectId: effectiveConnectId || "(empty)",
2379
2546
  params
2380
2547
  });
2381
- const queueKey = (interactionId ?? effectiveConnectId) || "__ledger_default__";
2548
+ const queueKey = (operationId ?? effectiveConnectId) || "__ledger_default__";
2382
2549
  try {
2383
2550
  const result = await this._jobQueue.enqueue(
2384
2551
  queueKey,
2385
2552
  async (signal) => {
2386
- if (interactionId) this._activeInteractionJobs.add(interactionId);
2553
+ if (operationId) this._activeOperationJobs.add(operationId);
2387
2554
  try {
2388
2555
  return await this._runConnectorCall(
2389
2556
  effectiveConnectId,
@@ -2394,16 +2561,16 @@ var _LedgerAdapter = class _LedgerAdapter {
2394
2561
  permissionDeviceId,
2395
2562
  commonParams,
2396
2563
  installContext ?? {},
2397
- interactionId
2564
+ operationId
2398
2565
  );
2399
2566
  } catch (error) {
2400
2567
  this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
2401
2568
  throw error;
2402
2569
  } finally {
2403
- if (interactionId) {
2404
- this._activeInteractionJobs.delete(interactionId);
2405
- if (this._pendingInteractionDisconnects.delete(interactionId)) {
2406
- await this._releaseLostInteractionConnection(interactionId);
2570
+ if (operationId) {
2571
+ this._activeOperationJobs.delete(operationId);
2572
+ if (this._pendingOperationDisconnects.delete(operationId)) {
2573
+ await this._releaseLostOperationConnection(operationId);
2407
2574
  }
2408
2575
  }
2409
2576
  }
@@ -2429,15 +2596,19 @@ var _LedgerAdapter = class _LedgerAdapter {
2429
2596
  });
2430
2597
  throw err;
2431
2598
  } finally {
2432
- releaseInteractionRetention?.();
2599
+ releaseOperationRetention?.();
2433
2600
  }
2434
2601
  }
2435
2602
  /**
2436
2603
  * Race a promise against an abort signal. On abort, rejects with
2437
2604
  * signal.reason → instance _lastCancelReason → generic Error('Aborted').
2438
2605
  */
2606
+ /** Hermes/RN polyfills don't always populate signal.reason; fall back. */
2607
+ _abortReason(signal) {
2608
+ return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2609
+ }
2439
2610
  _abortable(signal, promise) {
2440
- const getAbortReason = () => signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
2611
+ const getAbortReason = () => this._abortReason(signal);
2441
2612
  if (signal.aborted) {
2442
2613
  void promise.catch(() => void 0);
2443
2614
  return Promise.reject(getAbortReason());
@@ -2466,9 +2637,9 @@ var _LedgerAdapter = class _LedgerAdapter {
2466
2637
  }
2467
2638
  }
2468
2639
  /** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
2469
- async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext, interactionId, lockedRetryBudget = _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET) {
2640
+ async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext, operationId, lockedRetryBudget = _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET) {
2470
2641
  _LedgerAdapter._throwIfAborted(signal);
2471
- if (!interactionId) {
2642
+ if (!operationId) {
2472
2643
  await this._ensureDevicePermission(
2473
2644
  connectId,
2474
2645
  permissionDeviceId ?? fingerprint?.deviceId,
@@ -2504,7 +2675,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2504
2675
  message: "Ledger all-network connection ended"
2505
2676
  });
2506
2677
  }
2507
- let resolvedConnectId = interactionId ? this._interactions.resolve(interactionId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
2678
+ let resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
2508
2679
  preferredConnectId,
2509
2680
  signal,
2510
2681
  allowUsbEphemeralFallback,
@@ -2516,12 +2687,12 @@ var _LedgerAdapter = class _LedgerAdapter {
2516
2687
  installContext.connection = { connectId: resolvedConnectId, sessionId };
2517
2688
  }
2518
2689
  if (!sessionId) {
2519
- if (interactionId) {
2520
- this._interactions.end(interactionId, "disconnect");
2690
+ if (operationId) {
2691
+ this._operations.end(operationId, "disconnect");
2521
2692
  throw (0, import_hwk_adapter_core3.createHwkError)({
2522
- code: import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded,
2523
- message: "Ledger interaction connection is no longer active",
2524
- params: { interactionId, reason: "disconnect" }
2693
+ code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
2694
+ message: "Ledger operation connection is no longer active",
2695
+ params: { operationId, reason: "disconnect" }
2525
2696
  });
2526
2697
  }
2527
2698
  throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
@@ -2540,7 +2711,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2540
2711
  )
2541
2712
  );
2542
2713
  if (fp.success) break;
2543
- const binding = interactionId ? this._pendingInteractionBindings.get(interactionId) : connectionAttempt;
2714
+ const binding = operationId ? this._pendingOperationBindings.get(operationId) : connectionAttempt;
2544
2715
  if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
2545
2716
  throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
2546
2717
  code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
@@ -2551,13 +2722,13 @@ var _LedgerAdapter = class _LedgerAdapter {
2551
2722
  binding.rejectedConnectId = resolvedConnectId;
2552
2723
  this._sessions.delete(resolvedConnectId);
2553
2724
  await this.connector.disconnect(sessionId);
2554
- if (interactionId) this._pendingInteractionDisconnects.delete(interactionId);
2725
+ if (operationId) this._pendingOperationDisconnects.delete(operationId);
2555
2726
  _LedgerAdapter._throwIfAborted(signal);
2556
2727
  resolvedConnectId = await this._connectFirstOrSelect(
2557
2728
  [],
2558
2729
  void 0,
2559
2730
  true,
2560
- interactionId,
2731
+ operationId,
2561
2732
  binding,
2562
2733
  signal
2563
2734
  );
@@ -2569,8 +2740,8 @@ var _LedgerAdapter = class _LedgerAdapter {
2569
2740
  message: "Selected Ledger connection ended"
2570
2741
  });
2571
2742
  sessionId = selectedSession;
2572
- if (interactionId)
2573
- this._interactions.rebind(interactionId, {
2743
+ if (operationId)
2744
+ this._operations.rebind(operationId, {
2574
2745
  connectId: resolvedConnectId,
2575
2746
  device: selectedDevice,
2576
2747
  connectionKeys: [sessionId]
@@ -2578,22 +2749,21 @@ var _LedgerAdapter = class _LedgerAdapter {
2578
2749
  if (installContext)
2579
2750
  installContext.connection = { connectId: resolvedConnectId, sessionId };
2580
2751
  }
2581
- if (!interactionId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
2582
- this._verifiedBleReconnectTargets.set(connectId, {
2583
- connectId: resolvedConnectId,
2584
- chain: fingerprint.chain,
2585
- fingerprint: fingerprint.deviceId
2586
- });
2587
- }
2588
2752
  await this._publishVerifiedBleBinding(
2589
2753
  resolvedConnectId,
2590
2754
  fingerprint.chain,
2591
2755
  fingerprint.deviceId,
2592
2756
  connectionAttempt,
2593
- interactionId,
2594
- connectId,
2757
+ operationId,
2595
2758
  signal
2596
2759
  );
2760
+ if (!operationId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
2761
+ this._verifiedBleReconnectTargets.set(connectId, {
2762
+ connectId: resolvedConnectId,
2763
+ chain: fingerprint.chain,
2764
+ fingerprint: fingerprint.deviceId
2765
+ });
2766
+ }
2597
2767
  }
2598
2768
  businessCallStarted = true;
2599
2769
  return await this._callConnector(sessionId, method, effectiveParams, signal);
@@ -2601,17 +2771,17 @@ var _LedgerAdapter = class _LedgerAdapter {
2601
2771
  if (signal.aborted) throw err;
2602
2772
  if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
2603
2773
  this._discoveredDevices.delete(resolvedConnectId);
2604
- if (interactionId) await this._releaseLostInteractionConnection(interactionId);
2774
+ if (operationId) await this._releaseLostOperationConnection(operationId);
2605
2775
  else {
2606
2776
  this._sessions.delete(resolvedConnectId);
2607
2777
  await this.connector.disconnect(sessionId).catch(() => void 0);
2608
2778
  }
2609
2779
  const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
2610
- const interactionParams = interactionId ? { interactionId, reason: "disconnect" } : void 0;
2780
+ const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
2611
2781
  throw (0, import_hwk_adapter_core3.createHwkError)({
2612
- code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : mapLedgerError(err).code,
2782
+ code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
2613
2783
  message: "Ledger operation connection was lost; start a new operation",
2614
- params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { interactionId }) : interactionParams,
2784
+ params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
2615
2785
  recovery: ambiguous ? { scope: "unknown" } : void 0
2616
2786
  });
2617
2787
  }
@@ -2630,7 +2800,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2630
2800
  await this._waitForDeviceConnect(signal);
2631
2801
  if (this._sessions.get(resolvedConnectId) !== sessionId) {
2632
2802
  throw (0, import_hwk_adapter_core3.createHwkError)({
2633
- code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2803
+ code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2634
2804
  message: "Ledger connection ended while waiting for unlock"
2635
2805
  });
2636
2806
  }
@@ -2643,7 +2813,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2643
2813
  permissionDeviceId,
2644
2814
  commonParams,
2645
2815
  installContext,
2646
- interactionId,
2816
+ operationId,
2647
2817
  lockedRetryBudget - 1
2648
2818
  );
2649
2819
  }
@@ -2651,7 +2821,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2651
2821
  await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
2652
2822
  if (this._sessions.get(resolvedConnectId) !== sessionId) {
2653
2823
  throw (0, import_hwk_adapter_core3.createHwkError)({
2654
- code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2824
+ code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
2655
2825
  message: "Ledger connection ended during the app transition"
2656
2826
  });
2657
2827
  }
@@ -2660,26 +2830,26 @@ var _LedgerAdapter = class _LedgerAdapter {
2660
2830
  } catch (retryErr) {
2661
2831
  if (isStuckAppStateError(retryErr)) throw err;
2662
2832
  if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
2663
- if (interactionId) await this._releaseLostInteractionConnection(interactionId);
2833
+ if (operationId) await this._releaseLostOperationConnection(operationId);
2664
2834
  else {
2665
2835
  this._sessions.delete(resolvedConnectId);
2666
2836
  this._discoveredDevices.delete(resolvedConnectId);
2667
2837
  await this.connector.disconnect(sessionId).catch(() => void 0);
2668
2838
  }
2669
2839
  throw (0, import_hwk_adapter_core3.createHwkError)({
2670
- code: interactionId ? import_hwk_adapter_core3.HardwareErrorCode.InteractionEnded : mapLedgerError(retryErr).code,
2840
+ code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
2671
2841
  message: `Ledger ${method} may have completed before the connection was lost`,
2672
2842
  params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
2673
- interactionId,
2843
+ operationId,
2674
2844
  reason: "disconnect"
2675
- }) : { interactionId, reason: "disconnect" },
2845
+ }) : { operationId, reason: "disconnect" },
2676
2846
  recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
2677
2847
  });
2678
2848
  }
2679
2849
  throw retryErr;
2680
2850
  }
2681
2851
  }
2682
- if (!interactionId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
2852
+ if (!operationId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
2683
2853
  this._sessions.delete(resolvedConnectId);
2684
2854
  this._discoveredDevices.delete(resolvedConnectId);
2685
2855
  await this.connector.disconnect(sessionId).catch(() => void 0);
@@ -2741,7 +2911,7 @@ var _LedgerAdapter = class _LedgerAdapter {
2741
2911
  permissionDeviceId,
2742
2912
  commonParams,
2743
2913
  installContext,
2744
- interactionId
2914
+ operationId
2745
2915
  );
2746
2916
  }
2747
2917
  }
@@ -2894,7 +3064,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
2894
3064
  var LedgerAdapter = _LedgerAdapter;
2895
3065
 
2896
3066
  // src/connector/LedgerConnectorBase.ts
2897
- var import_hwk_adapter_core14 = require("@onekeyfe/hwk-adapter-core");
3067
+ var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
2898
3068
 
2899
3069
  // src/device/LedgerDeviceManager.ts
2900
3070
  var LedgerDeviceManager = class {
@@ -4124,360 +4294,115 @@ async function _createZcashSigner(ctx, sessionId) {
4124
4294
  }
4125
4295
 
4126
4296
  // src/connector/chains/tron.ts
4127
- var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
4128
- var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
4129
-
4130
- // src/connector/chains/legacyChainCall.ts
4131
- var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
4132
-
4133
- // src/app/AppManager.ts
4134
- var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
4135
4297
  var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
4136
- var APP_NAME_MAP = {
4137
- ETH: "Ethereum",
4138
- BTC: "Bitcoin",
4139
- SOL: "Solana",
4140
- TRX: "Tron",
4141
- ZEC: "Zcash",
4142
- XRP: "XRP",
4143
- ADA: "Cardano",
4144
- DOT: "Polkadot",
4145
- ATOM: "Cosmos"
4146
- };
4147
- var DASHBOARD_APP_NAME = "BOLOS";
4148
- var AppManager = class {
4149
- constructor(dmk, options) {
4150
- this._dmk = dmk;
4151
- this._waitMs = options?.waitMs ?? 1e3;
4152
- this._maxRetries = options?.maxRetries ?? 10;
4298
+
4299
+ // src/signer/SignerTron.ts
4300
+ var SignerTron = class {
4301
+ // eslint-disable-next-line no-useless-constructor, no-empty-function
4302
+ constructor(_sdk) {
4303
+ this._sdk = _sdk;
4153
4304
  }
4154
- /**
4155
- * Return the Ledger app name for a given chain ticker,
4156
- * or undefined if the chain is not supported.
4157
- */
4158
- static getAppName(chain) {
4159
- return APP_NAME_MAP[chain];
4305
+ /** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
4306
+ async getAddress(derivationPath, options) {
4307
+ const action = this._sdk.getAddress(derivationPath, options);
4308
+ const result = await deviceActionToPromise(
4309
+ action,
4310
+ this.onInteraction,
4311
+ void 0,
4312
+ this.onRegisterCanceller
4313
+ );
4314
+ return { address: result.address, publicKey: result.publicKey };
4160
4315
  }
4161
- /**
4162
- * Ensure the target app is open on the device identified by `sessionId`.
4163
- *
4164
- * Flow:
4165
- * 1. Check the currently running app.
4166
- * 2. If it is already the target, return immediately.
4167
- * 3. If a different app is running (not dashboard), close it first.
4168
- * 4. Open the target app.
4169
- * 5. Poll until the device confirms the target app is running.
4170
- */
4171
- /**
4172
- * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
4173
- * device is about to display "Open <app>" on screen and wait for the
4174
- * user's button press. UI consumers should show their "open app" prompt
4175
- * in response. NOT called when the target app is already open (no user
4176
- * interaction needed in that case).
4177
- *
4178
- * Important: OpenAppCommand is blocking. It does not resolve until the user
4179
- * has physically confirmed on the device, so anything that runs AFTER
4180
- * `await this._openApp(...)` lands AFTER the prompt is already gone.
4181
- * Hence the callback must fire BEFORE that await.
4182
- */
4183
- async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
4184
- const currentApp = await this._getCurrentApp(sessionId);
4185
- if (currentApp === targetAppName) {
4186
- return;
4187
- }
4188
- if (!this._isDashboard(currentApp)) {
4189
- await this._closeCurrentApp(sessionId);
4190
- await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
4191
- }
4192
- onConfirmOnDevice?.();
4193
- await this._openApp(sessionId, targetAppName);
4194
- await this._waitForApp(sessionId, targetAppName);
4316
+ /** Sign a protobuf-encoded raw transaction. */
4317
+ async signTransaction(derivationPath, transaction, options) {
4318
+ const action = this._sdk.signTransaction(derivationPath, transaction, options);
4319
+ return deviceActionToPromise(
4320
+ action,
4321
+ this.onInteraction,
4322
+ void 0,
4323
+ this.onRegisterCanceller
4324
+ );
4195
4325
  }
4196
- // ---------------------------------------------------------------------------
4197
- // Private helpers
4198
- // ---------------------------------------------------------------------------
4199
- async _getCurrentApp(sessionId) {
4200
- const result = await this._dmk.sendCommand({
4201
- sessionId,
4202
- command: new import_device_management_kit2.GetAppAndVersionCommand()
4203
- });
4204
- if ((0, import_device_management_kit2.isSuccessCommandResult)(result)) {
4205
- debugLog("[AppManager] currentApp:", result.data.name);
4206
- return result.data.name;
4207
- }
4208
- const errResult = result;
4209
- const dmkErr = errResult.error ?? {};
4210
- const original = dmkErr.originalError;
4211
- debugLog(
4212
- "[AppManager] _getCurrentApp failed sessionId=",
4213
- sessionId,
4214
- "tag=",
4215
- dmkErr._tag,
4216
- "errorCode=",
4217
- dmkErr.errorCode,
4218
- "message=",
4219
- dmkErr.message,
4220
- "originalErrorMessage=",
4221
- original?.message ?? String(original ?? "")
4326
+ /** Sign a personal message (TIP-191). */
4327
+ async signPersonalMessage(derivationPath, message, options) {
4328
+ const action = this._sdk.signPersonalMessage(derivationPath, message, options);
4329
+ return deviceActionToPromise(
4330
+ action,
4331
+ this.onInteraction,
4332
+ void 0,
4333
+ this.onRegisterCanceller
4222
4334
  );
4335
+ }
4336
+ };
4337
+
4338
+ // src/connector/chains/tron.ts
4339
+ async function tronGetAddress(ctx, sessionId, params) {
4340
+ const tronSigner = await _createTronSigner(ctx, sessionId);
4341
+ const path = normalizePath(params.path);
4342
+ try {
4343
+ const result = await tronSigner.getAddress(path, {
4344
+ checkOnDevice: params.showOnDevice ?? false
4345
+ });
4346
+ return { address: result.address, publicKey: result.publicKey, path: params.path };
4347
+ } catch (err) {
4348
+ ctx.invalidateSession(sessionId);
4349
+ throw ctx.wrapError(err);
4350
+ } finally {
4351
+ ctx.clearCanceller(sessionId);
4352
+ }
4353
+ }
4354
+ async function tronSignTransaction(ctx, sessionId, params) {
4355
+ if (!params.rawTxHex) {
4223
4356
  throw Object.assign(
4224
- new Error(
4225
- dmkErr.message ?? "Failed to get current app from device"
4226
- ),
4227
- {
4228
- _tag: dmkErr._tag,
4229
- errorCode: dmkErr.errorCode,
4230
- originalError: original
4231
- }
4357
+ new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
4358
+ { code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
4232
4359
  );
4233
4360
  }
4234
- async _openApp(sessionId, appName) {
4235
- const result = await this._dmk.sendCommand({
4236
- sessionId,
4237
- command: new import_device_management_kit2.OpenAppCommand({ appName })
4238
- });
4239
- if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
4240
- const dmkErr = result.error;
4241
- const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
4242
- const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
4243
- debugLog(
4244
- "[AppManager] openApp failed:",
4245
- appName,
4246
- "errorCode:",
4247
- errorCode,
4248
- "tag:",
4249
- dmkErr._tag
4250
- );
4251
- let code;
4252
- if (errorCode === "6807" || /unknown application/i.test(message)) {
4253
- code = import_hwk_adapter_core11.HardwareErrorCode.AppNotInstalled;
4254
- } else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
4255
- code = import_hwk_adapter_core11.HardwareErrorCode.UserRejected;
4256
- }
4257
- throw Object.assign(new Error(`Failed to open "${appName}"`), {
4258
- _tag: ERROR_TAG.OpenAppCommand,
4259
- code,
4260
- errorCode,
4261
- statusCode: errorCode,
4262
- appName,
4263
- originalError: dmkErr
4264
- });
4265
- }
4266
- }
4267
- async _closeCurrentApp(sessionId) {
4268
- debugLog("[AppManager] closeCurrentApp");
4269
- await this._dmk.sendCommand({
4270
- sessionId,
4271
- command: new import_device_management_kit2.CloseAppCommand()
4272
- });
4273
- }
4274
- /**
4275
- * Poll the device until the expected app is reported as running,
4276
- * or throw after `_maxRetries` attempts.
4277
- */
4278
- async _waitForApp(sessionId, expectedAppName) {
4279
- let lastSeen = "";
4280
- for (let i = 0; i < this._maxRetries; i++) {
4281
- await this._wait();
4282
- const current = await this._getCurrentApp(sessionId);
4283
- lastSeen = current;
4284
- if (current === expectedAppName) {
4285
- return;
4286
- }
4287
- }
4288
- debugLog(
4289
- "[AppManager] waitForApp exhausted: expected=",
4290
- expectedAppName,
4291
- "lastSeen=",
4292
- lastSeen
4293
- );
4294
- throw new Error(
4295
- `Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
4296
- );
4297
- }
4298
- _isDashboard(appName) {
4299
- return appName === DASHBOARD_APP_NAME;
4300
- }
4301
- _wait() {
4302
- return new Promise((resolve) => setTimeout(resolve, this._waitMs));
4303
- }
4304
- };
4305
-
4306
- // src/connector/chains/legacyChainCall.ts
4307
- function isLegacyWrongAppError(err, _appName) {
4308
- return isWrongAppError(err);
4309
- }
4310
- async function withLegacyChainCall(ctx, sessionId, options, action) {
4311
- const { appName, needsConfirmation } = options;
4312
- let openAppPromptShown = false;
4313
- const onAppOpenPrompt = () => {
4314
- openAppPromptShown = true;
4315
- ctx.emit("ui-event", {
4316
- type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOpenApp,
4317
- payload: { sessionId }
4318
- });
4319
- };
4320
- const closeOpenAppUiIfShown = () => {
4321
- if (openAppPromptShown) {
4322
- ctx.emit("ui-event", {
4323
- type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
4324
- payload: { sessionId }
4325
- });
4326
- openAppPromptShown = false;
4327
- }
4328
- };
4329
- try {
4330
- await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
4331
- } catch (err) {
4332
- debugLog(
4333
- "[LegacyChainCall] pre-flight ensureAppOpen failed:",
4334
- appName,
4335
- err?.message
4336
- );
4337
- closeOpenAppUiIfShown();
4338
- throw ctx.wrapError(err, { defaultAppName: appName });
4339
- }
4340
- const runOnce = async () => {
4341
- let confirmEmitted = false;
4342
- if (needsConfirmation) {
4343
- ctx.emit("ui-event", {
4344
- type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOnDevice,
4345
- payload: { sessionId }
4346
- });
4347
- confirmEmitted = true;
4348
- }
4349
- try {
4350
- return await action(sessionId);
4351
- } finally {
4352
- if (confirmEmitted || openAppPromptShown) {
4353
- ctx.emit("ui-event", {
4354
- type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
4355
- payload: { sessionId }
4356
- });
4357
- openAppPromptShown = false;
4358
- }
4359
- }
4360
- };
4361
+ const tronSigner = await _createTronSigner(ctx, sessionId);
4362
+ const path = normalizePath(params.path);
4361
4363
  try {
4362
- return await runOnce();
4364
+ const signature = await tronSigner.signTransaction(path, (0, import_hwk_adapter_core11.hexToBytes)(params.rawTxHex));
4365
+ return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4363
4366
  } catch (err) {
4364
- if (!isLegacyWrongAppError(err, appName)) {
4365
- debugLog("[LegacyChainCall] non-wrong-app failure:", appName, err?.message);
4366
- ctx.invalidateSession(sessionId);
4367
- throw ctx.wrapError(err, { defaultAppName: appName });
4368
- }
4369
- debugLog("[LegacyChainCall] wrong-app detected, retrying:", appName);
4370
- try {
4371
- await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
4372
- } catch (switchErr) {
4373
- debugLog(
4374
- "[LegacyChainCall] retry ensureAppOpen failed:",
4375
- appName,
4376
- switchErr?.message
4377
- );
4378
- closeOpenAppUiIfShown();
4379
- throw ctx.wrapError(switchErr, { defaultAppName: appName });
4380
- }
4381
- ctx.clearAllSigners();
4382
- const result = await runOnce();
4383
- debugLog("[LegacyChainCall] retry succeeded:", appName);
4384
- return result;
4385
- }
4386
- }
4387
- async function _ensureAppOpen(ctx, sessionId, appName, onPrompt) {
4388
- const dmk = await ctx.getOrCreateDmk();
4389
- const appManager = new AppManager(dmk);
4390
- await appManager.ensureAppOpen(sessionId, appName, onPrompt);
4391
- }
4392
-
4393
- // src/transport/DmkTransport.ts
4394
- var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
4395
- var DmkTransport = class extends import_hw_transport.default {
4396
- constructor(dmk, sessionId) {
4397
- super();
4398
- this._dmk = dmk;
4399
- this._sessionId = sessionId;
4400
- }
4401
- async exchange(apdu) {
4402
- const response = await this._dmk.sendApdu({
4403
- sessionId: this._sessionId,
4404
- apdu: new Uint8Array(apdu)
4405
- });
4406
- const { data, statusCode } = response;
4407
- const result = Buffer.alloc(data.length + 2);
4408
- if (data.length > 0) {
4409
- result.set(data, 0);
4410
- }
4411
- result.set(statusCode, data.length);
4412
- return result;
4413
- }
4414
- async close() {
4367
+ ctx.invalidateSession(sessionId);
4368
+ throw ctx.wrapError(err);
4369
+ } finally {
4370
+ ctx.clearCanceller(sessionId);
4415
4371
  }
4416
- };
4417
-
4418
- // src/connector/chains/tron.ts
4419
- async function tronGetAddress(ctx, sessionId, params) {
4420
- const path = normalizePath(params.path);
4421
- const showOnDevice = params.showOnDevice ?? false;
4422
- return withLegacyChainCall(
4423
- ctx,
4424
- sessionId,
4425
- {
4426
- appName: "Tron",
4427
- // Only show "confirm on device" UI when the device is actually going
4428
- // to display the address for the user to verify.
4429
- needsConfirmation: showOnDevice
4430
- },
4431
- async (sid) => {
4432
- const trx = await _createTrx(ctx, sid);
4433
- const result = await trx.getAddress(path, showOnDevice);
4434
- return { address: result.address, publicKey: result.publicKey, path: params.path };
4435
- }
4436
- );
4437
- }
4438
- async function tronSignTransaction(ctx, sessionId, params) {
4439
- if (!params.rawTxHex) {
4440
- throw Object.assign(
4441
- new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
4442
- { code: import_hwk_adapter_core13.HardwareErrorCode.InvalidParams }
4443
- );
4444
- }
4445
- const path = normalizePath(params.path);
4446
- return withLegacyChainCall(
4447
- ctx,
4448
- sessionId,
4449
- { appName: "Tron", needsConfirmation: true },
4450
- async (sid) => {
4451
- const trx = await _createTrx(ctx, sid);
4452
- const signature = await trx.signTransaction(
4453
- path,
4454
- params.rawTxHex,
4455
- params.tokenSignatures ?? []
4456
- );
4457
- return { signature };
4458
- }
4459
- );
4460
4372
  }
4461
4373
  async function tronSignMessage(ctx, sessionId, params) {
4374
+ const tronSigner = await _createTronSigner(ctx, sessionId);
4462
4375
  const path = normalizePath(params.path);
4463
- return withLegacyChainCall(
4464
- ctx,
4465
- sessionId,
4466
- { appName: "Tron", needsConfirmation: true },
4467
- async (sid) => {
4468
- const trx = await _createTrx(ctx, sid);
4469
- const signature = await trx.signPersonalMessage(path, params.messageHex);
4470
- return { signature };
4471
- }
4472
- );
4376
+ try {
4377
+ const signature = await tronSigner.signPersonalMessage(path, (0, import_hwk_adapter_core11.hexToBytes)(params.messageHex));
4378
+ return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
4379
+ } catch (err) {
4380
+ ctx.invalidateSession(sessionId);
4381
+ throw ctx.wrapError(err);
4382
+ } finally {
4383
+ ctx.clearCanceller(sessionId);
4384
+ }
4473
4385
  }
4474
- async function _createTrx(ctx, sessionId) {
4386
+ async function _createTronSigner(ctx, sessionId) {
4475
4387
  const dmk = await ctx.getOrCreateDmk();
4476
- return new import_hw_app_trx.default(new DmkTransport(dmk, sessionId));
4388
+ const { SignerTrxBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-tron");
4389
+ const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
4390
+ const signer = new SignerTron(sdkSigner);
4391
+ signer.onInteraction = (interaction) => {
4392
+ debugLog("[LedgerConnector] tron.onInteraction:", interaction);
4393
+ ctx.emit("ui-event", {
4394
+ type: collapseSignerInteraction(interaction),
4395
+ payload: { sessionId }
4396
+ });
4397
+ };
4398
+ signer.onRegisterCanceller = (cancel) => {
4399
+ ctx.registerCanceller(sessionId, cancel);
4400
+ };
4401
+ return signer;
4477
4402
  }
4478
4403
 
4479
4404
  // src/device-apps/customActions.ts
4480
- var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
4405
+ var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
4481
4406
  var import_rxjs = require("rxjs");
4482
4407
  var GetOsVersionDeviceAction = class {
4483
4408
  // eslint-disable-next-line no-useless-constructor, no-empty-function
@@ -4491,7 +4416,7 @@ var GetOsVersionDeviceAction = class {
4491
4416
  (async () => {
4492
4417
  try {
4493
4418
  subject.next({
4494
- status: import_device_management_kit3.DeviceActionStatus.Pending,
4419
+ status: import_device_management_kit2.DeviceActionStatus.Pending,
4495
4420
  intermediateValue: { requiredUserInteraction: "none" }
4496
4421
  });
4497
4422
  const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
@@ -4500,11 +4425,11 @@ var GetOsVersionDeviceAction = class {
4500
4425
  const errObj = result?.error;
4501
4426
  throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
4502
4427
  }
4503
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: result.data });
4428
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: result.data });
4504
4429
  subject.complete();
4505
4430
  } catch (err) {
4506
4431
  if (cancelled) return;
4507
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4432
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
4508
4433
  subject.complete();
4509
4434
  }
4510
4435
  })();
@@ -4512,7 +4437,7 @@ var GetOsVersionDeviceAction = class {
4512
4437
  observable: subject.asObservable(),
4513
4438
  cancel: () => {
4514
4439
  cancelled = true;
4515
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4440
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
4516
4441
  subject.complete();
4517
4442
  }
4518
4443
  };
@@ -4530,7 +4455,7 @@ var ListAvailableAppsDeviceAction = class {
4530
4455
  (async () => {
4531
4456
  try {
4532
4457
  subject.next({
4533
- status: import_device_management_kit3.DeviceActionStatus.Pending,
4458
+ status: import_device_management_kit2.DeviceActionStatus.Pending,
4534
4459
  intermediateValue: { requiredUserInteraction: "none" }
4535
4460
  });
4536
4461
  const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
@@ -4547,11 +4472,11 @@ var ListAvailableAppsDeviceAction = class {
4547
4472
  throw new Error(httpErr?.message ?? "Manager API getAppList failed");
4548
4473
  }
4549
4474
  const apps = either.extract();
4550
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Completed, output: apps });
4475
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: apps });
4551
4476
  subject.complete();
4552
4477
  } catch (err) {
4553
4478
  if (cancelled) return;
4554
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Error, error: err });
4479
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
4555
4480
  subject.complete();
4556
4481
  }
4557
4482
  })();
@@ -4559,7 +4484,7 @@ var ListAvailableAppsDeviceAction = class {
4559
4484
  observable: subject.asObservable(),
4560
4485
  cancel: () => {
4561
4486
  cancelled = true;
4562
- subject.next({ status: import_device_management_kit3.DeviceActionStatus.Stopped });
4487
+ subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
4563
4488
  subject.complete();
4564
4489
  }
4565
4490
  };
@@ -4652,7 +4577,7 @@ var DeviceApps = class {
4652
4577
  seTargetId: v.seTargetId,
4653
4578
  mcuTargetId: v.mcuTargetId,
4654
4579
  seVersion: v.seVersion,
4655
- seFlagsHex: bytesToHex3(v.seFlags),
4580
+ seFlagsHex: bytesToHex4(v.seFlags),
4656
4581
  mcuSephVersion: v.mcuSephVersion,
4657
4582
  mcuBootloaderVersion: v.mcuBootloaderVersion,
4658
4583
  hwVersion: v.hwVersion
@@ -4726,7 +4651,7 @@ var DeviceApps = class {
4726
4651
  }
4727
4652
  }
4728
4653
  };
4729
- function bytesToHex3(bytes) {
4654
+ function bytesToHex4(bytes) {
4730
4655
  if (!bytes) return "";
4731
4656
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
4732
4657
  }
@@ -4773,7 +4698,7 @@ var METHOD_PREFIX_TO_APP_NAME = {
4773
4698
  zcash: "Zcash"
4774
4699
  };
4775
4700
  var HARDWARE_ERROR_CODE_VALUES = new Set(
4776
- Object.values(import_hwk_adapter_core14.HardwareErrorCode).filter((value) => typeof value === "number")
4701
+ Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
4777
4702
  );
4778
4703
  var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
4779
4704
  var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
@@ -4810,6 +4735,8 @@ async function defaultLedgerKitImporter(pkg) {
4810
4735
  return import("@ledgerhq/device-signer-kit-bitcoin");
4811
4736
  case "@ledgerhq/device-signer-kit-solana":
4812
4737
  return import("@ledgerhq/device-signer-kit-solana");
4738
+ case "@ledgerhq/device-signer-kit-tron":
4739
+ return import("@ledgerhq/device-signer-kit-tron");
4813
4740
  case "@ledgerhq/device-signer-kit-zcash":
4814
4741
  return import("@ledgerhq/device-signer-kit-zcash");
4815
4742
  case "@ledgerhq/context-module":
@@ -4922,7 +4849,7 @@ var LedgerConnectorBase = class {
4922
4849
  async searchDevices() {
4923
4850
  const dm = await this._getDeviceManager();
4924
4851
  const descriptors = await this._discoverDescriptors(dm);
4925
- const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core14.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
4852
+ const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core12.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
4926
4853
  descriptor: d,
4927
4854
  connectId: this._resolveConnectId(d)
4928
4855
  }));
@@ -4970,7 +4897,7 @@ var LedgerConnectorBase = class {
4970
4897
  `Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
4971
4898
  );
4972
4899
  err._tag = ERROR_TAG.BlePairingTimeout;
4973
- err.code = import_hwk_adapter_core14.HardwareErrorCode.BlePairingTimeout;
4900
+ err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
4974
4901
  reject(err);
4975
4902
  }, HANG_CEILING_MS);
4976
4903
  });
@@ -5003,7 +4930,7 @@ var LedgerConnectorBase = class {
5003
4930
  "Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
5004
4931
  );
5005
4932
  err._tag = ERROR_TAG.DeviceNotAdvertising;
5006
- err.code = import_hwk_adapter_core14.HardwareErrorCode.DeviceNotFound;
4933
+ err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
5007
4934
  throw err;
5008
4935
  };
5009
4936
  const doConnect = async (path) => {
@@ -5067,7 +4994,7 @@ var LedgerConnectorBase = class {
5067
4994
  "Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
5068
4995
  );
5069
4996
  wrapped._tag = ERROR_TAG.BleGattBondingFailed;
5070
- wrapped.code = import_hwk_adapter_core14.HardwareErrorCode.BlePairingTimeout;
4997
+ wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
5071
4998
  wrapped.originalError = err;
5072
4999
  throw wrapped;
5073
5000
  }
@@ -5145,7 +5072,7 @@ var LedgerConnectorBase = class {
5145
5072
  this._unwatchSessionState(sessionId);
5146
5073
  this._signerManager?.invalidate(sessionId);
5147
5074
  this._cancellers.get(sessionId)?.({
5148
- code: import_hwk_adapter_core14.HardwareErrorCode.DeviceDisconnected,
5075
+ code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
5149
5076
  tag: "DeviceDisconnected",
5150
5077
  message: "Device disconnected"
5151
5078
  });
@@ -5169,9 +5096,9 @@ var LedgerConnectorBase = class {
5169
5096
  if (isAppStuckByApdu(err)) {
5170
5097
  return {
5171
5098
  success: false,
5172
- error: (0, import_hwk_adapter_core14.serializeConnectorError)(
5099
+ error: (0, import_hwk_adapter_core12.serializeConnectorError)(
5173
5100
  Object.assign(new Error("Ledger app is unresponsive"), {
5174
- code: import_hwk_adapter_core14.HardwareErrorCode.DeviceAppStuck,
5101
+ code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
5175
5102
  _tag: ERROR_TAG.DeviceAppStuck,
5176
5103
  originalError: err
5177
5104
  })
@@ -5181,16 +5108,16 @@ var LedgerConnectorBase = class {
5181
5108
  if (isTransportStuck(err)) {
5182
5109
  return {
5183
5110
  success: false,
5184
- error: (0, import_hwk_adapter_core14.serializeConnectorError)(
5111
+ error: (0, import_hwk_adapter_core12.serializeConnectorError)(
5185
5112
  Object.assign(new Error("Device communication interrupted, please retry"), {
5186
- code: import_hwk_adapter_core14.HardwareErrorCode.TransportError,
5113
+ code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
5187
5114
  _tag: ERROR_TAG.DeviceTransportStuck,
5188
5115
  originalError: err
5189
5116
  })
5190
5117
  )
5191
5118
  };
5192
5119
  }
5193
- return { success: false, error: (0, import_hwk_adapter_core14.serializeConnectorError)(err) };
5120
+ return { success: false, error: (0, import_hwk_adapter_core12.serializeConnectorError)(err) };
5194
5121
  }
5195
5122
  }
5196
5123
  async _dispatch(sessionId, method, params) {
@@ -5258,7 +5185,7 @@ var LedgerConnectorBase = class {
5258
5185
  try {
5259
5186
  return await apps.install(p.appName, ({ progress }) => {
5260
5187
  ctx.emit("ui-event", {
5261
- type: import_hwk_adapter_core14.EConnectorInteraction.AppInstallProgress,
5188
+ type: import_hwk_adapter_core12.EConnectorInteraction.AppInstallProgress,
5262
5189
  payload: {
5263
5190
  sessionId,
5264
5191
  appName: p.appName,
@@ -5597,6 +5524,204 @@ var LedgerConnectorBase = class {
5597
5524
  return error;
5598
5525
  }
5599
5526
  };
5527
+
5528
+ // src/transport/DmkTransport.ts
5529
+ var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
5530
+ var DmkTransport = class extends import_hw_transport.default {
5531
+ constructor(dmk, sessionId) {
5532
+ super();
5533
+ this._dmk = dmk;
5534
+ this._sessionId = sessionId;
5535
+ }
5536
+ async exchange(apdu) {
5537
+ const response = await this._dmk.sendApdu({
5538
+ sessionId: this._sessionId,
5539
+ apdu: new Uint8Array(apdu)
5540
+ });
5541
+ const { data, statusCode } = response;
5542
+ const result = Buffer.alloc(data.length + 2);
5543
+ if (data.length > 0) {
5544
+ result.set(data, 0);
5545
+ }
5546
+ result.set(statusCode, data.length);
5547
+ return result;
5548
+ }
5549
+ async close() {
5550
+ }
5551
+ };
5552
+
5553
+ // src/app/AppManager.ts
5554
+ var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
5555
+ var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
5556
+ var APP_NAME_MAP = {
5557
+ ETH: "Ethereum",
5558
+ BTC: "Bitcoin",
5559
+ SOL: "Solana",
5560
+ TRX: "Tron",
5561
+ ZEC: "Zcash",
5562
+ XRP: "XRP",
5563
+ ADA: "Cardano",
5564
+ DOT: "Polkadot",
5565
+ ATOM: "Cosmos"
5566
+ };
5567
+ var DASHBOARD_APP_NAME = "BOLOS";
5568
+ var AppManager = class {
5569
+ constructor(dmk, options) {
5570
+ this._dmk = dmk;
5571
+ this._waitMs = options?.waitMs ?? 1e3;
5572
+ this._maxRetries = options?.maxRetries ?? 10;
5573
+ }
5574
+ /**
5575
+ * Return the Ledger app name for a given chain ticker,
5576
+ * or undefined if the chain is not supported.
5577
+ */
5578
+ static getAppName(chain) {
5579
+ return APP_NAME_MAP[chain];
5580
+ }
5581
+ /**
5582
+ * Ensure the target app is open on the device identified by `sessionId`.
5583
+ *
5584
+ * Flow:
5585
+ * 1. Check the currently running app.
5586
+ * 2. If it is already the target, return immediately.
5587
+ * 3. If a different app is running (not dashboard), close it first.
5588
+ * 4. Open the target app.
5589
+ * 5. Poll until the device confirms the target app is running.
5590
+ */
5591
+ /**
5592
+ * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
5593
+ * device is about to display "Open <app>" on screen and wait for the
5594
+ * user's button press. UI consumers should show their "open app" prompt
5595
+ * in response. NOT called when the target app is already open (no user
5596
+ * interaction needed in that case).
5597
+ *
5598
+ * Important: OpenAppCommand is blocking. It does not resolve until the user
5599
+ * has physically confirmed on the device, so anything that runs AFTER
5600
+ * `await this._openApp(...)` lands AFTER the prompt is already gone.
5601
+ * Hence the callback must fire BEFORE that await.
5602
+ */
5603
+ async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
5604
+ const currentApp = await this._getCurrentApp(sessionId);
5605
+ if (currentApp === targetAppName) {
5606
+ return;
5607
+ }
5608
+ if (!this._isDashboard(currentApp)) {
5609
+ await this._closeCurrentApp(sessionId);
5610
+ await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
5611
+ }
5612
+ onConfirmOnDevice?.();
5613
+ await this._openApp(sessionId, targetAppName);
5614
+ await this._waitForApp(sessionId, targetAppName);
5615
+ }
5616
+ // ---------------------------------------------------------------------------
5617
+ // Private helpers
5618
+ // ---------------------------------------------------------------------------
5619
+ async _getCurrentApp(sessionId) {
5620
+ const result = await this._dmk.sendCommand({
5621
+ sessionId,
5622
+ command: new import_device_management_kit3.GetAppAndVersionCommand()
5623
+ });
5624
+ if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5625
+ debugLog("[AppManager] currentApp:", result.data.name);
5626
+ return result.data.name;
5627
+ }
5628
+ const errResult = result;
5629
+ const dmkErr = errResult.error ?? {};
5630
+ const original = dmkErr.originalError;
5631
+ debugLog(
5632
+ "[AppManager] _getCurrentApp failed sessionId=",
5633
+ sessionId,
5634
+ "tag=",
5635
+ dmkErr._tag,
5636
+ "errorCode=",
5637
+ dmkErr.errorCode,
5638
+ "message=",
5639
+ dmkErr.message,
5640
+ "originalErrorMessage=",
5641
+ original?.message ?? String(original ?? "")
5642
+ );
5643
+ throw Object.assign(
5644
+ new Error(
5645
+ dmkErr.message ?? "Failed to get current app from device"
5646
+ ),
5647
+ {
5648
+ _tag: dmkErr._tag,
5649
+ errorCode: dmkErr.errorCode,
5650
+ originalError: original
5651
+ }
5652
+ );
5653
+ }
5654
+ async _openApp(sessionId, appName) {
5655
+ const result = await this._dmk.sendCommand({
5656
+ sessionId,
5657
+ command: new import_device_management_kit3.OpenAppCommand({ appName })
5658
+ });
5659
+ if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
5660
+ const dmkErr = result.error;
5661
+ const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
5662
+ const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
5663
+ debugLog(
5664
+ "[AppManager] openApp failed:",
5665
+ appName,
5666
+ "errorCode:",
5667
+ errorCode,
5668
+ "tag:",
5669
+ dmkErr._tag
5670
+ );
5671
+ let code;
5672
+ if (errorCode === "6807" || /unknown application/i.test(message)) {
5673
+ code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
5674
+ } else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
5675
+ code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
5676
+ }
5677
+ throw Object.assign(new Error(`Failed to open "${appName}"`), {
5678
+ _tag: ERROR_TAG.OpenAppCommand,
5679
+ code,
5680
+ errorCode,
5681
+ statusCode: errorCode,
5682
+ appName,
5683
+ originalError: dmkErr
5684
+ });
5685
+ }
5686
+ }
5687
+ async _closeCurrentApp(sessionId) {
5688
+ debugLog("[AppManager] closeCurrentApp");
5689
+ await this._dmk.sendCommand({
5690
+ sessionId,
5691
+ command: new import_device_management_kit3.CloseAppCommand()
5692
+ });
5693
+ }
5694
+ /**
5695
+ * Poll the device until the expected app is reported as running,
5696
+ * or throw after `_maxRetries` attempts.
5697
+ */
5698
+ async _waitForApp(sessionId, expectedAppName) {
5699
+ let lastSeen = "";
5700
+ for (let i = 0; i < this._maxRetries; i++) {
5701
+ await this._wait();
5702
+ const current = await this._getCurrentApp(sessionId);
5703
+ lastSeen = current;
5704
+ if (current === expectedAppName) {
5705
+ return;
5706
+ }
5707
+ }
5708
+ debugLog(
5709
+ "[AppManager] waitForApp exhausted: expected=",
5710
+ expectedAppName,
5711
+ "lastSeen=",
5712
+ lastSeen
5713
+ );
5714
+ throw new Error(
5715
+ `Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
5716
+ );
5717
+ }
5718
+ _isDashboard(appName) {
5719
+ return appName === DASHBOARD_APP_NAME;
5720
+ }
5721
+ _wait() {
5722
+ return new Promise((resolve) => setTimeout(resolve, this._waitMs));
5723
+ }
5724
+ };
5600
5725
  // Annotate the CommonJS export names for ESM import in node:
5601
5726
  0 && (module.exports = {
5602
5727
  AppManager,