@onekeyfe/hwk-adapter-core 1.1.26-alpha.8 → 1.1.26-patch.1

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
@@ -27,6 +27,8 @@ declare enum HardwareErrorCode {
27
27
  InvalidParams = 10002,
28
28
  OperationTimeout = 10003,
29
29
  MethodNotSupported = 10004,
30
+ /** User dismissed in-app cancel UI. Distinct from UserRejected (on-device). */
31
+ UserAborted = 10005,
30
32
  DeviceNotFound = 10100,
31
33
  DeviceDisconnected = 10101,
32
34
  DeviceBusy = 10102,
@@ -34,6 +36,12 @@ declare enum HardwareErrorCode {
34
36
  DeviceNotInitialized = 10104,
35
37
  DeviceInBootloader = 10105,
36
38
  DeviceMismatch = 10106,
39
+ /** Chain app wedged (e.g. Ledger BTC 0x6901). User must exit app on device. */
40
+ DeviceAppStuck = 10107,
41
+ /** Vendor (Ledger / Trezor) doesn't support the chain at all. */
42
+ ChainNotSupported = 10108,
43
+ /** Current operation supports only one connected device. */
44
+ DeviceOneDeviceOnly = 10109,
37
45
  FirmwareTooOld = 10200,
38
46
  FirmwareUpdateRequired = 10201,
39
47
  TransportError = 10300,
@@ -45,10 +53,19 @@ declare enum HardwareErrorCode {
45
53
  * permission" toast and let the user retry manually.
46
54
  */
47
55
  DevicePermissionDenied = 10303,
56
+ /**
57
+ * BLE SMP pairing did not complete within the GATT bonding window.
58
+ * GATT connected but the device didn't acknowledge SMP — typically
59
+ * because the user didn't confirm the passkey on the device, or the
60
+ * device went out of range mid-pairing. Distinct from OperationTimeout
61
+ * (generic) and from DeviceLocked (Secure Element actually locked).
62
+ */
63
+ BlePairingTimeout = 10304,
48
64
  PinInvalid = 10400,
49
65
  PinCancelled = 10401,
50
66
  PassphraseRejected = 10402,
51
- AppNotOpen = 10500,
67
+ /** Chain app NOT INSTALLED on device. User must install via Ledger Live. */
68
+ AppNotInstalled = 10500,
52
69
  WrongApp = 10501,
53
70
  /** 0x911c Command code not supported — app predates current SDK. */
54
71
  AppTooOld = 10502,
@@ -74,6 +91,18 @@ declare enum HardwareErrorCode {
74
91
  /** 0xb007 Aborted due to unexpected state (malformed PSBT / missing UTXO). */
75
92
  BtcUnexpectedState = 11301
76
93
  }
94
+ /**
95
+ * Device-level failures the SDK cannot self-recover from — affect the entire
96
+ * batch (vs per-chain failures like AppNotInstalled / WrongApp which soft-
97
+ * skip in onboarding). Combined with `accounts.length === 0`, signals
98
+ * genuine orphan. Also reused as the batch-abort whitelist for HWK.
99
+ * Single source of truth.
100
+ *
101
+ * UserRejected (device-side reject) is included: pressing reject is an
102
+ * explicit "I don't consent" — continuing the batch to ask again on the
103
+ * next chain is harassment, not helpful.
104
+ */
105
+ declare const ORPHAN_ELIGIBLE_ERROR_CODES: number[];
77
106
 
78
107
  interface Success<T> {
79
108
  success: true;
@@ -84,11 +113,12 @@ interface Failure {
84
113
  payload: {
85
114
  error: string;
86
115
  code: HardwareErrorCode;
116
+ params?: Record<string, unknown>;
87
117
  };
88
118
  }
89
119
  type Response<T> = Success<T> | Failure;
90
120
  declare function success<T>(payload: T): Success<T>;
91
- declare function failure(code: HardwareErrorCode, error: string): Failure;
121
+ declare function failure(code: HardwareErrorCode, error: string, params?: Record<string, unknown>): Failure;
92
122
 
93
123
  type VendorType = 'trezor' | 'ledger';
94
124
  type ConnectionType = 'usb' | 'ble';
@@ -113,13 +143,22 @@ interface DeviceCapabilities {
113
143
  }
114
144
  interface DeviceInfo {
115
145
  vendor: VendorType;
146
+ /** Machine model id (e.g. "nanoX"). */
116
147
  model: string;
148
+ /** Human-readable model name (e.g. "Ledger Nano X"). */
149
+ modelName?: string;
117
150
  firmwareVersion: string;
118
151
  deviceId: string;
119
152
  connectId: string;
120
153
  label?: string;
121
154
  connectionType: ConnectionType;
122
155
  battery?: number;
156
+ /** BLE signal strength (BLE only). */
157
+ rssi?: number | null;
158
+ /** BLE connectable flag (BLE only). */
159
+ isConnectable?: boolean | null;
160
+ /** USB serial number (USB only). */
161
+ serialNumber?: string;
123
162
  /** Device capabilities — varies by vendor, model, and connection type */
124
163
  capabilities?: DeviceCapabilities;
125
164
  }
@@ -211,13 +250,8 @@ interface EvmSignature {
211
250
  signature: string;
212
251
  address?: string;
213
252
  }
214
- type ProgressCallback = (progress: {
215
- index: number;
216
- total: number;
217
- }) => void;
218
253
  interface IEvmMethods {
219
254
  evmGetAddress(connectId: string, deviceId: string, params: EvmGetAddressParams): Promise<Response<EvmAddress>>;
220
- evmGetAddresses(connectId: string, deviceId: string, params: EvmGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<EvmAddress[]>>;
221
255
  evmSignTransaction(connectId: string, deviceId: string, params: EvmSignTxParams): Promise<Response<EvmSignedTx>>;
222
256
  evmSignMessage(connectId: string, deviceId: string, params: EvmSignMsgParams): Promise<Response<EvmSignature>>;
223
257
  evmSignTypedData(connectId: string, deviceId: string, params: EvmSignTypedDataParams): Promise<Response<EvmSignature>>;
@@ -316,7 +350,6 @@ interface BtcSignature {
316
350
  }
317
351
  interface IBtcMethods {
318
352
  btcGetAddress(connectId: string, deviceId: string, params: BtcGetAddressParams): Promise<Response<BtcAddress>>;
319
- btcGetAddresses(connectId: string, deviceId: string, params: BtcGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<BtcAddress[]>>;
320
353
  btcGetPublicKey(connectId: string, deviceId: string, params: BtcGetPublicKeyParams): Promise<Response<BtcPublicKey>>;
321
354
  btcSignTransaction(connectId: string, deviceId: string, params: BtcSignTxParams): Promise<Response<BtcSignedTx>>;
322
355
  btcSignPsbt(connectId: string, deviceId: string, params: BtcSignPsbtParams): Promise<Response<BtcSignedPsbt>>;
@@ -363,7 +396,6 @@ interface SolSignature {
363
396
  }
364
397
  interface ISolMethods {
365
398
  solGetAddress(connectId: string, deviceId: string, params: SolGetAddressParams): Promise<Response<SolAddress>>;
366
- solGetAddresses(connectId: string, deviceId: string, params: SolGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<SolAddress[]>>;
367
399
  solSignTransaction(connectId: string, deviceId: string, params: SolSignTxParams): Promise<Response<SolSignedTx>>;
368
400
  solSignMessage(connectId: string, deviceId: string, params: SolSignMsgParams): Promise<Response<SolSignature>>;
369
401
  }
@@ -397,7 +429,6 @@ interface TronSignature {
397
429
  }
398
430
  interface ITronMethods {
399
431
  tronGetAddress(connectId: string, deviceId: string, params: TronGetAddressParams): Promise<Response<TronAddress>>;
400
- tronGetAddresses(connectId: string, deviceId: string, params: TronGetAddressParams[], onProgress?: ProgressCallback): Promise<Response<TronAddress[]>>;
401
432
  tronSignTransaction(connectId: string, deviceId: string, params: TronSignTxParams): Promise<Response<TronSignedTx>>;
402
433
  tronSignMessage(connectId: string, deviceId: string, params: TronSignMsgParams): Promise<Response<TronSignature>>;
403
434
  }
@@ -438,90 +469,6 @@ declare const DEVICE: {
438
469
  readonly CHANGED: "device-changed";
439
470
  };
440
471
 
441
- /** 10 min — every UI request is human-in-the-loop; bias toward "wait long". */
442
- declare const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600000;
443
- declare const UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
444
- declare const UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
445
- declare const UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
446
- /**
447
- * Per-type single-slot registry for adapter-level UI requests. A new `wait`
448
- * of the same type preempts (rejects) the prior one. Unknown response types
449
- * are dropped silently so the public `uiResponse` entry never throws.
450
- */
451
- declare class UiRequestRegistry {
452
- private pending;
453
- wait<T = unknown>(requestType: string, options?: {
454
- timeoutMs?: number;
455
- }): Promise<T>;
456
- resolve(responseType: string, payload: unknown): void;
457
- cancel(requestType?: string): void;
458
- reset(): void;
459
- hasPending(requestType: string): boolean;
460
- }
461
-
462
- /**
463
- * Per-device serial job queue with preemption support and stuck recovery.
464
- * Ensures that only one operation runs at a time per device, with intelligent
465
- * handling of conflicting operations.
466
- *
467
- * The 'confirm' level uses the standard UI request/response flow:
468
- * emits REQUEST_PREEMPTION → waits for RECEIVE_PREEMPTION via UiRequestRegistry.
469
- */
470
-
471
- type Interruptibility = 'none' | 'safe' | 'confirm';
472
- type PreemptionDecision = 'cancel-current' | 'wait' | 'reject-new';
473
- interface JobOptions {
474
- interruptibility?: Interruptibility;
475
- label?: string;
476
- }
477
- interface ActiveJobInfo {
478
- label?: string;
479
- interruptibility: Interruptibility;
480
- startedAt: number;
481
- }
482
- interface PreemptionEvent {
483
- deviceId: string;
484
- currentJob: ActiveJobInfo;
485
- newJob: {
486
- label?: string;
487
- interruptibility: Interruptibility;
488
- };
489
- }
490
- interface DeviceJobQueueDeps {
491
- /** Emit a UI request event to the frontend. */
492
- emit: (event: string, data: unknown) => void;
493
- /** Registry for waiting on UI responses. */
494
- uiRegistry: UiRequestRegistry;
495
- }
496
- declare class DeviceJobQueue {
497
- private readonly _queues;
498
- private readonly _active;
499
- private readonly _deps;
500
- /** Incremented on clear() so stale queued jobs can detect invalidation. */
501
- private _generation;
502
- constructor(deps?: DeviceJobQueueDeps);
503
- /**
504
- * Enqueue a job for a specific device.
505
- * If a job is already running for this device, behavior depends on interruptibility:
506
- * - 'none': new job queues silently (no preemption possible)
507
- * - 'safe': current job is auto-cancelled, new job runs immediately after
508
- * - 'confirm': emits REQUEST_PREEMPTION and waits for UI response
509
- */
510
- enqueue<T>(deviceId: string, job: (signal: AbortSignal) => Promise<T>, options?: JobOptions): Promise<T>;
511
- /** Manually cancel the active job on a device. Returns false if job is non-interruptible. */
512
- cancelActive(deviceId: string): boolean;
513
- /** Force cancel regardless of interruptibility. Use for device stuck recovery. */
514
- forceCancelActive(deviceId: string): boolean;
515
- /** Get info about the currently active job for a device, or null if idle. */
516
- getActiveJob(deviceId: string): ActiveJobInfo | null;
517
- clear(): void;
518
- /**
519
- * Request preemption decision via UI request/response flow.
520
- * Falls back to 'wait' if deps are not provided.
521
- */
522
- private _requestPreemptionDecision;
523
- }
524
-
525
472
  declare const UI_EVENT = "UI_EVENT";
526
473
  declare const UI_REQUEST: {
527
474
  readonly REQUEST_PIN: "ui-request-pin";
@@ -533,7 +480,7 @@ declare const UI_REQUEST: {
533
480
  readonly REQUEST_DEVICE_PERMISSION: "ui-request-device-permission";
534
481
  readonly REQUEST_SELECT_DEVICE: "ui-request-select-device";
535
482
  readonly REQUEST_DEVICE_CONNECT: "ui-request-device-connect";
536
- readonly REQUEST_PREEMPTION: "ui-request-preemption";
483
+ readonly REQUEST_BTC_HIGH_INDEX_CONFIRM: "ui-request-btc-high-index-confirm";
537
484
  readonly CLOSE_UI_WINDOW: "ui-close";
538
485
  readonly DEVICE_PROGRESS: "ui-device_progress";
539
486
  readonly FIRMWARE_PROGRESS: "ui-firmware-progress";
@@ -547,9 +494,15 @@ declare const UI_RESPONSE: {
547
494
  readonly RECEIVE_SELECT_DEVICE: "receive-select-device";
548
495
  readonly RECEIVE_DEVICE_CONNECT: "receive-device-connect";
549
496
  readonly RECEIVE_DEVICE_PERMISSION: "receive-device-permission";
550
- readonly RECEIVE_PREEMPTION: "receive-preemption";
497
+ readonly RECEIVE_BTC_HIGH_INDEX_CONFIRM: "receive-btc-high-index-confirm";
551
498
  readonly CANCEL: "cancel";
552
499
  };
500
+ type DevicePermissionDeniedReason = 'bluetoothTurnedOff' | 'permissionDenied' | (string & Record<never, never>);
501
+ type DevicePermissionResponse = {
502
+ granted: boolean;
503
+ reason?: DevicePermissionDeniedReason;
504
+ message?: string;
505
+ };
553
506
  type UiResponseEvent = {
554
507
  type: typeof UI_RESPONSE.RECEIVE_PIN;
555
508
  payload: string;
@@ -578,13 +531,11 @@ type UiResponseEvent = {
578
531
  };
579
532
  } | {
580
533
  type: typeof UI_RESPONSE.RECEIVE_DEVICE_PERMISSION;
581
- payload: {
582
- granted: boolean;
583
- };
534
+ payload: DevicePermissionResponse;
584
535
  } | {
585
- type: typeof UI_RESPONSE.RECEIVE_PREEMPTION;
536
+ type: typeof UI_RESPONSE.RECEIVE_BTC_HIGH_INDEX_CONFIRM;
586
537
  payload: {
587
- decision: PreemptionDecision;
538
+ confirmed: boolean;
588
539
  };
589
540
  } | {
590
541
  type: typeof UI_RESPONSE.CANCEL;
@@ -599,6 +550,155 @@ declare const SDK: {
599
550
  readonly DEVICE_INTERACTION: "device-interaction";
600
551
  };
601
552
 
553
+ /**
554
+ * Minimal device info returned during discovery (searchDevices).
555
+ * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.
556
+ */
557
+ interface ConnectorDevice {
558
+ connectId: string;
559
+ deviceId: string;
560
+ name: string;
561
+ /** Machine model id (e.g. "nanoX"). */
562
+ model?: string;
563
+ /** Human-readable model name (e.g. "Ledger Nano X"). */
564
+ modelName?: string;
565
+ /** BLE signal strength (BLE only). */
566
+ rssi?: number | null;
567
+ /** BLE connectable flag (BLE only). */
568
+ isConnectable?: boolean | null;
569
+ /** USB serial number (USB only). */
570
+ serialNumber?: string;
571
+ /** Device capabilities — available from scan time */
572
+ capabilities?: DeviceCapabilities;
573
+ }
574
+ interface ConnectorSession {
575
+ sessionId: string;
576
+ deviceInfo: DeviceInfo;
577
+ }
578
+ type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';
579
+ /**
580
+ * Interaction event types emitted via 'ui-event'.
581
+ * These map to user-facing prompts (confirm on device, open app, etc.).
582
+ */
583
+ declare enum EConnectorInteraction {
584
+ /** Adapter is actively searching for the device (no session yet) */
585
+ Searching = "searching",
586
+ /** Device requires user to open a specific app */
587
+ ConfirmOpenApp = "confirm-open-app",
588
+ /** Device requires user to unlock */
589
+ UnlockDevice = "unlock-device",
590
+ /** Device needs user to confirm on device (sign, verify, etc.) */
591
+ ConfirmOnDevice = "confirm-on-device",
592
+ /** Previous interaction completed — clear UI prompt */
593
+ InteractionComplete = "interaction-complete"
594
+ }
595
+ type ConnectorUiEvent = {
596
+ type: EConnectorInteraction.Searching;
597
+ payload: {
598
+ sessionId: string;
599
+ };
600
+ } | {
601
+ type: EConnectorInteraction.ConfirmOpenApp;
602
+ payload: {
603
+ sessionId: string;
604
+ };
605
+ } | {
606
+ type: EConnectorInteraction.UnlockDevice;
607
+ payload: {
608
+ sessionId: string;
609
+ };
610
+ } | {
611
+ type: EConnectorInteraction.ConfirmOnDevice;
612
+ payload: {
613
+ sessionId: string;
614
+ };
615
+ } | {
616
+ type: EConnectorInteraction.InteractionComplete;
617
+ payload: {
618
+ sessionId: string;
619
+ };
620
+ };
621
+ interface ConnectorEventMap {
622
+ 'device-connect': {
623
+ device: ConnectorDevice;
624
+ };
625
+ 'device-disconnect': {
626
+ connectId: string;
627
+ };
628
+ 'ui-request': {
629
+ type: string;
630
+ payload?: unknown;
631
+ };
632
+ 'ui-event': ConnectorUiEvent;
633
+ }
634
+ interface IConnector {
635
+ /** Physical connection type this connector uses. Fixed at construction. */
636
+ readonly connectionType: ConnectionType;
637
+ searchDevices(): Promise<ConnectorDevice[]>;
638
+ connect(deviceId?: string): Promise<ConnectorSession>;
639
+ disconnect(sessionId: string): Promise<void>;
640
+ call(sessionId: string, method: string, params: unknown): Promise<unknown>;
641
+ cancel(sessionId: string): Promise<void>;
642
+ /** Send a UI response (e.g. PIN, passphrase) to the device. */
643
+ uiResponse(response: UiResponseEvent): void;
644
+ on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
645
+ off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
646
+ reset(): void;
647
+ }
648
+ interface IHardwareBridge {
649
+ searchDevices(params: {
650
+ vendor: VendorType;
651
+ }): Promise<ConnectorDevice[]>;
652
+ connect(params: {
653
+ vendor: VendorType;
654
+ deviceId?: string;
655
+ }): Promise<ConnectorSession>;
656
+ disconnect(params: {
657
+ vendor: VendorType;
658
+ sessionId: string;
659
+ }): Promise<void>;
660
+ call(params: {
661
+ vendor: VendorType;
662
+ sessionId: string;
663
+ method: string;
664
+ callParams: unknown;
665
+ }): Promise<unknown>;
666
+ cancel(params: {
667
+ vendor: VendorType;
668
+ sessionId: string;
669
+ }): Promise<void>;
670
+ uiResponse(params: {
671
+ vendor: VendorType;
672
+ response: UiResponseEvent;
673
+ }): void;
674
+ reset(params: {
675
+ vendor: VendorType;
676
+ }): void;
677
+ /** Register an event handler for connector events forwarded across the bridge. */
678
+ onEvent(params: {
679
+ vendor: VendorType;
680
+ }, handler: (event: {
681
+ type: ConnectorEventType;
682
+ data: unknown;
683
+ }) => void): void;
684
+ /** Unregister a previously registered event handler. */
685
+ offEvent(params: {
686
+ vendor: VendorType;
687
+ }, handler: (event: {
688
+ type: ConnectorEventType;
689
+ data: unknown;
690
+ }) => void): void;
691
+ }
692
+ /**
693
+ * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.
694
+ * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).
695
+ * Events are forwarded via bridge.onEvent / offEvent.
696
+ *
697
+ * Use this anywhere the actual hardware lives behind a process / context boundary
698
+ * (Electron main, extension background, native module, worker, iframe).
699
+ */
700
+ declare function createBridgedConnector(vendor: VendorType, connectionType: ConnectionType, bridge: IHardwareBridge): IConnector;
701
+
602
702
  type ChainCapability = 'evm' | 'btc' | 'sol' | 'tron';
603
703
  interface PassphraseResponse {
604
704
  passphrase: string;
@@ -664,18 +764,23 @@ type UiRequestEvent = {
664
764
  } | {
665
765
  type: typeof UI_REQUEST.REQUEST_DEVICE_CONNECT;
666
766
  payload: {
767
+ /** Vendor that emitted the request, e.g. 'ledger', 'trezor'. */
768
+ vendor: string;
769
+ /**
770
+ * Why the SDK is asking for a reconnect. Lets the app render
771
+ * vendor-aware copy without inspecting message strings.
772
+ * - 'device-not-found': search returned 0 / device not reachable.
773
+ * Future values can be added (e.g. 'pairing-failed') as new fallback
774
+ * causes are surfaced.
775
+ */
776
+ reason: string;
777
+ /**
778
+ * Best-effort English fallback. Apps should prefer rendering via
779
+ * `vendor` + `reason` for i18n; fall back to this if the combination
780
+ * isn't recognized.
781
+ */
667
782
  message: string;
668
783
  };
669
- } | {
670
- type: typeof UI_REQUEST.REQUEST_PREEMPTION;
671
- payload: {
672
- deviceId: string;
673
- currentJob: ActiveJobInfo;
674
- newJob: {
675
- label?: string;
676
- interruptibility: Interruptibility;
677
- };
678
- };
679
784
  } | {
680
785
  type: typeof UI_REQUEST.CLOSE_UI_WINDOW;
681
786
  payload: Record<string, never>;
@@ -702,7 +807,7 @@ type SdkEvent = {
702
807
  connectId: string;
703
808
  };
704
809
  };
705
- type HardwareEvent = DeviceEvent | UiRequestEvent | SdkEvent;
810
+ type HardwareEvent = DeviceEvent | UiRequestEvent | SdkEvent | ConnectorUiEvent;
706
811
  type DeviceEventListener = (event: HardwareEvent) => void;
707
812
  /**
708
813
  * Type-safe event map for IHardwareWallet.on / .off.
@@ -711,6 +816,7 @@ type DeviceEventListener = (event: HardwareEvent) => void;
711
816
  * and the value is the narrowed event object the listener will receive.
712
817
  */
713
818
  interface HardwareEventMap {
819
+ 'ui-event': ConnectorUiEvent;
714
820
  [DEVICE.CONNECT]: {
715
821
  type: typeof DEVICE.CONNECT;
716
822
  payload: DeviceInfo;
@@ -780,18 +886,17 @@ interface HardwareEventMap {
780
886
  [UI_REQUEST.REQUEST_DEVICE_CONNECT]: {
781
887
  type: typeof UI_REQUEST.REQUEST_DEVICE_CONNECT;
782
888
  payload: {
889
+ vendor: string;
890
+ reason: string;
783
891
  message: string;
784
892
  };
785
893
  };
786
- [UI_REQUEST.REQUEST_PREEMPTION]: {
787
- type: typeof UI_REQUEST.REQUEST_PREEMPTION;
894
+ [UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM]: {
895
+ type: typeof UI_REQUEST.REQUEST_BTC_HIGH_INDEX_CONFIRM;
788
896
  payload: {
789
- deviceId: string;
790
- currentJob: ActiveJobInfo;
791
- newJob: {
792
- label?: string;
793
- interruptibility: Interruptibility;
794
- };
897
+ vendor: string;
898
+ path: string;
899
+ accountIndex: number;
795
900
  };
796
901
  };
797
902
  [UI_REQUEST.CLOSE_UI_WINDOW]: {
@@ -831,12 +936,13 @@ interface IHardwareWallet<TConfig = unknown> extends IEvmMethods, IBtcMethods, I
831
936
  dispose(): Promise<void>;
832
937
  getAvailableTransports(): TransportType[];
833
938
  switchTransport(type: TransportType): Promise<void>;
834
- searchDevices(): Promise<DeviceInfo[]>;
939
+ searchDevices(options?: SearchDevicesOptions): Promise<DeviceInfo[]>;
835
940
  connectDevice(connectId: string): Promise<Response<string>>;
836
941
  disconnectDevice(connectId: string): Promise<void>;
837
942
  getDeviceInfo(connectId: string, deviceId: string): Promise<Response<DeviceInfo>>;
838
943
  getSupportedChains(): ChainCapability[];
839
- cancel(connectId: string): void;
944
+ /** Abort the in-flight call. Omit connectId to cancel whatever is active. */
945
+ cancel(connectId?: string): void;
840
946
  /** Respond to any pending `ui-request-*`. */
841
947
  uiResponse(response: UiResponseEvent): void;
842
948
  /**
@@ -854,6 +960,16 @@ interface IHardwareWallet<TConfig = unknown> extends IEvmMethods, IBtcMethods, I
854
960
  off<K extends keyof HardwareEventMap>(event: K, listener: (event: HardwareEventMap[K]) => void): void;
855
961
  off(event: string, listener: DeviceEventListener): void;
856
962
  }
963
+ interface SearchDevicesOptions {
964
+ /**
965
+ * Clear cached adapter sessions before scanning.
966
+ *
967
+ * Use this for an explicit "search/add another device" flow on transports
968
+ * whose connectId is not stable, such as Ledger WebHID. Normal refresh scans
969
+ * should leave this false so an active session can still be reused.
970
+ */
971
+ resetSession?: boolean;
972
+ }
857
973
 
858
974
  /**
859
975
  * Low-level device descriptor from Transport layer.
@@ -866,12 +982,28 @@ interface DeviceDescriptor {
866
982
  product?: number;
867
983
  /** USB vendor ID */
868
984
  vendor?: number;
869
- /** Device type/model identifier */
985
+ /** Device type/model identifier (e.g. "nanoX"). */
870
986
  type?: string;
871
- /** BLE device name (e.g., "Nano X 123A") — contains stable 4-digit HEX suffix */
987
+ /** Human-readable model name (e.g. "Ledger Nano X"). */
988
+ modelName?: string;
989
+ /** Human-readable display name from the transport layer. */
872
990
  name?: string;
991
+ /** Raw Ledger BLE advertisement name from RN BLE `Device.name`, when available. */
992
+ bleName?: string;
993
+ /** User-visible Ledger BLE local name from the raw RN BLE `Device.localName` field. */
994
+ localName?: string;
873
995
  /** Transport identifier (e.g., 'WEB-HID', 'BLE') */
874
996
  transport?: string;
997
+ /** BLE RSSI when provided by the transport scanner. */
998
+ rssi?: number | null;
999
+ /** BLE advertised service UUIDs, when provided by the scanner. */
1000
+ serviceUUIDs?: string[] | null;
1001
+ /** BLE connectable flag, when provided by the scanner. */
1002
+ isConnectable?: boolean | null;
1003
+ /** USB product name, when provided by the transport. */
1004
+ productName?: string;
1005
+ /** USB serial number, when provided by the transport. */
1006
+ serialNumber?: string;
875
1007
  }
876
1008
  interface DeviceConnectEvent {
877
1009
  type: 'device-connected';
@@ -884,137 +1016,51 @@ interface DeviceDisconnectEvent {
884
1016
  type DeviceChangeEvent = DeviceConnectEvent | DeviceDisconnectEvent;
885
1017
 
886
1018
  /**
887
- * Minimal device info returned during discovery (searchDevices).
888
- * At scan time, full DeviceInfo fields like firmwareVersion are not yet available.
1019
+ * Pure FIFO job queue. Every enqueue chains onto the tail; jobs run one at
1020
+ * a time across all devices. The queue is intentionally passive — it does
1021
+ * NOT decide whether to interrupt or ask the user. Those are application-
1022
+ * layer concerns owned by the caller (e.g. a UI button handler that wants
1023
+ * to ask "device is busy, interrupt current?" before submitting). The
1024
+ * queue exposes inspection (`getActiveJob`) and explicit cancellation
1025
+ * (`cancelActive` / `cancelAll`) so callers can implement those policies
1026
+ * synchronously, without racing against in-flight enqueues.
889
1027
  */
890
- interface ConnectorDevice {
891
- connectId: string;
892
- deviceId: string;
893
- name: string;
894
- model?: string;
895
- /** Device capabilities — available from scan time */
896
- capabilities?: DeviceCapabilities;
897
- }
898
- interface ConnectorSession {
899
- sessionId: string;
900
- deviceInfo: DeviceInfo;
901
- }
902
- type ConnectorEventType = 'device-connect' | 'device-disconnect' | 'ui-request' | 'ui-event';
903
- /**
904
- * Interaction event types emitted via 'ui-event'.
905
- * These map to user-facing prompts (confirm on device, open app, etc.).
906
- */
907
- declare enum EConnectorInteraction {
908
- /** Device requires user to open a specific app */
909
- ConfirmOpenApp = "confirm-open-app",
910
- /** Device requires user to unlock */
911
- UnlockDevice = "unlock-device",
912
- /** Device needs user to confirm on device (sign, verify, etc.) */
913
- ConfirmOnDevice = "confirm-on-device",
914
- /** Previous interaction completed — clear UI prompt */
915
- InteractionComplete = "interaction-complete"
916
- }
917
- type ConnectorUiEvent = {
918
- type: EConnectorInteraction.ConfirmOpenApp;
919
- payload: {
920
- sessionId: string;
921
- };
922
- } | {
923
- type: EConnectorInteraction.UnlockDevice;
924
- payload: {
925
- sessionId: string;
926
- };
927
- } | {
928
- type: EConnectorInteraction.ConfirmOnDevice;
929
- payload: {
930
- sessionId: string;
931
- };
932
- } | {
933
- type: EConnectorInteraction.InteractionComplete;
934
- payload: {
935
- sessionId: string;
936
- };
937
- };
938
- interface ConnectorEventMap {
939
- 'device-connect': {
940
- device: ConnectorDevice;
941
- };
942
- 'device-disconnect': {
943
- connectId: string;
944
- };
945
- 'ui-request': {
946
- type: string;
947
- payload?: unknown;
948
- };
949
- 'ui-event': ConnectorUiEvent;
1028
+ interface JobOptions {
1029
+ label?: string;
1030
+ rejectIfBusy?: boolean;
1031
+ busyError?: Error;
950
1032
  }
951
- interface IConnector {
952
- /** Physical connection type this connector uses. Fixed at construction. */
953
- readonly connectionType: ConnectionType;
954
- searchDevices(): Promise<ConnectorDevice[]>;
955
- connect(deviceId?: string): Promise<ConnectorSession>;
956
- disconnect(sessionId: string): Promise<void>;
957
- call(sessionId: string, method: string, params: unknown): Promise<unknown>;
958
- cancel(sessionId: string): Promise<void>;
959
- /** Send a UI response (e.g. PIN, passphrase) to the device. */
960
- uiResponse(response: UiResponseEvent): void;
961
- on<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
962
- off<K extends ConnectorEventType>(event: K, handler: (data: ConnectorEventMap[K]) => void): void;
963
- reset(): void;
1033
+ interface ActiveJobInfo {
1034
+ deviceId: string;
1035
+ label?: string;
1036
+ startedAt: number;
964
1037
  }
965
- interface IHardwareBridge {
966
- searchDevices(params: {
967
- vendor: VendorType;
968
- }): Promise<ConnectorDevice[]>;
969
- connect(params: {
970
- vendor: VendorType;
971
- deviceId?: string;
972
- }): Promise<ConnectorSession>;
973
- disconnect(params: {
974
- vendor: VendorType;
975
- sessionId: string;
976
- }): Promise<void>;
977
- call(params: {
978
- vendor: VendorType;
979
- sessionId: string;
980
- method: string;
981
- callParams: unknown;
982
- }): Promise<unknown>;
983
- cancel(params: {
984
- vendor: VendorType;
985
- sessionId: string;
986
- }): Promise<void>;
987
- uiResponse(params: {
988
- vendor: VendorType;
989
- response: UiResponseEvent;
990
- }): void;
991
- reset(params: {
992
- vendor: VendorType;
993
- }): void;
994
- /** Register an event handler for connector events forwarded across the bridge. */
995
- onEvent(params: {
996
- vendor: VendorType;
997
- }, handler: (event: {
998
- type: ConnectorEventType;
999
- data: unknown;
1000
- }) => void): void;
1001
- /** Unregister a previously registered event handler. */
1002
- offEvent(params: {
1003
- vendor: VendorType;
1004
- }, handler: (event: {
1005
- type: ConnectorEventType;
1006
- data: unknown;
1007
- }) => void): void;
1038
+ declare class DeviceJobQueue {
1039
+ private _tail;
1040
+ private _active;
1041
+ private readonly _jobs;
1042
+ /** Incremented on clear() so queued-but-not-yet-running jobs detect invalidation. */
1043
+ private _generation;
1044
+ private readonly _generationCancelReasons;
1045
+ /**
1046
+ * Enqueue a job. Runs after every previously-enqueued job has settled.
1047
+ * `deviceId` is a label only — used by inspection / cancellation routing.
1048
+ */
1049
+ enqueue<T>(deviceId: string, job: (signal: AbortSignal) => Promise<T>, options?: JobOptions): Promise<T>;
1050
+ /** Cancel the active job. If `deviceId` is given, only cancels when it matches. */
1051
+ cancelActive(deviceId?: string): boolean;
1052
+ /** Force cancel the active job. `reason` becomes signal.reason. */
1053
+ forceCancelActive(deviceId?: string, reason?: Error): boolean;
1054
+ /** Cancel the active job (alias for callers that previously needed multi-device cancel). */
1055
+ cancelAllActive(reason?: Error): void;
1056
+ /** Cancel the active job and invalidate queued jobs that have not started. */
1057
+ cancelActiveAndPending(deviceId?: string, reason?: Error): boolean;
1058
+ /** Get info about the currently active job, or null if idle. */
1059
+ getActiveJob(deviceId?: string): ActiveJobInfo | null;
1060
+ /** True if any job is currently running. */
1061
+ isBusy(): boolean;
1062
+ clear(reason?: Error): void;
1008
1063
  }
1009
- /**
1010
- * Adapt an IHardwareBridge (multi-vendor backend) into a single-vendor IConnector.
1011
- * Every IConnector method becomes a transparent forward to bridge.<method>({ vendor, ... }).
1012
- * Events are forwarded via bridge.onEvent / offEvent.
1013
- *
1014
- * Use this anywhere the actual hardware lives behind a process / context boundary
1015
- * (Electron main, extension background, native module, worker, iframe).
1016
- */
1017
- declare function createBridgedConnector(vendor: VendorType, connectionType: ConnectionType, bridge: IHardwareBridge): IConnector;
1018
1064
 
1019
1065
  /**
1020
1066
  * Minimal typed event emitter using Map<string, Set<listener>>.
@@ -1040,6 +1086,32 @@ declare class TypedEventEmitter<TMap extends Record<string, any> = Record<string
1040
1086
  removeAllListeners(): void;
1041
1087
  }
1042
1088
 
1089
+ /** 10 min — every UI request is human-in-the-loop; bias toward "wait long". */
1090
+ declare const UI_REQUEST_DEFAULT_TIMEOUT_MS = 600000;
1091
+ declare const UI_REQUEST_PREEMPTED_TAG = "UiRequestPreempted";
1092
+ declare const UI_REQUEST_CANCELLED_TAG = "UiRequestCancelled";
1093
+ declare const UI_REQUEST_TIMEOUT_TAG = "UiRequestTimeout";
1094
+ /**
1095
+ * Per-type single-slot registry for adapter-level UI requests. A new `wait`
1096
+ * of the same type supersedes (rejects) the prior pending entry. With the
1097
+ * job queue running globally serially, cross-type collisions don't occur in
1098
+ * normal flow — same-type preemption is a defensive measure for callers
1099
+ * that fire the same request twice without waiting on the first.
1100
+ *
1101
+ * Unknown response types are dropped silently so the public `uiResponse`
1102
+ * entry never throws.
1103
+ */
1104
+ declare class UiRequestRegistry {
1105
+ private pending;
1106
+ wait<T = unknown>(requestType: string, options?: {
1107
+ timeoutMs?: number;
1108
+ }): Promise<T>;
1109
+ resolve(responseType: string, payload: unknown): void;
1110
+ cancel(requestType?: string): void;
1111
+ reset(): void;
1112
+ hasPending(requestType?: string): boolean;
1113
+ }
1114
+
1043
1115
  /**
1044
1116
  * Compare two semver strings (e.g. "2.1.0" vs "2.3.1").
1045
1117
  * Returns -1 if a < b, 0 if equal, 1 if a > b.
@@ -1075,4 +1147,4 @@ declare function batchCall<TParam, TResult>(params: TParam[], callFn: (p: TParam
1075
1147
  total: number;
1076
1148
  }) => void): Promise<Response<TResult[]>>;
1077
1149
 
1078
- export { type ActiveJobInfo, type BtcAddress, type BtcGetAddressParams, type BtcGetPublicKeyParams, type BtcPublicKey, type BtcRefTransaction, type BtcSignMsgParams, type BtcSignPsbtParams, type BtcSignTxParams, type BtcSignature, type BtcSignedPsbt, type BtcSignedTx, type BtcTxInput, type BtcTxOutput, CHAIN_FINGERPRINT_PATHS, type ChainCapability, type ChainForFingerprint, type ConnectionType, type ConnectorDevice, type ConnectorEventMap, type ConnectorEventType, type ConnectorSession, DEVICE, DEVICE_EVENT, type DeviceCapabilities, type DeviceChangeEvent, type DeviceConnectEvent, type DeviceDescriptor, type DeviceDisconnectEvent, type DeviceEvent, type DeviceEventListener, type DeviceInfo, DeviceJobQueue, type DeviceJobQueueDeps, type DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmSignMsgParams, type EvmSignTxParams, type EvmSignTypedDataFull, type EvmSignTypedDataHash, type EvmSignTypedDataParams, type EvmSignature, type EvmSignedTx, type Failure, HardwareErrorCode, type HardwareEvent, type HardwareEventMap, type IBtcMethods, type IConnector, type IEvmMethods, type IHardwareBridge, type IHardwareWallet, type ISolMethods, type ITronMethods, type Interruptibility, type JobOptions, type PassphraseResponse, type PreemptionDecision, type PreemptionEvent, type ProgressCallback, type QrDisplayData, type QrResponseData, type Response, SDK, type SdkEvent, type SolAddress, type SolGetAddressParams, type SolSignMsgParams, type SolSignTxParams, type SolSignature, type SolSignedTx, type Success, type TransportType, type TronAddress, type TronGetAddressParams, type TronSignMsgParams, type TronSignTxParams, type TronSignature, type TronSignedTx, TypedEventEmitter, UI_EVENT, UI_REQUEST, UI_REQUEST_CANCELLED_TAG, UI_REQUEST_DEFAULT_TIMEOUT_MS, UI_REQUEST_PREEMPTED_TAG, UI_REQUEST_TIMEOUT_TAG, UI_RESPONSE, type UiRequestEvent, UiRequestRegistry, type UiResponseEvent, type VendorType, batchCall, bytesToHex, compareSemver, createBridgedConnector, deriveDeviceFingerprint, enrichErrorMessage, ensure0x, failure, hexToBytes, padHex64, stripHex, success };
1150
+ export { type ActiveJobInfo, type BtcAddress, type BtcGetAddressParams, type BtcGetPublicKeyParams, type BtcPublicKey, type BtcRefTransaction, type BtcSignMsgParams, type BtcSignPsbtParams, type BtcSignTxParams, type BtcSignature, type BtcSignedPsbt, type BtcSignedTx, type BtcTxInput, type BtcTxOutput, CHAIN_FINGERPRINT_PATHS, type ChainCapability, type ChainForFingerprint, type ConnectionType, type ConnectorDevice, type ConnectorEventMap, type ConnectorEventType, type ConnectorSession, type ConnectorUiEvent, DEVICE, DEVICE_EVENT, type DeviceCapabilities, type DeviceChangeEvent, type DeviceConnectEvent, type DeviceDescriptor, type DeviceDisconnectEvent, type DeviceEvent, type DeviceEventListener, type DeviceInfo, DeviceJobQueue, type DevicePermissionDeniedReason, type DevicePermissionResponse, type DeviceTarget, EConnectorInteraction, type EIP712Domain, type EvmAddress, type EvmGetAddressParams, type EvmSignMsgParams, type EvmSignTxParams, type EvmSignTypedDataFull, type EvmSignTypedDataHash, type EvmSignTypedDataParams, type EvmSignature, type EvmSignedTx, type Failure, HardwareErrorCode, type HardwareEvent, type HardwareEventMap, type IBtcMethods, type IConnector, type IEvmMethods, type IHardwareBridge, type IHardwareWallet, type ISolMethods, type ITronMethods, type JobOptions, ORPHAN_ELIGIBLE_ERROR_CODES, type PassphraseResponse, type QrDisplayData, type QrResponseData, type Response, SDK, type SdkEvent, type SearchDevicesOptions, type SolAddress, type SolGetAddressParams, type SolSignMsgParams, type SolSignTxParams, type SolSignature, type SolSignedTx, type Success, type TransportType, type TronAddress, type TronGetAddressParams, type TronSignMsgParams, type TronSignTxParams, type TronSignature, type TronSignedTx, TypedEventEmitter, UI_EVENT, UI_REQUEST, UI_REQUEST_CANCELLED_TAG, UI_REQUEST_DEFAULT_TIMEOUT_MS, UI_REQUEST_PREEMPTED_TAG, UI_REQUEST_TIMEOUT_TAG, UI_RESPONSE, type UiRequestEvent, UiRequestRegistry, type UiResponseEvent, type VendorType, batchCall, bytesToHex, compareSemver, createBridgedConnector, deriveDeviceFingerprint, enrichErrorMessage, ensure0x, failure, hexToBytes, padHex64, stripHex, success };