@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.101 → 1.1.26-alpha.102

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.d.mts CHANGED
@@ -1,10 +1,18 @@
1
- import { IHardwareWallet, IConnector, TransportType, IUiHandler, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, EvmGetPublicKeyParams, EvmPublicKey, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolGetPublicKeyParams, SolPublicKey, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
1
+ import { IHardwareWallet, IConnector, TransportType, IUiHandler, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, EvmGetPublicKeyParams, EvmPublicKey, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolGetPublicKeyParams, SolPublicKey, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
2
2
  import { DeviceManagementKit, DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType } from '@ledgerhq/device-management-kit';
3
3
  import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
4
4
  import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
5
5
  import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
6
6
  import Transport from '@ledgerhq/hw-transport';
7
7
 
8
+ interface LedgerAdapterOptions {
9
+ /**
10
+ * `true` — emit `REQUEST_SELECT_DEVICE` on multi-device discovery and await
11
+ * `uiResponse({ type: RECEIVE_SELECT_DEVICE, payload: { sdkConnectId } })`.
12
+ * `false` (default) — silently pick the first device.
13
+ */
14
+ handleSelectDevice?: boolean;
15
+ }
8
16
  /**
9
17
  * Ledger hardware wallet adapter that delegates to an IConnector.
10
18
  *
@@ -20,9 +28,11 @@ declare class LedgerAdapter implements IHardwareWallet {
20
28
  private readonly connector;
21
29
  private readonly emitter;
22
30
  private _uiHandler;
31
+ private readonly _handleSelectDevice;
23
32
  private _discoveredDevices;
24
33
  private _sessions;
25
- constructor(connector: IConnector);
34
+ private readonly _uiRegistry;
35
+ constructor(connector: IConnector, options?: LedgerAdapterOptions);
26
36
  get activeTransport(): TransportType | null;
27
37
  getAvailableTransports(): TransportType[];
28
38
  switchTransport(_type: TransportType): Promise<void>;
@@ -35,6 +45,7 @@ declare class LedgerAdapter implements IHardwareWallet {
35
45
  */
36
46
  resetState(): void;
37
47
  dispose(): Promise<void>;
48
+ uiResponse(response: UiResponseEvent): void;
38
49
  searchDevices(): Promise<DeviceInfo[]>;
39
50
  connectDevice(connectId: string): Promise<Response<string>>;
40
51
  disconnectDevice(connectId: string): Promise<void>;
@@ -97,25 +108,12 @@ declare class LedgerAdapter implements IHardwareWallet {
97
108
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
98
109
  */
99
110
  private static readonly MAX_DEVICE_RETRY;
100
- private _deviceConnectResolve;
101
111
  private _connectingPromise;
102
- private static readonly DEVICE_CONNECT_TIMEOUT_MS;
103
- /**
104
- * Wait for user to connect and unlock device.
105
- * Emits 'ui-request' event via the adapter's own emitter.
106
- * The consumer (monorepo adapter wrapper) listens for this and shows UI.
107
- * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
108
- * Times out after 60 seconds if no response is received.
109
- */
110
112
  private _waitForDeviceConnect;
111
- /**
112
- * Called by consumer to respond to ui-request-device-connect.
113
- * type='confirm' → retry search, type='cancel' → abort.
114
- */
115
- deviceConnectResponse(type: 'confirm' | 'cancel'): void;
116
113
  private ensureConnected;
117
114
  private _doConnect;
118
115
  private _connectFirstOrSelect;
116
+ private _chooseDeviceFromList;
119
117
  /**
120
118
  * Call the connector with automatic session resolution and disconnect retry.
121
119
  *
@@ -223,10 +221,7 @@ declare class LedgerConnectorBase implements IConnector {
223
221
  disconnect(sessionId: string): Promise<void>;
224
222
  call(sessionId: string, method: string, params: unknown): Promise<unknown>;
225
223
  cancel(_sessionId: string): Promise<void>;
226
- uiResponse(_response: {
227
- type: string;
228
- payload: unknown;
229
- }): void;
224
+ uiResponse(_response: UiResponseEvent): void;
230
225
  on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
231
226
  off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
232
227
  reset(): void;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,18 @@
1
- import { IHardwareWallet, IConnector, TransportType, IUiHandler, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, EvmGetPublicKeyParams, EvmPublicKey, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolGetPublicKeyParams, SolPublicKey, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
1
+ import { IHardwareWallet, IConnector, TransportType, IUiHandler, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, EvmGetPublicKeyParams, EvmPublicKey, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolGetPublicKeyParams, SolPublicKey, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
2
2
  import { DeviceManagementKit, DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType } from '@ledgerhq/device-management-kit';
3
3
  import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
4
4
  import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
5
5
  import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
6
6
  import Transport from '@ledgerhq/hw-transport';
7
7
 
8
+ interface LedgerAdapterOptions {
9
+ /**
10
+ * `true` — emit `REQUEST_SELECT_DEVICE` on multi-device discovery and await
11
+ * `uiResponse({ type: RECEIVE_SELECT_DEVICE, payload: { sdkConnectId } })`.
12
+ * `false` (default) — silently pick the first device.
13
+ */
14
+ handleSelectDevice?: boolean;
15
+ }
8
16
  /**
9
17
  * Ledger hardware wallet adapter that delegates to an IConnector.
10
18
  *
@@ -20,9 +28,11 @@ declare class LedgerAdapter implements IHardwareWallet {
20
28
  private readonly connector;
21
29
  private readonly emitter;
22
30
  private _uiHandler;
31
+ private readonly _handleSelectDevice;
23
32
  private _discoveredDevices;
24
33
  private _sessions;
25
- constructor(connector: IConnector);
34
+ private readonly _uiRegistry;
35
+ constructor(connector: IConnector, options?: LedgerAdapterOptions);
26
36
  get activeTransport(): TransportType | null;
27
37
  getAvailableTransports(): TransportType[];
28
38
  switchTransport(_type: TransportType): Promise<void>;
@@ -35,6 +45,7 @@ declare class LedgerAdapter implements IHardwareWallet {
35
45
  */
36
46
  resetState(): void;
37
47
  dispose(): Promise<void>;
48
+ uiResponse(response: UiResponseEvent): void;
38
49
  searchDevices(): Promise<DeviceInfo[]>;
39
50
  connectDevice(connectId: string): Promise<Response<string>>;
40
51
  disconnectDevice(connectId: string): Promise<void>;
@@ -97,25 +108,12 @@ declare class LedgerAdapter implements IHardwareWallet {
97
108
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
98
109
  */
99
110
  private static readonly MAX_DEVICE_RETRY;
100
- private _deviceConnectResolve;
101
111
  private _connectingPromise;
102
- private static readonly DEVICE_CONNECT_TIMEOUT_MS;
103
- /**
104
- * Wait for user to connect and unlock device.
105
- * Emits 'ui-request' event via the adapter's own emitter.
106
- * The consumer (monorepo adapter wrapper) listens for this and shows UI.
107
- * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
108
- * Times out after 60 seconds if no response is received.
109
- */
110
112
  private _waitForDeviceConnect;
111
- /**
112
- * Called by consumer to respond to ui-request-device-connect.
113
- * type='confirm' → retry search, type='cancel' → abort.
114
- */
115
- deviceConnectResponse(type: 'confirm' | 'cancel'): void;
116
113
  private ensureConnected;
117
114
  private _doConnect;
118
115
  private _connectFirstOrSelect;
116
+ private _chooseDeviceFromList;
119
117
  /**
120
118
  * Call the connector with automatic session resolution and disconnect retry.
121
119
  *
@@ -223,10 +221,7 @@ declare class LedgerConnectorBase implements IConnector {
223
221
  disconnect(sessionId: string): Promise<void>;
224
222
  call(sessionId: string, method: string, params: unknown): Promise<unknown>;
225
223
  cancel(_sessionId: string): Promise<void>;
226
- uiResponse(_response: {
227
- type: string;
228
- payload: unknown;
229
- }): void;
224
+ uiResponse(_response: UiResponseEvent): void;
230
225
  on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
231
226
  off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
232
227
  reset(): void;
package/dist/index.js CHANGED
@@ -204,7 +204,7 @@ function formatDeviceMismatchError(expected, actual) {
204
204
  return `Wrong device: expected ${expected}, got ${actual}`;
205
205
  }
206
206
  var _LedgerAdapter = class _LedgerAdapter {
207
- constructor(connector) {
207
+ constructor(connector, options) {
208
208
  this.vendor = "ledger";
209
209
  this.emitter = new import_hwk_adapter_core2.TypedEventEmitter();
210
210
  this._uiHandler = null;
@@ -212,8 +212,7 @@ var _LedgerAdapter = class _LedgerAdapter {
212
212
  this._discoveredDevices = /* @__PURE__ */ new Map();
213
213
  // Session tracking: maps connectId -> sessionId
214
214
  this._sessions = /* @__PURE__ */ new Map();
215
- // Pending device-connect resolve — set by _waitForDeviceConnect, resolved by uiResponse
216
- this._deviceConnectResolve = null;
215
+ this._uiRegistry = new import_hwk_adapter_core2.UiRequestRegistry();
217
216
  // Mutex for ensureConnected — prevents concurrent calls from establishing duplicate connections
218
217
  this._connectingPromise = null;
219
218
  // ---------------------------------------------------------------------------
@@ -243,6 +242,7 @@ var _LedgerAdapter = class _LedgerAdapter {
243
242
  this.handleUiEvent(data);
244
243
  };
245
244
  this.connector = connector;
245
+ this._handleSelectDevice = options?.handleSelectDevice ?? false;
246
246
  this.registerEventListeners();
247
247
  }
248
248
  // ---------------------------------------------------------------------------
@@ -278,10 +278,10 @@ var _LedgerAdapter = class _LedgerAdapter {
278
278
  this._discoveredDevices.clear();
279
279
  this._sessions.clear();
280
280
  this._connectingPromise = null;
281
+ this._uiRegistry.reset();
281
282
  }
282
283
  async dispose() {
283
- this._deviceConnectResolve?.(true);
284
- this._deviceConnectResolve = null;
284
+ this._uiRegistry.reset();
285
285
  this.unregisterEventListeners();
286
286
  this.connector.reset();
287
287
  this._uiHandler = null;
@@ -289,6 +289,9 @@ var _LedgerAdapter = class _LedgerAdapter {
289
289
  this._sessions.clear();
290
290
  this.emitter.removeAllListeners();
291
291
  }
292
+ uiResponse(response) {
293
+ this._uiRegistry.resolve(response.type, response.payload);
294
+ }
292
295
  // ---------------------------------------------------------------------------
293
296
  // Device management
294
297
  // ---------------------------------------------------------------------------
@@ -622,55 +625,24 @@ var _LedgerAdapter = class _LedgerAdapter {
622
625
  }
623
626
  throw new Error(`Unsupported chain for fingerprint: ${chain}`);
624
627
  }
625
- /**
626
- * Wait for user to connect and unlock device.
627
- * Emits 'ui-request' event via the adapter's own emitter.
628
- * The consumer (monorepo adapter wrapper) listens for this and shows UI.
629
- * When user confirms, they call adapter.deviceConnectResponse() which resolves this promise.
630
- * Times out after 60 seconds if no response is received.
631
- */
632
- _waitForDeviceConnect(attempt) {
633
- return new Promise((resolve, reject) => {
634
- let settled = false;
635
- const timer = setTimeout(() => {
636
- if (!settled) {
637
- settled = true;
638
- this._deviceConnectResolve = null;
639
- reject(new Error("Ledger device connect timed out after 60 seconds"));
640
- }
641
- }, _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS);
642
- this._deviceConnectResolve = (cancelled) => {
643
- if (settled) return;
644
- settled = true;
645
- clearTimeout(timer);
646
- this._deviceConnectResolve = null;
647
- if (cancelled) {
648
- reject(
649
- Object.assign(new Error("User cancelled Ledger connection"), {
650
- _tag: "DeviceNotRecognizedError"
651
- })
652
- );
653
- } else {
654
- resolve();
655
- }
656
- };
657
- this.emitter.emit(import_hwk_adapter_core2.UI_REQUEST.REQUEST_DEVICE_CONNECT, {
658
- type: import_hwk_adapter_core2.UI_REQUEST.REQUEST_DEVICE_CONNECT,
659
- payload: {
660
- message: "Please connect and unlock your Ledger device",
661
- retryCount: attempt,
662
- maxRetries: _LedgerAdapter.MAX_DEVICE_RETRY
663
- }
664
- });
628
+ // Ledger WebUSB won't expose a locked device, so we can't auto-detect unlock.
629
+ // The user must press Confirm after unlocking, which triggers a search retry.
630
+ async _waitForDeviceConnect(attempt) {
631
+ this.emitter.emit(import_hwk_adapter_core2.UI_REQUEST.REQUEST_DEVICE_CONNECT, {
632
+ type: import_hwk_adapter_core2.UI_REQUEST.REQUEST_DEVICE_CONNECT,
633
+ payload: {
634
+ message: "Please connect and unlock your Ledger device",
635
+ retryCount: attempt,
636
+ maxRetries: _LedgerAdapter.MAX_DEVICE_RETRY
637
+ }
665
638
  });
666
- }
667
- /**
668
- * Called by consumer to respond to ui-request-device-connect.
669
- * type='confirm' → retry search, type='cancel' → abort.
670
- */
671
- deviceConnectResponse(type) {
672
- if (this._deviceConnectResolve) {
673
- this._deviceConnectResolve(type === "cancel");
639
+ const payload = await this._uiRegistry.wait(
640
+ import_hwk_adapter_core2.UI_REQUEST.REQUEST_DEVICE_CONNECT
641
+ );
642
+ if (!payload?.confirmed) {
643
+ throw Object.assign(new Error("User cancelled Ledger connection"), {
644
+ _tag: "DeviceNotRecognizedError"
645
+ });
674
646
  }
675
647
  }
676
648
  async ensureConnected(connectId) {
@@ -708,26 +680,39 @@ var _LedgerAdapter = class _LedgerAdapter {
708
680
  );
709
681
  }
710
682
  async _connectFirstOrSelect(devices) {
711
- if (devices.length === 1) {
712
- const result2 = await this.connectDevice(devices[0].connectId);
713
- if (!result2.success) {
714
- throw Object.assign(new Error(result2.payload.error), { _tag: "DeviceNotRecognizedError" });
715
- }
716
- return devices[0].connectId;
683
+ const chosenConnectId = devices.length === 1 ? devices[0].connectId : await this._chooseDeviceFromList(devices);
684
+ const result = await this.connectDevice(chosenConnectId);
685
+ if (!result.success) {
686
+ throw Object.assign(new Error(result.payload.error), {
687
+ _tag: "DeviceNotRecognizedError"
688
+ });
717
689
  }
718
- if (this._uiHandler?.onSelectDevice) {
719
- const selectedConnectId = await this._uiHandler.onSelectDevice(devices);
720
- const result2 = await this.connectDevice(selectedConnectId);
721
- if (!result2.success) {
722
- throw Object.assign(new Error(result2.payload.error), { _tag: "DeviceNotRecognizedError" });
723
- }
724
- return selectedConnectId;
690
+ return chosenConnectId;
691
+ }
692
+ async _chooseDeviceFromList(devices) {
693
+ if (!this._handleSelectDevice) {
694
+ debugLog(
695
+ `[DMK] Multiple Ledger devices found (${devices.length}); handleSelectDevice=false, picking first (${devices[0].connectId}).`
696
+ );
697
+ return devices[0].connectId;
725
698
  }
726
- const result = await this.connectDevice(devices[0].connectId);
727
- if (!result.success) {
728
- throw Object.assign(new Error(result.payload.error), { _tag: "DeviceNotRecognizedError" });
699
+ this.emitter.emit(import_hwk_adapter_core2.UI_REQUEST.REQUEST_SELECT_DEVICE, {
700
+ type: import_hwk_adapter_core2.UI_REQUEST.REQUEST_SELECT_DEVICE,
701
+ payload: { devices }
702
+ });
703
+ const response = await this._uiRegistry.wait(
704
+ import_hwk_adapter_core2.UI_REQUEST.REQUEST_SELECT_DEVICE
705
+ );
706
+ const chosen = devices.find((d) => d.connectId === response?.sdkConnectId);
707
+ if (!chosen) {
708
+ throw Object.assign(
709
+ new Error(
710
+ `Selected sdkConnectId '${response?.sdkConnectId}' not in discovered list`
711
+ ),
712
+ { _tag: "DeviceNotRecognizedError" }
713
+ );
729
714
  }
730
- return devices[0].connectId;
715
+ return chosen.connectId;
731
716
  }
732
717
  /**
733
718
  * Call the connector with automatic session resolution and disconnect retry.
@@ -910,7 +895,6 @@ var _LedgerAdapter = class _LedgerAdapter {
910
895
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
911
896
  */
912
897
  _LedgerAdapter.MAX_DEVICE_RETRY = 3;
913
- _LedgerAdapter.DEVICE_CONNECT_TIMEOUT_MS = 6e4;
914
898
  var LedgerAdapter = _LedgerAdapter;
915
899
 
916
900
  // src/device/LedgerDeviceManager.ts