@onekeyfe/hwk-ledger-adapter 1.1.26-alpha.8 → 1.1.26

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,6 +1,7 @@
1
- import { IHardwareWallet, IConnector, TransportType, UiResponseEvent, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, ProgressCallback, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, ConnectionType, DeviceDescriptor, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, DeviceChangeEvent, Failure, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
2
- import { DeviceManagementKit, DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType } from '@ledgerhq/device-management-kit';
1
+ import { IHardwareWallet, IConnector, TransportType, UiResponseEvent, SearchDevicesOptions, DeviceInfo, Response, ChainCapability, EvmGetAddressParams, EvmAddress, EvmSignTxParams, EvmSignedTx, EvmSignMsgParams, EvmSignature, EvmSignTypedDataParams, BtcGetAddressParams, BtcAddress, BtcGetPublicKeyParams, BtcPublicKey, BtcSignTxParams, BtcSignedTx, BtcSignPsbtParams, BtcSignedPsbt, BtcSignMsgParams, BtcSignature, SolGetAddressParams, SolAddress, SolSignTxParams, SolSignedTx, SolSignMsgParams, SolSignature, TronGetAddressParams, TronAddress, TronSignTxParams, TronSignedTx, TronSignMsgParams, TronSignature, HardwareEventMap, DeviceEventListener, ChainForFingerprint, DeviceDescriptor, DeviceChangeEvent, ConnectionType, ConnectorDevice, ConnectorSession, ConnectorEventType, ConnectorEventMap, Failure, HardwareErrorCode } from '@onekeyfe/hwk-adapter-core';
2
+ import { DeviceActionState as DeviceActionState$1, DiscoveredDevice, ExecuteDeviceActionReturnType, DeviceManagementKit } from '@ledgerhq/device-management-kit';
3
3
  import { Address, Signature, SignerEth as SignerEth$1, TypedData } from '@ledgerhq/device-signer-kit-ethereum';
4
+ import { ContextModule } from '@ledgerhq/context-module';
4
5
  import { SignerBtc as SignerBtc$1 } from '@ledgerhq/device-signer-kit-bitcoin';
5
6
  import { SignerSolana } from '@ledgerhq/device-signer-kit-solana';
6
7
  import Transport from '@ledgerhq/hw-transport';
@@ -13,16 +14,6 @@ interface LedgerAdapterOptions {
13
14
  */
14
15
  handleSelectDevice?: boolean;
15
16
  }
16
- /**
17
- * Ledger hardware wallet adapter that delegates to an IConnector.
18
- *
19
- * This is a thin translation layer that:
20
- * - Accepts a pre-configured IConnector (transport decisions are made at connector creation time)
21
- * - Translates IHardwareWallet method calls to connector.call() invocations
22
- * - Maps connector results/errors to our Response<T> format with enriched error messages
23
- * - Translates connector events to HardwareEventMap events
24
- * - Emits `REQUEST_DEVICE_PERMISSION` for OS-level permission checks
25
- */
26
17
  declare class LedgerAdapter implements IHardwareWallet {
27
18
  readonly vendor: "ledger";
28
19
  private readonly connector;
@@ -31,15 +22,10 @@ declare class LedgerAdapter implements IHardwareWallet {
31
22
  private _discoveredDevices;
32
23
  private _sessions;
33
24
  private readonly _uiRegistry;
25
+ private _btcHighIndexConfirmedThisSession;
34
26
  private readonly _jobQueue;
27
+ private _doConnectAbortController;
35
28
  constructor(connector: IConnector, options?: LedgerAdapterOptions);
36
- /**
37
- * Classify a method's interruptibility.
38
- * - Signing / typed data / transaction → 'confirm' (user may decide via preemption UI)
39
- * - Read-only queries (getAddress / getPublicKey / getMasterFingerprint) → 'safe'
40
- * (auto-cancels any pending read for the same device)
41
- */
42
- private static _getInterruptibility;
43
29
  get activeTransport(): TransportType | null;
44
30
  getAvailableTransports(): TransportType[];
45
31
  switchTransport(_type: TransportType): Promise<void>;
@@ -52,24 +38,22 @@ declare class LedgerAdapter implements IHardwareWallet {
52
38
  resetState(): void;
53
39
  dispose(): Promise<void>;
54
40
  uiResponse(response: UiResponseEvent): void;
55
- searchDevices(): Promise<DeviceInfo[]>;
41
+ searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
42
+ private static readonly MAX_BUSINESS_RETRY_BUDGET;
43
+ private static readonly STUCK_APP_RETRY_DELAY_MS;
44
+ private static readonly MAX_DOCONNECT_CONFIRMS;
45
+ private _lastCancelReason;
46
+ private static _createDeviceBusyError;
56
47
  connectDevice(connectId: string): Promise<Response<string>>;
57
48
  disconnectDevice(connectId: string): Promise<void>;
58
49
  getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
59
50
  getSupportedChains(): ChainCapability[];
60
51
  private callChain;
61
- /**
62
- * Batch version of callChain — checks permission once,
63
- * fingerprint is verified on the first call inside connectorCall.
64
- */
65
- private callChainBatch;
66
52
  evmGetAddress(connectId: string, deviceId: string, params: EvmGetAddressParams): Promise<Response<EvmAddress>>;
67
- evmGetAddresses(connectId: string, deviceId: string, params: EvmGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<EvmAddress[]>>;
68
53
  evmSignTransaction(connectId: string, deviceId: string, params: EvmSignTxParams): Promise<Response<EvmSignedTx>>;
69
54
  evmSignMessage(connectId: string, deviceId: string, params: EvmSignMsgParams): Promise<Response<EvmSignature>>;
70
55
  evmSignTypedData(connectId: string, deviceId: string, params: EvmSignTypedDataParams): Promise<Response<EvmSignature>>;
71
56
  btcGetAddress(connectId: string, deviceId: string, params: BtcGetAddressParams): Promise<Response<BtcAddress>>;
72
- btcGetAddresses(connectId: string, deviceId: string, params: BtcGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<BtcAddress[]>>;
73
57
  btcGetPublicKey(connectId: string, deviceId: string, params: BtcGetPublicKeyParams): Promise<Response<BtcPublicKey>>;
74
58
  btcSignTransaction(connectId: string, deviceId: string, params: BtcSignTxParams): Promise<Response<BtcSignedTx>>;
75
59
  btcSignPsbt(connectId: string, deviceId: string, params: BtcSignPsbtParams): Promise<Response<BtcSignedPsbt>>;
@@ -78,18 +62,16 @@ declare class LedgerAdapter implements IHardwareWallet {
78
62
  masterFingerprint: string;
79
63
  }>>;
80
64
  solGetAddress(connectId: string, deviceId: string, params: SolGetAddressParams): Promise<Response<SolAddress>>;
81
- solGetAddresses(connectId: string, deviceId: string, params: SolGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<SolAddress[]>>;
82
65
  solSignTransaction(connectId: string, deviceId: string, params: SolSignTxParams): Promise<Response<SolSignedTx>>;
83
66
  solSignMessage(connectId: string, deviceId: string, params: SolSignMsgParams): Promise<Response<SolSignature>>;
84
67
  tronGetAddress(connectId: string, deviceId: string, params: TronGetAddressParams): Promise<Response<TronAddress>>;
85
- tronGetAddresses(connectId: string, deviceId: string, params: TronGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<TronAddress[]>>;
86
68
  tronSignTransaction(connectId: string, deviceId: string, params: TronSignTxParams): Promise<Response<TronSignedTx>>;
87
69
  tronSignMessage(connectId: string, deviceId: string, params: TronSignMsgParams): Promise<Response<TronSignature>>;
88
70
  on<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;
89
71
  on(event: string, listener: DeviceEventListener): void;
90
72
  off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;
91
73
  off(event: string, listener: DeviceEventListener): void;
92
- cancel(connectId: string): void;
74
+ cancel(connectId?: string): void;
93
75
  getChainFingerprint(connectId: string, deviceId: string, chain: ChainForFingerprint): Promise<Response<string>>;
94
76
  /**
95
77
  * Verify fingerprint using an existing sessionId directly.
@@ -118,12 +100,21 @@ declare class LedgerAdapter implements IHardwareWallet {
118
100
  * - If ANY session exists (Ledger IDs are ephemeral), reuse it.
119
101
  * - Otherwise: search → 1 device: auto-connect, multiple: ask user, 0: throw.
120
102
  */
121
- private static readonly MAX_DEVICE_RETRY;
122
103
  private _connectingPromise;
123
104
  private _waitForDeviceConnect;
105
+ /**
106
+ * Decide whether a BTC pubkey call needs `showOnDevice=true` because of
107
+ * the BTC App's account-index policy, asking the user once per session.
108
+ *
109
+ * Returns the params to pass through (with `showOnDevice` possibly
110
+ * promoted), or `null` if the user declined.
111
+ */
112
+ private _gateBtcHighIndex;
113
+ private _waitForBtcHighIndexConfirm;
124
114
  private ensureConnected;
125
115
  private _doConnect;
126
116
  private _connectFirstOrSelect;
117
+ private _connectDeviceOrThrow;
127
118
  private _chooseDeviceFromList;
128
119
  /**
129
120
  * Call the connector with automatic session resolution and disconnect retry.
@@ -135,16 +126,31 @@ declare class LedgerAdapter implements IHardwareWallet {
135
126
  */
136
127
  private connectorCall;
137
128
  /**
138
- * Race a promise against an abort signal. If the signal fires, rejects with the
139
- * signal's reason (or a generic Error). The underlying connector.call() cannot
140
- * actually be cancelled on Ledger DMK, but the caller gets the abort immediately.
129
+ * Race a promise against an abort signal. On abort, rejects with
130
+ * signal.reason instance _lastCancelReason → generic Error('Aborted').
141
131
  */
142
- private static _abortable;
132
+ private _abortable;
143
133
  /** Throw an AbortError if signal is already aborted. */
144
134
  private static _throwIfAborted;
145
135
  /** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
146
136
  private _runConnectorCall;
147
- /** Clear stale session, reconnect, and retry the call. */
137
+ /**
138
+ * Stuck-app recovery: pause for the device's UI transition, then retry once.
139
+ *
140
+ * Caller has already cleared the session + reset connector. We wait so Stax
141
+ * finishes its post-CloseApp animation, then go through ensureConnected +
142
+ * fingerprint check + call exactly once. Caller decides what to do on a
143
+ * second stuck-app hit.
144
+ */
145
+ private _retryAfterStuckApp;
146
+ private _sleepAbortable;
147
+ /**
148
+ * Clear stale session, reconnect, and retry the call.
149
+ *
150
+ * Timeout recovery starts with a full connector reset. After an APDU
151
+ * timeout, DMK/transport state may still emit malformed responses; retrying
152
+ * on the same DMK can poison the next chain switch.
153
+ */
148
154
  private _retryWithFreshConnection;
149
155
  /**
150
156
  * Ensure OS-level device permission (Bluetooth / USB) before proceeding.
@@ -166,14 +172,115 @@ declare class LedgerAdapter implements IHardwareWallet {
166
172
  private errorToFailure;
167
173
  private deviceConnectHandler;
168
174
  private deviceDisconnectHandler;
169
- private uiRequestHandler;
170
- private uiEventHandler;
175
+ private uiEventForwarder;
171
176
  private registerEventListeners;
172
177
  private unregisterEventListeners;
173
- private handleUiEvent;
174
178
  private connectorDeviceToDeviceInfo;
175
- private extractDeviceInfoFromPayload;
176
- private unknownDevice;
179
+ }
180
+
181
+ /**
182
+ * Re-export DMK types under local aliases for backward compatibility.
183
+ * These replace the previous duck-typed interfaces with the real SDK types.
184
+ */
185
+ type DmkDiscoveredDevice = DiscoveredDevice;
186
+ /**
187
+ * DMK DeviceAction — the Observable-based return type of all DMK signer methods.
188
+ *
189
+ * This is a permissive alias for `ExecuteDeviceActionReturnType` that accepts
190
+ * any Error and IntermediateValue generics. Signer wrapper code only cares about
191
+ * the Output type and the observable/cancel shape.
192
+ */
193
+ type DeviceAction<T> = ExecuteDeviceActionReturnType<T, any, any>;
194
+ /**
195
+ * DMK DeviceActionState — re-exported with permissive Error/IntermediateValue.
196
+ * The real type is a discriminated union on `status`.
197
+ */
198
+ type DeviceActionState<T> = DeviceActionState$1<T, any, any>;
199
+ /** ETH address result — re-exported from DMK for backward compatibility. */
200
+ type SignerEvmAddress = Address;
201
+ /** ETH signature result — re-exported from DMK for backward compatibility. */
202
+ type SignerEvmSignature = Signature;
203
+ /** BTC address result (WalletAddress not exported from DMK top-level). */
204
+ interface SignerBtcAddress {
205
+ address: string;
206
+ }
207
+
208
+ /**
209
+ * Manages device discovery, connection, and session tracking.
210
+ * Wraps DMK's Observable APIs into simpler imperative calls.
211
+ */
212
+ declare class LedgerDeviceManager {
213
+ private readonly _dmk;
214
+ private readonly _discovered;
215
+ private readonly _sessions;
216
+ private readonly _sessionToDevice;
217
+ private _listenSub;
218
+ constructor(dmk: DeviceManagementKit);
219
+ /**
220
+ * One-shot enumeration: subscribe to listenToAvailableDevices,
221
+ * take the first emission, unsubscribe, return DeviceDescriptors.
222
+ */
223
+ enumerate(): Promise<DeviceDescriptor[]>;
224
+ /**
225
+ * Continuous listening: tracks device connect/disconnect via diffing.
226
+ */
227
+ listen(onChange: (event: DeviceChangeEvent) => void): void;
228
+ stopListening(): void;
229
+ /**
230
+ * Resolve to the latest snapshot of advertising devices observed within
231
+ * `timeoutMs`. Rewrites `_discovered` so it tracks the live list.
232
+ *
233
+ * `listenToAvailableDevices` is a BehaviorSubject — it emits the cached
234
+ * list on subscribe and *only* re-emits when the list changes. A stable
235
+ * list of currently-advertising devices therefore produces only the
236
+ * subscription frame; treating that frame as "fossil to be discarded"
237
+ * caused devices to flicker in/out of the UI as searches alternated
238
+ * between "saw a change frame" and "saw only the cached frame".
239
+ *
240
+ * The window still gives a chance for the active scan to update the list
241
+ * (e.g. drop a peripheral that just stopped broadcasting), but if nothing
242
+ * changes we trust the snapshot — DMK silence on a stable list means
243
+ * "everything's still there".
244
+ */
245
+ getLiveDevices(timeoutMs?: number): Promise<DmkDiscoveredDevice[]>;
246
+ /**
247
+ * Trigger browser device selection (WebHID requestDevice).
248
+ * Starts discovery for a short period, then stops.
249
+ */
250
+ /**
251
+ * Start BLE discovery if not already running.
252
+ * Does NOT stop — DMK keeps scanning in the background so that
253
+ * listenToAvailableDevices() always has fresh data.
254
+ */
255
+ private _discoverySub;
256
+ requestDevice(): Promise<void>;
257
+ /** Lookup a previously-discovered device's display name. */
258
+ getDeviceName(deviceId: string): string | undefined;
259
+ /** Lookup minimal model/signal info from a previously-discovered device. */
260
+ getDiscoveredDeviceInfo(deviceId: string): {
261
+ model?: string;
262
+ modelName?: string;
263
+ name?: string;
264
+ rssi?: number | null;
265
+ } | undefined;
266
+ hasDiscoveredDevice(deviceId: string): boolean;
267
+ /** Connect to a previously discovered device. Returns sessionId. */
268
+ connect(deviceId: string): Promise<string>;
269
+ /** Disconnect a session. */
270
+ disconnect(sessionId: string): Promise<void>;
271
+ getSessionId(deviceId: string): string | undefined;
272
+ getDeviceId(sessionId: string): string | undefined;
273
+ /** Get the underlying DMK instance (needed by SignerManager). */
274
+ getDmk(): DeviceManagementKit;
275
+ stopDiscovery(): void;
276
+ dispose(): void;
277
+ /**
278
+ * Tear down RxJS subscriptions and local state without closing the DMK.
279
+ * For light-reset paths that want to drop session state but keep the
280
+ * underlying transport alive for retry. Call this instead of orphaning
281
+ * the manager — bare null assignment leaks _listenSub / _discoverySub.
282
+ */
283
+ disposeKeepingDmk(): void;
177
284
  }
178
285
 
179
286
  /**
@@ -201,7 +308,14 @@ interface LedgerConnectorBaseOptions {
201
308
  * Subclasses only need to:
202
309
  * 1. Supply a transport factory via the constructor.
203
310
  * 2. Optionally override `_resolveConnectId()` for transport-specific
204
- * device identity resolution (e.g. BLE hex ID extraction).
311
+ * device identity resolution.
312
+ *
313
+ * Invariant: one instance = one transport. `connectionType` is fixed at
314
+ * construction. To switch transport (e.g. desktop BLE ↔ WebHID), the host
315
+ * must build a new connector instance and replace the old one — don't add
316
+ * multiple transports to a single instance. Lifting this constraint would
317
+ * require routing `connectionType` from `descriptor.transport` per-device
318
+ * and updating every `this.connectionType` branch in this file.
205
319
  */
206
320
  declare class LedgerConnectorBase implements IConnector {
207
321
  private _deviceManager;
@@ -211,15 +325,8 @@ declare class LedgerConnectorBase implements IConnector {
211
325
  private readonly _providedDmk;
212
326
  private readonly _createTransport;
213
327
  readonly connectionType: ConnectionType;
214
- private _connectIdToPath;
215
- private _pathToConnectId;
216
- /** Register a connectId <-> path mapping from a device descriptor. */
217
- private _registerDeviceId;
218
- /** Get DMK path from external connectId. Falls back to connectId itself. */
219
- private _getPathForConnectId;
220
- /** Get external connectId from DMK path. Falls back to path itself. */
221
- private _getConnectIdForPath;
222
328
  private readonly _cancellers;
329
+ private readonly _sessionStateSubs;
223
330
  /**
224
331
  * Resolves a Ledger signer kit module by package name.
225
332
  * Override via constructor to use CJS paths for Metro (React Native).
@@ -228,6 +335,10 @@ declare class LedgerConnectorBase implements IConnector {
228
335
  protected _importLedgerKit: (pkg: string) => Promise<any>;
229
336
  /** Context object passed to per-chain handler functions. */
230
337
  private readonly _ctx;
338
+ /** When true, BLE direct-connect throws NotAdvertising if the pre-flight
339
+ * scan can't see the device — guard for GATT stacks that wedge on
340
+ * non-advertising peripherals (iOS). */
341
+ private readonly _requirePreFlightScan;
231
342
  constructor(createTransport: TransportFactory, options?: {
232
343
  connectionType?: ConnectionType;
233
344
  dmk?: DeviceManagementKit;
@@ -237,17 +348,39 @@ declare class LedgerConnectorBase implements IConnector {
237
348
  * For Metro (React Native): pass a resolver that uses CJS paths.
238
349
  */
239
350
  importLedgerKit?: (pkg: string) => Promise<any>;
351
+ /** Default false. RN-iOS subclass should pass `true`. */
352
+ requirePreFlightScan?: boolean;
240
353
  });
241
354
  /**
242
355
  * Resolve the connectId for a discovered device descriptor.
243
356
  * Default: use the DMK path (ephemeral UUID).
244
- * Override in subclasses to extract stable identifiers (e.g. BLE hex ID).
357
+ * Override in subclasses only when the public connectId differs from the transport path.
245
358
  */
246
359
  protected _resolveConnectId(descriptor: DeviceDescriptor): string;
360
+ /**
361
+ * Authoritative discovery for this transport. Default = enumerate snapshot
362
+ * (USB/HID). BLE overrides to drive from a live scan window since DMK's
363
+ * enumerate() cache survives peripherals going offline.
364
+ */
365
+ protected _discoverDescriptors(dm: LedgerDeviceManager): Promise<DeviceDescriptor[]>;
247
366
  searchDevices(): Promise<ConnectorDevice[]>;
248
367
  connect(deviceId?: string): Promise<ConnectorSession>;
249
368
  disconnect(sessionId: string): Promise<void>;
369
+ /**
370
+ * Subscribe to DMK's per-session state observable so that any autonomous
371
+ * disconnect (USB unplug, BLE drop, device sleep, transport reset) is
372
+ * surfaced as a `device-disconnect` event — without this, the upstream
373
+ * `LedgerAdapter._sessions` map would hold a dead session entry until
374
+ * the next call hit `DeviceSessionNotFound`.
375
+ *
376
+ * Best-effort: any error subscribing is swallowed so a flaky DMK
377
+ * doesn't break the connect path.
378
+ */
379
+ private _watchSessionState;
380
+ private _unwatchSessionState;
381
+ private _handleAutonomousDisconnect;
250
382
  call(sessionId: string, method: string, params: unknown): Promise<unknown>;
383
+ private _dispatch;
251
384
  cancel(sessionId: string): Promise<void>;
252
385
  uiResponse(_response: UiResponseEvent): void;
253
386
  on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
@@ -265,90 +398,53 @@ declare class LedgerConnectorBase implements IConnector {
265
398
  private _invalidateSession;
266
399
  /**
267
400
  * Replace an old session with a new one after app switch.
268
- * Updates the connectId→path mapping so subsequent calls() use the new session,
269
- * and emits device-connect so the adapter updates its _sessions Map.
401
+ * Emits device-connect so the adapter updates its _sessions Map.
270
402
  */
271
403
  private _replaceSession;
272
404
  /**
273
- * Light reset: clear signer/session state but keep DMK, BLE scan, and ID mapping alive.
405
+ * Light reset: clear signer/session state but keep DMK alive.
274
406
  * Used by connect() retry — we want to re-discover with the same transport.
407
+ *
408
+ * Note: drops the device manager but tears down its RxJS subs first via
409
+ * disposeKeepingDmk(). Bare null-assignment would leak _listenSub /
410
+ * _discoverySub and double-scan after the next _initManagers().
275
411
  */
276
412
  private _resetSignersAndSessions;
277
413
  private _resetAll;
278
414
  protected _emit<K extends ConnectorEventType>(event: K, data: ConnectorEventMap[K]): void;
279
- private _wrapError;
280
- }
281
-
282
- /**
283
- * Manages device discovery, connection, and session tracking.
284
- * Wraps DMK's Observable APIs into simpler imperative calls.
285
- */
286
- declare class LedgerDeviceManager {
287
- private readonly _dmk;
288
- private readonly _discovered;
289
- private readonly _sessions;
290
- private readonly _sessionToDevice;
291
- private _listenSub;
292
- constructor(dmk: DeviceManagementKit);
293
- /**
294
- * One-shot enumeration: subscribe to listenToAvailableDevices,
295
- * take the first emission, unsubscribe, return DeviceDescriptors.
296
- */
297
- enumerate(): Promise<DeviceDescriptor[]>;
298
- /**
299
- * Continuous listening: tracks device connect/disconnect via diffing.
300
- */
301
- listen(onChange: (event: DeviceChangeEvent) => void): void;
302
- stopListening(): void;
303
415
  /**
304
- * Trigger browser device selection (WebHID requestDevice).
305
- * Starts discovery for a short period, then stops.
306
- */
307
- /**
308
- * Start BLE discovery if not already running.
309
- * Does NOT stop — DMK keeps scanning in the background so that
310
- * listenToAvailableDevices() always has fresh data.
416
+ * Return a per-call ctx with the chain's Ledger app name pre-bound to
417
+ * wrapError, so chain handlers don't need to repeat `{ defaultAppName: 'X' }`
418
+ * at every catch site. Falls through unchanged for unknown methods.
311
419
  */
312
- private _discoverySub;
313
- requestDevice(): Promise<void>;
314
- /** Connect to a previously discovered device. Returns sessionId. */
315
- connect(deviceId: string): Promise<string>;
316
- /** Disconnect a session. */
317
- disconnect(sessionId: string): Promise<void>;
318
- getSessionId(deviceId: string): string | undefined;
319
- getDeviceId(sessionId: string): string | undefined;
320
- /** Get the underlying DMK instance (needed by SignerManager). */
321
- getDmk(): DeviceManagementKit;
322
- stopDiscovery(): void;
323
- dispose(): void;
420
+ private _ctxForMethod;
421
+ private _wrapError;
324
422
  }
325
423
 
424
+ /** Optional context attached to the rejection when a canceller fires. */
425
+ interface CancelReason {
426
+ code?: number;
427
+ tag?: string;
428
+ message?: string;
429
+ }
326
430
  /**
327
- * Re-export DMK types under local aliases for backward compatibility.
328
- * These replace the previous duck-typed interfaces with the real SDK types.
329
- */
330
- type DmkDiscoveredDevice = DiscoveredDevice;
331
- /**
332
- * DMK DeviceAction — the Observable-based return type of all DMK signer methods.
431
+ * Convert a DMK DeviceAction (Observable-based) into a Promise.
432
+ * Handles pending -> completed/error state transitions and interaction callbacks.
333
433
  *
334
- * This is a permissive alias for `ExecuteDeviceActionReturnType` that accepts
335
- * any Error and IntermediateValue generics. Signer wrapper code only cares about
336
- * the Output type and the observable/cancel shape.
337
- */
338
- type DeviceAction<T> = ExecuteDeviceActionReturnType<T, any, any>;
339
- /**
340
- * DMK DeviceActionState re-exported with permissive Error/IntermediateValue.
341
- * The real type is a discriminated union on `status`.
434
+ * Tracks the last DMK step observed (e.g. `signer.eth.steps.blindSignTransactionFallback`)
435
+ * and attaches it to the rejected error as a non-enumerable `_lastStep` property,
436
+ * so upstream error classifiers can distinguish failure contexts (e.g. Blind signing
437
+ * disabled vs. generic Invalid data).
438
+ *
439
+ * @param timeoutMs Idle watchdog ms. Re-armed on each emission, paused
440
+ * during interactive pending. 0 disables. Default 65s
441
+ * (covers DMK's 60s + margin; we're a backstop only).
442
+ * @param onRegisterCanceller Optional callback that receives a function which, when
443
+ * called, unsubscribes and cancels the underlying DeviceAction
444
+ * (releases DMK's IntentQueue slot). Caller is responsible
445
+ * for invoking the canceller on timeout/abort scenarios.
342
446
  */
343
- type DeviceActionState<T> = DeviceActionState$1<T, any, any>;
344
- /** ETH address result — re-exported from DMK for backward compatibility. */
345
- type SignerEvmAddress = Address;
346
- /** ETH signature result — re-exported from DMK for backward compatibility. */
347
- type SignerEvmSignature = Signature;
348
- /** BTC address result (WalletAddress not exported from DMK top-level). */
349
- interface SignerBtcAddress {
350
- address: string;
351
- }
447
+ declare function deviceActionToPromise<T>(action: DeviceAction<T>, onInteraction?: (interaction: string) => void, timeoutMs?: number, onRegisterCanceller?: (cancel: (reason?: CancelReason) => void) => void): Promise<T>;
352
448
 
353
449
  /**
354
450
  * Wraps Ledger's SDK signer (Observable-based DeviceActions) into
@@ -363,7 +459,7 @@ declare class SignerEth {
363
459
  * for the underlying DeviceAction. Caller can invoke it to release DMK's
364
460
  * IntentQueue slot and unsubscribe from the action's observable.
365
461
  */
366
- onRegisterCanceller?: (cancel: () => void) => void;
462
+ onRegisterCanceller?: (cancel: (reason?: CancelReason) => void) => void;
367
463
  getAddress(derivationPath: string, options?: {
368
464
  checkOnDevice?: boolean;
369
465
  }): Promise<SignerEvmAddress>;
@@ -376,8 +472,14 @@ type SignerEthBuilderFn = (args: {
376
472
  dmk: DeviceManagementKit;
377
473
  sessionId: string;
378
474
  }) => {
475
+ withContextModule?(contextModule: ContextModule): {
476
+ build(): SignerEth$1;
477
+ };
379
478
  build(): SignerEth$1;
380
479
  } | Promise<{
480
+ withContextModule?(contextModule: ContextModule): {
481
+ build(): SignerEth$1;
482
+ };
381
483
  build(): SignerEth$1;
382
484
  }>;
383
485
  /**
@@ -393,6 +495,8 @@ declare class SignerManager {
393
495
  invalidate(_sessionId: string): void;
394
496
  clearAll(): void;
395
497
  private static _defaultBuilder;
498
+ private static _createContextModule;
499
+ static wrapBlindSigningReportNonBlocking<T extends ContextModule>(contextModule: T): T;
396
500
  }
397
501
 
398
502
  type BtcWallet = Parameters<SignerBtc$1['getWalletAddress']>[0];
@@ -406,7 +510,7 @@ type BtcMessageOptions = Parameters<SignerBtc$1['signMessage']>[2];
406
510
  declare class SignerBtc {
407
511
  private readonly _sdk;
408
512
  onInteraction?: (interaction: string) => void;
409
- onRegisterCanceller?: (cancel: () => void) => void;
513
+ onRegisterCanceller?: (cancel: (reason?: CancelReason) => void) => void;
410
514
  constructor(_sdk: SignerBtc$1);
411
515
  getWalletAddress(wallet: BtcWallet, addressIndex: number, options?: {
412
516
  checkOnDevice?: boolean;
@@ -452,7 +556,7 @@ type SolMsgOptions = Parameters<SignerSolana['signMessage']>[2];
452
556
  declare class SignerSol {
453
557
  private readonly _sdk;
454
558
  onInteraction?: (interaction: string) => void;
455
- onRegisterCanceller?: (cancel: () => void) => void;
559
+ onRegisterCanceller?: (cancel: (reason?: CancelReason) => void) => void;
456
560
  constructor(_sdk: SignerSolana);
457
561
  /**
458
562
  * Get the Solana address (base58-encoded Ed25519 public key) at the given derivation path.
@@ -493,24 +597,6 @@ declare class DmkTransport extends Transport {
493
597
  close(): Promise<void>;
494
598
  }
495
599
 
496
- /**
497
- * Convert a DMK DeviceAction (Observable-based) into a Promise.
498
- * Handles pending -> completed/error state transitions and interaction callbacks.
499
- *
500
- * Tracks the last DMK step observed (e.g. `signer.eth.steps.blindSignTransactionFallback`)
501
- * and attaches it to the rejected error as a non-enumerable `_lastStep` property,
502
- * so upstream error classifiers can distinguish failure contexts (e.g. Blind signing
503
- * disabled vs. generic Invalid data).
504
- *
505
- * @param timeoutMs Timeout in ms. Resets each time the Observable emits (device is alive).
506
- * Pass 0 to disable. Default: 30s.
507
- * @param onRegisterCanceller Optional callback that receives a function which, when
508
- * called, unsubscribes and cancels the underlying DeviceAction
509
- * (releases DMK's IntentQueue slot). Caller is responsible
510
- * for invoking the canceller on timeout/abort scenarios.
511
- */
512
- declare function deviceActionToPromise<T>(action: DeviceAction<T>, onInteraction?: (interaction: string) => void, timeoutMs?: number, onRegisterCanceller?: (cancel: () => void) => void): Promise<T>;
513
-
514
600
  interface AppManagerOptions {
515
601
  waitMs?: number;
516
602
  maxRetries?: number;
@@ -540,9 +626,16 @@ declare class AppManager {
540
626
  * 5. Poll until the device confirms the target app is running.
541
627
  */
542
628
  /**
543
- * @param onConfirmOnDevice Called after OpenAppCommand succeeds
544
- * the device is now showing a confirmation prompt to the user.
545
- * NOT called if the app is already open or if the app is not installed.
629
+ * @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued the
630
+ * device is about to display "Open <app>" on screen and wait for the
631
+ * user's button press. UI consumers should show their "open app" prompt
632
+ * in response. NOT called when the target app is already open (no user
633
+ * interaction needed in that case).
634
+ *
635
+ * Important: OpenAppCommand is blocking. It does not resolve until the user
636
+ * has physically confirmed on the device, so anything that runs AFTER
637
+ * `await this._openApp(...)` lands AFTER the prompt is already gone.
638
+ * Hence the callback must fire BEFORE that await.
546
639
  */
547
640
  ensureAppOpen(sessionId: string, targetAppName: string, onConfirmOnDevice?: () => void): Promise<void>;
548
641
  private _getCurrentApp;
@@ -557,48 +650,59 @@ declare class AppManager {
557
650
  private _wait;
558
651
  }
559
652
 
560
- /**
561
- * Ledger-specific Failure: adds `appName` for "the currently-open app" — a
562
- * Ledger hardware concept not shared with other vendors, so it lives here
563
- * rather than in core's generic Failure.
564
- */
565
653
  type LedgerFailure = Omit<Failure, 'payload'> & {
566
654
  payload: Failure['payload'] & {
567
655
  appName?: string;
656
+ _tag?: string;
568
657
  };
569
658
  };
570
- /**
571
- * Structurally compatible with `Failure`; writes `appName` only when provided,
572
- * so `'appName' in payload` is a reliable "has info" signal for consumers.
573
- */
574
- declare function ledgerFailure(code: HardwareErrorCode, error: string, appName?: string): LedgerFailure;
575
- /** Check if an error (or any error in its chain) represents a locked Ledger device. */
659
+ interface WrapErrorOptions {
660
+ /** Fallback when err has no `appName` (DMK signer errors don't carry it). */
661
+ defaultAppName?: string;
662
+ }
663
+ declare function ledgerFailure(code: HardwareErrorCode, error: string, appName?: string, tag?: string, params?: Record<string, unknown>): LedgerFailure;
576
664
  declare function isDeviceLockedError(err: unknown): boolean;
577
665
  /**
578
- * Map a Ledger DMK error to a HardwareErrorCode and human-readable message
579
- * with actionable recovery information for the caller.
666
+ * Map a Ledger DMK error to a HardwareErrorCode and human-readable message.
667
+ * `opts.defaultAppName` fills `appName` when the raw error doesn't carry it
668
+ * (DMK signer errors don't).
580
669
  */
581
- declare function mapLedgerError(err: unknown): {
670
+ declare function mapLedgerError(err: unknown, opts?: WrapErrorOptions): {
582
671
  code: HardwareErrorCode;
583
672
  message: string;
584
673
  appName?: string;
585
674
  };
586
675
 
587
676
  /**
588
- * Centralised debug logger for the Ledger adapter.
589
- *
590
- * Off by default. Toggle programmatically via `setDebugEnabled(true)`.
677
+ * SDK-global event bus. Per-runtime singleton each process subscribes
678
+ * independently; cross-process hosts forward events over their own IPC.
591
679
  */
592
- /** Enable or disable debug logging at runtime. */
593
- declare function setDebugEnabled(value: boolean): void;
594
- /** Returns the current debug-enabled state. */
595
- declare function isDebugEnabled(): boolean;
680
+ type SdkLogEvent = {
681
+ type: 'log';
682
+ level: 'debug' | 'error';
683
+ /** Pre-stringified payload. */
684
+ message: string;
685
+ };
686
+ /** Add new variants here; hosts dispatch on `event.type`. */
687
+ type SdkEvent = SdkLogEvent;
688
+ type SdkEventListener = (event: SdkEvent) => void;
689
+ declare function onSdkEvent(listener: SdkEventListener): () => void;
690
+ declare function offSdkEvent(listener: SdkEventListener): void;
691
+
692
+ declare function debugLog(...args: unknown[]): void;
596
693
 
597
694
  /**
598
- * Extract the stable 4-digit HEX identifier from a Ledger BLE device name.
599
- * e.g., "Nano X 123A" -> "123A", "Ledger Nano X AB12" -> "AB12"
600
- * Returns undefined if no valid HEX suffix found.
695
+ * Ledger DMK transport identifiers that represent BLE devices.
696
+ *
697
+ * Known today:
698
+ * - "BLE": generic/web BLE descriptors
699
+ * - "RN_BLE": @ledgerhq/device-transport-kit-react-native-ble
700
+ *
701
+ * Keep the suffix check here so future DMK BLE transports (for example
702
+ * "FOO_BLE") are handled in one place instead of scattering string checks.
601
703
  */
602
- declare function extractBleHexId(name?: string): string | undefined;
704
+ declare function isLedgerDmkBleTransport(transport?: string): boolean;
705
+ declare function isLedgerBleConnectionType(connectionType?: ConnectionType): boolean;
706
+ declare function isLedgerBleDescriptor(connectionType: ConnectionType, descriptor: DeviceDescriptor): boolean;
603
707
 
604
- export { AppManager, type DeviceActionState, type DmkDiscoveredDevice, DmkTransport, LedgerAdapter, LedgerConnectorBase, type LedgerConnectorBaseOptions, LedgerDeviceManager, type LedgerFailure, SignerBtc, type SignerBtcAddress, SignerEth, type SignerEvmAddress, type SignerEvmSignature, SignerManager, SignerSol, type TransportFactory, deviceActionToPromise, extractBleHexId, isDebugEnabled, isDeviceLockedError, ledgerFailure, mapLedgerError, setDebugEnabled };
708
+ export { AppManager, type DeviceActionState, type DmkDiscoveredDevice, DmkTransport, LedgerAdapter, LedgerConnectorBase, type LedgerConnectorBaseOptions, LedgerDeviceManager, type LedgerFailure, type SdkEvent, type SdkEventListener, type SdkLogEvent, SignerBtc, type SignerBtcAddress, SignerEth, type SignerEvmAddress, type SignerEvmSignature, SignerManager, SignerSol, type TransportFactory, debugLog, deviceActionToPromise, isDeviceLockedError, isLedgerBleConnectionType, isLedgerBleDescriptor, isLedgerDmkBleTransport, ledgerFailure, mapLedgerError, offSdkEvent, onSdkEvent };